diff --git a/SpecUtils/SpecFile.h b/SpecUtils/SpecFile.h index 9e97909..a72996e 100644 --- a/SpecUtils/SpecFile.h +++ b/SpecUtils/SpecFile.h @@ -614,6 +614,11 @@ class Measurement */ float exposure_rate() const; + /** Returns the application specific "tag" character, used by the PCF file format. + Values of '\0' or ' ' generally indicate it is not set. + */ + char pcf_tag() const; + //position_time(): returns the (local, or detector) time of the GPS fix, if // known. Returns time_point_t{} otherwise. const time_point_t position_time() const; @@ -812,6 +817,9 @@ class Measurement //To set real and live times, see SpecFile::set_live_time(...) + /** Sets the application specific "tag" character, used by the PCF file format. */ + void set_pcf_tag( const char tag_char ); + /** returns the number of channels in #gamma_counts_. Note: energy calibration could still be invalid and not have channel energies defined, even when this returns a non-zero value. @@ -1133,6 +1141,18 @@ class Measurement */ float exposure_rate_; + /** A application-specific data element used by the PCF format. + + For the PCF format, the meaning of the 'tag' character is highly overloaded, and can mean, + among other uses: + '-' not occupied, and anything else occupied - for RPM data + '-' use a dashed line when plotting + '<' Use filled region style when plotting + 'T' Calibration from thorium + 'K' Calibration from potassium + */ + char pcf_tag_; + /** The #LocationState indicates the position, speed, and/or orientation of the instrument, detector, or item being measured. At the moment, only one of these quantities are recorded, primarily to reduce complexity since the author hasnt encountered any files that actually diff --git a/bindings/c/SpecUtils_c.cpp b/bindings/c/SpecUtils_c.cpp index 1ca7b73..a6d597c 100644 --- a/bindings/c/SpecUtils_c.cpp +++ b/bindings/c/SpecUtils_c.cpp @@ -1669,6 +1669,22 @@ bool SpecUtils_Measurement_set_start_time_str( SpecUtils_Measurement *instance, m->set_start_time( tp ); } +char SpecUtils_Measurement_pcf_tag( const SpecUtils_Measurement * const instance ) +{ + auto m = reinterpret_cast( instance ); + assert( m ); + return m ? m->pcf_tag() : '\0'; +} + + +void SpecUtils_Measurement_set_pcf_tag( SpecUtils_Measurement *instance, + const char tag_char ) +{ + auto m = reinterpret_cast( instance ); + assert( m ); + if( m ) + m->set_pcf_tag( tag_char ); +} uint32_t SpecUtils_Measurement_number_gamma_channels( const SpecUtils_Measurement * const instance ) { diff --git a/bindings/c/SpecUtils_c.h b/bindings/c/SpecUtils_c.h index f467f3f..c211ecc 100644 --- a/bindings/c/SpecUtils_c.h +++ b/bindings/c/SpecUtils_c.h @@ -768,6 +768,14 @@ DLLEXPORT bool CALLINGCONVENTION SpecUtils_Measurement_set_start_time_str( SpecUtils_Measurement *instance, const char * const start_time_str ); +/** Returns the application-specific "tag" characters used by the PCF file format. */ +DLLEXPORT char CALLINGCONVENTION +SpecUtils_Measurement_pcf_tag( const SpecUtils_Measurement * const instance ); + +/** Sets the application-specific "tag" characters used by the PCF file format. */ +DLLEXPORT void CALLINGCONVENTION +SpecUtils_Measurement_set_pcf_tag( SpecUtils_Measurement *instance, + const char tag_char ); DLLEXPORT uint32_t CALLINGCONVENTION SpecUtils_Measurement_number_gamma_channels( const SpecUtils_Measurement * const instance ); diff --git a/src/SpecFile.cpp b/src/SpecFile.cpp index 37079b1..02879f6 100644 --- a/src/SpecFile.cpp +++ b/src/SpecFile.cpp @@ -1591,6 +1591,8 @@ void Measurement::reset() dose_rate_ = exposure_rate_ = -1.0f; + pcf_tag_ = '\0'; + location_.reset(); }//void reset() @@ -1621,6 +1623,18 @@ float Measurement::exposure_rate() const { return exposure_rate_; } + + +char Measurement::pcf_tag() const +{ + return pcf_tag_; +} + + +void Measurement::set_pcf_tag( const char tag_char ) +{ + pcf_tag_ = tag_char; +} void Measurement::combine_gamma_channels( const size_t ncombine ) @@ -3548,6 +3562,12 @@ void Measurement::equal_enough( const Measurement &lhs, const Measurement &rhs ) + " while RHS is " + std::to_string(rhs.exposure_rate_) ); } + if( lhs.pcf_tag_ != rhs.pcf_tag_ ) + { + issues.push_back( string("Measurement: The PCF tag of LHS is ") + lhs.pcf_tag_ + + " while RHS is " + std::to_string(rhs.pcf_tag_) ); + } + if( (!lhs.location_) != (!rhs.location_) ) { issues.push_back( "Measurement: The " @@ -4402,6 +4422,8 @@ const Measurement &Measurement::operator=( const Measurement &rhs ) dose_rate_ = rhs.dose_rate_; exposure_rate_ = rhs.exposure_rate_; + pcf_tag_ = rhs.pcf_tag_; + location_ = rhs.location_; return *this; @@ -7830,6 +7852,9 @@ std::shared_ptr SpecFile::sum_measurements( const std::set &sa dataH->exposure_rate_ += meas->exposure_rate_; }//if( meas->dose_rate_ >= 0.0f ) + if( meas->pcf_tag_ != '\0' ) + dataH->pcf_tag_ = meas->pcf_tag_; + if( meas->has_gps_info() ) { num_gps += 1; diff --git a/src/SpecFile_n42.cpp b/src/SpecFile_n42.cpp index 2535c07..ac49643 100644 --- a/src/SpecFile_n42.cpp +++ b/src/SpecFile_n42.cpp @@ -1252,6 +1252,14 @@ void add_spectra_to_measurement_node_in_2012_N42_xml( ::rapidxml::xml_node Spectrum->append_node( remark ); } + if( m->pcf_tag() != '\0' ) + { + const string tag_remark = string("Tag: ") + m->pcf_tag(); + val = doc->allocate_string( tag_remark.c_str(), tag_remark.size()+1 ); + xml_node *remark = doc->allocate_node( node_element, "Remark", val ); + Spectrum->append_node( remark ); + }// + const std::vector &remarks = m->remarks(); for( size_t i = 0; i < remarks.size(); ++i ) { @@ -1331,6 +1339,14 @@ void add_spectra_to_measurement_node_in_2012_N42_xml( ::rapidxml::xml_node GrossCounts->append_node( remark ); }//if( m->title_.size() ) + if( m->pcf_tag() != '\0' ) + { + const string tag_remark = string("Tag: ") + m->pcf_tag(); + val = doc->allocate_string( tag_remark.c_str(), tag_remark.size()+1 ); + xml_node *remark = doc->allocate_node( node_element, "Remark", val ); + GrossCounts->append_node( remark ); + }// + const auto &remarks = m->remarks(); for( size_t i = 0; i < remarks.size(); ++i ) { @@ -2603,6 +2619,13 @@ struct N42DecodeHelper2006 meas.title_ = remark; continue; } + + if( SpecUtils::istarts_with( remark, "Tag:") ) + { + const string tag_str = SpecUtils::trim_copy( remark.substr(4) ); + meas.pcf_tag_ = tag_str.empty() ? '\0' : tag_str[0]; + continue; + } meas.remarks_.push_back( remark ); @@ -3615,6 +3638,10 @@ struct N42DecodeHelper2012 rel_loc->from_cartesian( dx, dy, dz ); } */ + }else if( SpecUtils::istarts_with( remark, "Tag:") ) + { + const string tag_str = SpecUtils::trim_copy( remark.substr(4) ); + meas->pcf_tag_ = tag_str.empty() ? '\0' : tag_str[0]; }else if( remark.size() ) { meas->remarks_.emplace_back( std::move(remark) ); @@ -4008,6 +4035,11 @@ struct N42DecodeHelper2012 { //See notes in equivalent portion of code for the tag meas->title_ += SpecUtils::trim_copy( remark.substr(6) ); + }else if( SpecUtils::istarts_with( remark, "Tag:") ) + { + //See notes in equivalent portion of code for the tag + const string tag_str = SpecUtils::trim_copy( remark.substr(4) ); + meas->pcf_tag_ = tag_str.empty() ? '\0' : tag_str.front(); }else if( !remark.empty() ) { meas->remarks_.push_back( remark ); @@ -9293,6 +9325,9 @@ namespace SpecUtils if( title_.size() ) remarks.push_back( "Title: " + title_ ); + if( pcf_tag_ != '\0' ) + remarks.push_back( string("Tag: ") + pcf_tag_ ); + bool wroteSurvey = false, wroteName = false, wroteSpeed = false; for( size_t i = 0; i < remarks_.size(); ++i ) diff --git a/src/SpecFile_pcf.cpp b/src/SpecFile_pcf.cpp index 95dbe22..6f11b64 100644 --- a/src/SpecFile_pcf.cpp +++ b/src/SpecFile_pcf.cpp @@ -751,7 +751,6 @@ bool SpecFile::write_pcf( std::ostream &outputstrm ) const string spectrum_title; //ex: 'Survey 1 Det=Aa1 Background @250cm' string collection_time; //Formatted like: '2010-02-24T00:08:24.82Z' - char character_tag; float live_time, true_time, halflife = 0.0, molecular_weight = 0.0, spectrum_multiplier = 0.0, offset, gain, quadratic, cubic, low_energy, neutron_counts; @@ -959,18 +958,18 @@ bool SpecFile::write_pcf( std::ostream &outputstrm ) const else collection_time = " "; //"01-Jan-1900 00:00:00.00"; //23 characters - character_tag = ' '; + char character_tag = meas->pcf_tag(); //From phone conversation with Dean 20170816: // The meaning of the 'tag' character is highly overloaded, and can mean, - // among other usses: + // among other uses: // '-' not occupied, and anything else occupied - for RPM data // '-' use a dashed line when plotting // '<' Use filled region style when plotting // 'T' Calibration from thorium - // 'K' Calibration from potasium + // 'K' Calibration from potassium - if( passthrough() ) + if( ((character_tag == '\0') || (character_tag == ' ')) && passthrough() ) { if( (meas->occupied() == OccupancyStatus::NotOccupied) && (meas->source_type() != SourceType::Background) ) @@ -1693,6 +1692,7 @@ bool SpecFile::load_from_pcf( std::istream &input ) if( !source_list.empty() ) meas->remarks_.push_back( "Source: " + source_list ); + meas->pcf_tag_ = character_tag; if( character_tag == '-' ) { meas->occupied_ = OccupancyStatus::NotOccupied; @@ -1702,7 +1702,7 @@ bool SpecFile::load_from_pcf( std::istream &input ) meas->occupied_ = OccupancyStatus::Occupied; //Background spectra should not have the tag character be a dash, as the - // tag chacter could indicate calibration isotope. + // tag character could indicate calibration isotope. if( meas->source_type_ == SourceType::Background ) meas->occupied_ = OccupancyStatus::NotOccupied; }else