diff --git a/CMakeLists.txt b/CMakeLists.txt index ddfc3cd..4460f79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ project(gridtools-verification CXX C) include(ExternalProject) -set(GRIDTOOLS_VERIFICATION_VERSION_STRING "0.3") +set(GRIDTOOLS_VERIFICATION_VERSION_STRING "0.4") set(SERIALBOX_VERSION_REQUIRED "2.2.1") #----------------- CMake options diff --git a/src/common.h b/src/common.h index b22ca44..1506fa4 100644 --- a/src/common.h +++ b/src/common.h @@ -36,3 +36,19 @@ #pragma once #include + +#if __cplusplus >= 201402L // since c++14 +#define GV_DEPRECATED(func) [[deprecated]] func +#define GV_DEPRECATED_REASON(func, msg) [[deprecated(#msg)]] func +#else +#ifdef __GNUC__ +#define GV_DEPRECATED(func) __attribute__((deprecated)) func +#define GV_DEPRECATED_REASON(func, msg) GV_DEPRECATED(func) +#elif defined(_MSC_VER) +#define GV_DEPRECATED(func) __declspec(deprecated) func +#define GV_DEPRECATED_REASON(func, msg) GV_DEPRECATED(func) +#else +#define GV_DEPRECATED(func) func +#define GV_DEPRECATED_REASON(func, msg) GV_DEPRECATED(func) +#endif +#endif diff --git a/src/verification/field_collection.h b/src/verification/field_collection.h index 91f53d5..c098be1 100644 --- a/src/verification/field_collection.h +++ b/src/verification/field_collection.h @@ -76,6 +76,19 @@ namespace gt_verification { }; } + // TODO a clean solution for the iterator would iterate over something like this. + // class verification_savepoint { + // public: + // void load_input(...) + // { + // } + // verification_result verify(..) + // { + // } + // private: + // ... + // }; + /** * @brief A collection of serialized fields * @@ -84,8 +97,40 @@ namespace gt_verification { template < typename T > class field_collection { public: - field_collection(verification_specification verificationSpecification) - : verificationSpecification_(verificationSpecification){}; + field_collection(verification_specification verificationSpecification) : reporter_(verificationSpecification){}; + + field_collection(const field_collection &) = delete; + field_collection &operator=(const field_collection &) = delete; + field_collection(field_collection &&) = default; + field_collection &operator=(field_collection &&) = default; + + struct collection_iterator { + size_t pos_; + // TODO this is a bit hacky, but I think good enough for now, + // the clean solution would be to iterate over a list of s + field_collection< T > &collection_; + + collection_iterator(size_t pos, field_collection< T > &collection) : pos_(pos), collection_(collection) {} + + field_collection< T > &operator*() { + collection_.active_iteration_ = pos_; // TODO + return collection_; + }; + + collection_iterator &operator++() { + pos_++; + return *this; + } + + collection_iterator operator++(int) { + collection_iterator tmp(*this); + operator++(); + return tmp; + } + + bool operator==(const collection_iterator &other) const { return pos_ == other.pos_; } + bool operator!=(const collection_iterator &other) const { return !operator==(other); } + }; /** * @brief Attach a reference serializer to the collection. @@ -141,11 +186,21 @@ namespace gt_verification { * @param field The field that has to be filled with data from disk */ template < typename FieldType > - void register_input_field(const std::string &fieldname, FieldType &field, bool also_previous = false) noexcept { + GV_DEPRECATED_REASON(void register_input_field( + const std::string &fieldname, FieldType &field, bool also_previous = false) noexcept, + "Use the c++11 iterator with iterator.load_input(...).") { inputFields_.push_back( internal::input_field< T >{fieldname, type_erased_field_view< T >(field), also_previous}); } + template < typename FieldType > + void load_input(const std::string &fieldname, FieldType &field) { + serialization serialization(referenceSerializer_); + auto inputSavepoint = iterations_[active_iteration_].input; + type_erased_field_view< T > f(field); + serialization.load(fieldname, f, inputSavepoint); + } + /** * @brief Register an output field for verification * @@ -157,8 +212,10 @@ namespace gt_verification { * @param metric The metric which is used to check the field */ template < typename FieldType > - void register_output_and_reference_field( - const std::string &fieldname, FieldType &field, boundary_extent boundary = boundary_extent()) noexcept { + GV_DEPRECATED_REASON( + void register_output_and_reference_field( + const std::string &fieldname, FieldType &field, boundary_extent boundary = boundary_extent()) noexcept, + "Use the c++11 iterator with iterator.verify_output(...).") { boundaries_.push_back(boundary); outputFields_.push_back(std::make_pair(fieldname, type_erased_field_view< T >(field))); @@ -166,18 +223,45 @@ namespace gt_verification { referenceFields_.push_back(std::make_pair(fieldname, type_erased_field< T >(field))); } + /** + * @brief verify an output field + * + * This is a new interface where you don't register the output field but call the verify with the field. + */ + template < typename FieldType > + verification_result add_output(const std::string &fieldname, + FieldType &field, + const error_metric_interface< T > &error_metric, + boundary_extent boundary = boundary_extent()) noexcept { + + auto refSavepoint = iterations_[active_iteration_].output; + + type_erased_field< T > reference_field(field); + + serialization serialization(referenceSerializer_); + serialization.load(fieldname, reference_field.to_view(), refSavepoint); + + verifications_.emplace_back(type_erased_field_view< T >(field), reference_field.to_view(), boundary); + result_.merge(verifications_.back().verify(error_metric)); + + return result_; + } + /** * @brief Loads input values and reference values from disk into the input- and reference fields * * After this the computations and verification can take place. */ - void load_iteration(int iteration) { + GV_DEPRECATED_REASON(void load_iteration(int iteration), + "Use the c++11 iterator with iterator.load_input(...) and iterator.verify_output(...).") { if (iteration >= (int)iterations_.size()) error::fatal(boost::format("invalid access of iteration '%i' (there are only %i iterations)") % iteration % iterations_.size()); serialization serialization(referenceSerializer_); + active_iteration_ = iteration; + auto inputSavepoint = iterations_[iteration].input; auto refSavepoint = iterations_[iteration].output; @@ -226,10 +310,9 @@ namespace gt_verification { * @brief Report failures depending on values set in VerificationReporter */ void report_failures() const noexcept { - verification_reporter verificationReporter(verificationSpecification_); for (const auto &verification : verifications_) if (!verification) { - verificationReporter.report(verification); + reporter_.report(verification); } } @@ -248,6 +331,24 @@ namespace gt_verification { */ const std::vector< internal::savepoint_pair > &iterations() const noexcept { return iterations_; } + collection_iterator begin() { return collection_iterator(0, *this); } + collection_iterator end() { return collection_iterator(iterations_.size(), *this); } + + /** + * @brief reports errors and resets the error state + */ + verification_result verify_collection() { + if (!result_.passed()) + report_failures(); + + verification_result tmp = result_; + verifications_.clear(); + result_.clear(); + return tmp; + } + + int active_iteration_; + private: std::string name_; std::shared_ptr< ser::serializer > referenceSerializer_; @@ -260,7 +361,8 @@ namespace gt_verification { std::vector< std::pair< std::string, type_erased_field< T > > > referenceFields_; std::vector< boundary_extent > boundaries_; - verification_specification verificationSpecification_; + verification_reporter reporter_; std::vector< verification< T > > verifications_; + verification_result result_; }; } diff --git a/src/verification/unittest_environment.h b/src/verification/unittest_environment.h index ec97cd2..e762b07 100644 --- a/src/verification/unittest_environment.h +++ b/src/verification/unittest_environment.h @@ -99,7 +99,7 @@ namespace gt_verification { skipped_.push_back(spname); } - return collection; + return std::move(collection); } void skip_test(std::string spname = ""); @@ -127,8 +127,9 @@ namespace gt_verification { * otherwise */ template < typename T > - testing::AssertionResult verify_collection( - field_collection< T > &fieldCollection, const error_metric_interface< T > &errorMetric) { + GV_DEPRECATED_REASON(testing::AssertionResult verify_collection(field_collection< T > &fieldCollection, + const error_metric_interface< T > &errorMetric), + "Consider calling verify_collection on the collection instead.") { verification_result result = fieldCollection.verify(errorMetric); if (!result.passed()) fieldCollection.report_failures(); diff --git a/src/verification/verification_reporter.h b/src/verification/verification_reporter.h index 203bde1..7821ae2 100644 --- a/src/verification/verification_reporter.h +++ b/src/verification/verification_reporter.h @@ -58,7 +58,7 @@ namespace gt_verification { * * @ingroup DycoreUnittestVerificationLibrary */ - class verification_reporter : private boost::noncopyable { + class verification_reporter { protected: template < typename T > void list_failures(const verification< T > &verif) const noexcept { @@ -176,7 +176,7 @@ namespace gt_verification { } public: - verification_reporter(const verification_specification verifSpec) : verifSpec_(verifSpec){}; + verification_reporter(const verification_specification &verifSpec) : verifSpec_(verifSpec){}; /** * @brief Report failures to console diff --git a/src/verification/verification_result.h b/src/verification/verification_result.h index 04d9cdd..9865d9b 100644 --- a/src/verification/verification_result.h +++ b/src/verification/verification_result.h @@ -48,7 +48,6 @@ namespace gt_verification { */ class verification_result { public: - verification_result() : passed_(true), msg_("") {} verification_result(const verification_result &) = default; verification_result(verification_result &&) = default; verification_result &operator=(const verification_result &) = default; @@ -77,6 +76,11 @@ namespace gt_verification { msg_ += " " + result.msg() + "\n"; } + void clear() noexcept { + passed_ = true; + msg_ = "\n"; + } + /** * @brief Check if any test failed */