mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 04:30:05 +00:00 
			
		
		
		
	P-VTEC parsing
This commit is contained in:
		
							parent
							
								
									e5c40b9eb5
								
							
						
					
					
						commit
						be1d7323bd
					
				
					 10 changed files with 835 additions and 5 deletions
				
			
		
							
								
								
									
										275
									
								
								wxdata/source/scwx/awips/pvtec.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								wxdata/source/scwx/awips/pvtec.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,275 @@ | |||
| // Enable chrono formatters
 | ||||
| #ifndef __cpp_lib_format | ||||
| #   define __cpp_lib_format 202110L | ||||
| #endif | ||||
| 
 | ||||
| #include <scwx/awips/pvtec.hpp> | ||||
| 
 | ||||
| #include <chrono> | ||||
| 
 | ||||
| #include <boost/assign.hpp> | ||||
| #include <boost/bimap.hpp> | ||||
| #include <boost/bimap/unordered_set_of.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| namespace scwx | ||||
| { | ||||
| namespace awips | ||||
| { | ||||
| 
 | ||||
| static const std::string logPrefix_ = "[scwx::awips::pvtec] "; | ||||
| 
 | ||||
| typedef boost::bimap<boost::bimaps::unordered_set_of<PVtec::ProductType>, | ||||
|                      boost::bimaps::unordered_set_of<std::string>> | ||||
|    ProductTypeCodesBimap; | ||||
| 
 | ||||
| static const ProductTypeCodesBimap productTypeCodes_ = | ||||
|    boost::assign::list_of<ProductTypeCodesBimap::relation>    //
 | ||||
|    (PVtec::ProductType::Operational, "O")                     //
 | ||||
|    (PVtec::ProductType::Test, "T")                            //
 | ||||
|    (PVtec::ProductType::Experimental, "E")                    //
 | ||||
|    (PVtec::ProductType::OperationalWithExperimentalVtec, "X") //
 | ||||
|    (PVtec::ProductType::Unknown, "??"); | ||||
| 
 | ||||
| typedef boost::bimap<boost::bimaps::unordered_set_of<PVtec::Action>, | ||||
|                      boost::bimaps::unordered_set_of<std::string>> | ||||
|    ActionCodesBimap; | ||||
| 
 | ||||
| static const ActionCodesBimap actionCodes_ = | ||||
|    boost::assign::list_of<ActionCodesBimap::relation> //
 | ||||
|    (PVtec::Action::New, "NEW")                        //
 | ||||
|    (PVtec::Action::Continued, "CON")                  //
 | ||||
|    (PVtec::Action::ExtendedInArea, "EXA")             //
 | ||||
|    (PVtec::Action::ExtendedInTime, "EXT")             //
 | ||||
|    (PVtec::Action::ExtendedInAreaAndTime, "EXB")      //
 | ||||
|    (PVtec::Action::Upgraded, "UPG")                   //
 | ||||
|    (PVtec::Action::Canceled, "CAN")                   //
 | ||||
|    (PVtec::Action::Expired, "EXP")                    //
 | ||||
|    (PVtec::Action::Routine, "ROU")                    //
 | ||||
|    (PVtec::Action::Correction, "COR")                 //
 | ||||
|    (PVtec::Action::Unknown, "???"); | ||||
| 
 | ||||
| class PVtecImpl | ||||
| { | ||||
| public: | ||||
|    explicit PVtecImpl() : | ||||
|        pVtecString_ {}, | ||||
|        fixedIdentifier_ {PVtec::ProductType::Unknown}, | ||||
|        action_ {PVtec::Action::Unknown}, | ||||
|        officeId_ {"????"}, | ||||
|        phenomenon_ {Phenomenon::Unknown}, | ||||
|        significance_ {Significance::Unknown}, | ||||
|        eventTrackingNumber_ {-1}, | ||||
|        eventBegin_ {}, | ||||
|        eventEnd_ {}, | ||||
|        valid_ {false} | ||||
|    { | ||||
|    } | ||||
| 
 | ||||
|    ~PVtecImpl() {} | ||||
| 
 | ||||
|    std::string pVtecString_; | ||||
| 
 | ||||
|    PVtec::ProductType fixedIdentifier_; | ||||
|    PVtec::Action      action_; | ||||
|    std::string        officeId_; | ||||
|    Phenomenon         phenomenon_; | ||||
|    Significance       significance_; | ||||
|    int16_t            eventTrackingNumber_; | ||||
| 
 | ||||
|    std::chrono::system_clock::time_point eventBegin_; | ||||
|    std::chrono::system_clock::time_point eventEnd_; | ||||
| 
 | ||||
|    bool valid_; | ||||
| }; | ||||
| 
 | ||||
| PVtec::PVtec() : p(std::make_unique<PVtecImpl>()) {} | ||||
| PVtec::~PVtec() = default; | ||||
| 
 | ||||
| PVtec::PVtec(PVtec&&) noexcept = default; | ||||
| PVtec& PVtec::operator=(PVtec&&) noexcept = default; | ||||
| 
 | ||||
| PVtec::ProductType PVtec::fixed_identifier() const | ||||
| { | ||||
|    return p->fixedIdentifier_; | ||||
| } | ||||
| 
 | ||||
| PVtec::Action PVtec::action() const | ||||
| { | ||||
|    return p->action_; | ||||
| } | ||||
| 
 | ||||
| std::string PVtec::office_id() const | ||||
| { | ||||
|    return p->officeId_; | ||||
| } | ||||
| 
 | ||||
| Phenomenon PVtec::phenomenon() const | ||||
| { | ||||
|    return p->phenomenon_; | ||||
| } | ||||
| 
 | ||||
| Significance PVtec::significance() const | ||||
| { | ||||
|    return p->significance_; | ||||
| } | ||||
| 
 | ||||
| int16_t PVtec::event_tracking_number() const | ||||
| { | ||||
|    return p->eventTrackingNumber_; | ||||
| } | ||||
| 
 | ||||
| std::chrono::system_clock::time_point PVtec::event_begin() const | ||||
| { | ||||
|    return p->eventBegin_; | ||||
| } | ||||
| 
 | ||||
| std::chrono::system_clock::time_point PVtec::event_end() const | ||||
| { | ||||
|    return p->eventEnd_; | ||||
| } | ||||
| 
 | ||||
| bool PVtec::Parse(const std::string& s) | ||||
| { | ||||
|    using namespace std::chrono; | ||||
| 
 | ||||
|    // P-VTEC takes the form:
 | ||||
|    // /k.aaa.cccc.pp.s.####.yymmddThhnnZ-yymmddThhnnZ/
 | ||||
|    // 012345678901234567890123456789012345678901234567
 | ||||
|    static constexpr size_t pVtecLength_             = 48u; | ||||
|    static constexpr size_t pVtecOffsetStart_        = 0u; | ||||
|    static constexpr size_t pVtecOffsetIdentifier_   = 1u; | ||||
|    static constexpr size_t pVtecOffsetAction_       = 3u; | ||||
|    static constexpr size_t pVtecOffsetOfficeId_     = 7u; | ||||
|    static constexpr size_t pVtecOffsetPhenomenon_   = 12u; | ||||
|    static constexpr size_t pVtecOffsetSignificance_ = 15u; | ||||
|    static constexpr size_t pVtecOffsetEventNumber_  = 17u; | ||||
|    static constexpr size_t pVtecOffsetEventBegin_   = 22u; | ||||
|    static constexpr size_t pVtecOffsetEventEnd_     = 35u; | ||||
|    static constexpr size_t pVtecOffsetEnd_          = 47u; | ||||
| 
 | ||||
|    bool dataValid = (s.length() >= pVtecLength_ &&     //
 | ||||
|                      s.at(pVtecOffsetStart_) == '/' && //
 | ||||
|                      s.at(pVtecOffsetEnd_) == '/'); | ||||
| 
 | ||||
|    if (dataValid) | ||||
|    { | ||||
|       p->pVtecString_ = s.substr(0, pVtecLength_); | ||||
| 
 | ||||
|       p->fixedIdentifier_ = GetProductType(s.substr(pVtecOffsetIdentifier_, 1)); | ||||
|       p->action_          = GetAction(s.substr(pVtecOffsetAction_, 3)); | ||||
|       p->officeId_        = s.substr(pVtecOffsetOfficeId_, 4); | ||||
|       p->phenomenon_      = GetPhenomenon(s.substr(pVtecOffsetPhenomenon_, 2)); | ||||
|       p->significance_ = GetSignificance(s.substr(pVtecOffsetSignificance_, 1)); | ||||
| 
 | ||||
|       std::string eventNumberString = s.substr(pVtecOffsetEventNumber_, 4); | ||||
| 
 | ||||
|       try | ||||
|       { | ||||
|          p->eventTrackingNumber_ = | ||||
|             static_cast<int16_t>(std::stoi(eventNumberString)); | ||||
|       } | ||||
|       catch (const std::exception& ex) | ||||
|       { | ||||
|          BOOST_LOG_TRIVIAL(warning) | ||||
|             << logPrefix_ << "Error parsing event tracking number: \"" | ||||
|             << eventNumberString << "\" (" << ex.what() << ")"; | ||||
| 
 | ||||
|          p->eventTrackingNumber_ = -1; | ||||
|       } | ||||
| 
 | ||||
|       static const std::string dateTimeFormat {"%y%m%dT%H%MZ"}; | ||||
| 
 | ||||
|       std::string sEventBegin = s.substr(pVtecOffsetEventBegin_, 12); | ||||
|       std::string sEventEnd   = s.substr(pVtecOffsetEventEnd_, 12); | ||||
| 
 | ||||
|       std::istringstream ssEventBegin {sEventBegin}; | ||||
|       std::istringstream ssEventEnd {sEventEnd}; | ||||
| 
 | ||||
|       sys_time<minutes> eventBegin; | ||||
|       sys_time<minutes> eventEnd; | ||||
| 
 | ||||
|       ssEventBegin >> parse(dateTimeFormat, eventBegin); | ||||
|       ssEventEnd >> parse(dateTimeFormat, eventEnd); | ||||
| 
 | ||||
|       if (!ssEventBegin.fail()) | ||||
|       { | ||||
|          p->eventBegin_ = eventBegin; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          // Time parsing expected to fail if time is "000000T0000Z"
 | ||||
|          p->eventBegin_ = {}; | ||||
|       } | ||||
| 
 | ||||
|       if (!ssEventEnd.fail()) | ||||
|       { | ||||
|          p->eventEnd_ = eventEnd; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          // Time parsing expected to fail if time is "000000T0000Z"
 | ||||
|          p->eventEnd_ = {}; | ||||
|       } | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       BOOST_LOG_TRIVIAL(warning) | ||||
|          << logPrefix_ << "Invalid P-VTEC: \"" << s << "\""; | ||||
|    } | ||||
| 
 | ||||
|    p->valid_ = dataValid; | ||||
| 
 | ||||
|    return dataValid; | ||||
| } | ||||
| 
 | ||||
| PVtec::ProductType PVtec::GetProductType(const std::string& code) | ||||
| { | ||||
|    ProductType productType; | ||||
| 
 | ||||
|    if (productTypeCodes_.right.find(code) != productTypeCodes_.right.end()) | ||||
|    { | ||||
|       productType = productTypeCodes_.right.at(code); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       productType = ProductType::Unknown; | ||||
| 
 | ||||
|       BOOST_LOG_TRIVIAL(debug) | ||||
|          << logPrefix_ << "Unrecognized product code: \"" << code << "\""; | ||||
|    } | ||||
| 
 | ||||
|    return productType; | ||||
| } | ||||
| 
 | ||||
| std::string PVtec::GetProductTypeCode(PVtec::ProductType productType) | ||||
| { | ||||
|    return productTypeCodes_.left.at(productType); | ||||
| } | ||||
| 
 | ||||
| PVtec::Action PVtec::GetAction(const std::string& code) | ||||
| { | ||||
|    Action action; | ||||
| 
 | ||||
|    if (actionCodes_.right.find(code) != actionCodes_.right.end()) | ||||
|    { | ||||
|       action = actionCodes_.right.at(code); | ||||
|    } | ||||
|    else | ||||
|    { | ||||
|       action = Action::Unknown; | ||||
| 
 | ||||
|       BOOST_LOG_TRIVIAL(debug) | ||||
|          << logPrefix_ << "Unrecognized action code: \"" << code << "\""; | ||||
|    } | ||||
| 
 | ||||
|    return action; | ||||
| } | ||||
| 
 | ||||
| std::string PVtec::GetActionCode(PVtec::Action action) | ||||
| { | ||||
|    return actionCodes_.left.at(action); | ||||
| } | ||||
| 
 | ||||
| } // namespace awips
 | ||||
| } // namespace scwx
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat