"Fossies" - the Fresh Open Source Software Archive

Member "fimex-1.4.2/src/metgm/MetGmCDMWriterImpl.cc" (6 Jan 2020, 14412 Bytes) of package /linux/privat/fimex-1.4.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "MetGmCDMWriterImpl.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.4.1_vs_1.4.2.

    1 /*
    2  * Fimex
    3  *
    4  * (C) Copyright 2011-2019, met.no
    5  *
    6  * Project Info:  https://wiki.met.no/fimex/start
    7  *
    8  * This library is free software; you can redistribute it and/or modify it
    9  * under the terms of the GNU Lesser General Public License as published by
   10  * the Free Software Foundation; either version 2.1 of the License, or
   11  * (at your option) any later version.
   12  *
   13  * This library is distributed in the hope that it will be useful, but
   14  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
   16  * License for more details.
   17  *
   18  * You should have received a copy of the GNU Lesser General Public
   19  * License along with this library; if not, write to the Free Software
   20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
   21  * USA.
   22  */
   23 
   24 #include "MetGmCDMWriterImpl.h"
   25 
   26 // private/implementation code
   27 //
   28 #include "MetGmCommentAttributeParser.h"
   29 #include "MetGmGroup1Ptr.h"
   30 #include "MetGmGroup2Ptr.h"
   31 #include "MetGmGroup3Ptr.h"
   32 #include "MetGmVersion.h"
   33 
   34 // fimex
   35 //
   36 #include "fimex/CDM.h"
   37 #include "fimex/SharedArray.h"
   38 #include "fimex/String2Type.h"
   39 #include "fimex/Units.h"
   40 #include "fimex/XMLDoc.h"
   41 #include "fimex/min_max.h"
   42 
   43 // libxml2
   44 #include <libxml/tree.h>
   45 #include <libxml/xpath.h>
   46 
   47 // standard
   48 #include <cmath>
   49 #include <memory>
   50 
   51 namespace MetNoFimex {
   52 
   53 typedef std::shared_ptr<MetGmTags> MetGmTagsPtr;
   54 
   55 MetGmCDMWriterImpl::MetGmCDMWriterImpl(CDMReader_p cdmReader, const std::string& outputFile, const std::string& configFile)
   56     : CDMWriter(cdmReader, outputFile)
   57 {
   58     if (configFile.empty())
   59         throw CDMException("Please supply xml config file the MetGm writer has to be informed how are pids mapped to actual CDM variables");
   60     xmlConfig_.reset(new XMLDoc(configFile));
   61 }
   62 
   63 MetGmCDMWriterImpl::~MetGmCDMWriterImpl() {}
   64 
   65 void MetGmCDMWriterImpl::configureAndWrite()
   66 {
   67     metgmTimeTag_ = MetGmTimeTag::createMetGmTimeTagGlobal(cdmReader);
   68     metgmVersion_ = MetGmVersion::createMetGmVersion(xmlConfig_);
   69     metgmFileHandle_ = MetGmFileHandlePtr::createMetGmFileHandlePtrForWriting(outputFile);
   70     metgmHandle_ = MetGmHandlePtr::createMetGmHandleForWriting(metgmFileHandle_, metgmVersion_);
   71     configure(xmlConfig_);
   72     init();
   73     write();
   74 }
   75 
   76 void MetGmCDMWriterImpl::configure(const std::unique_ptr<XMLDoc>& doc)
   77 {
   78     const CDM& cdmRef = cdmReader->getCDM();
   79 
   80     // start metgm_parameter
   81     xmlXPathObject_p xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter");
   82     xmlNodeSetPtr nodes = xpathObj->nodesetval;
   83     size_t size = (nodes) ? nodes->nodeNr : 0;
   84     for (size_t i = 0; i < size; ++i) {
   85         xmlNodePtr node = nodes->nodeTab[i];
   86 
   87         std::string metgmName = getXmlProp(node, "name");
   88         if (metgmName.empty()) {
   89             continue;
   90         }
   91 
   92         xmlXPathObject_p xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter[@name=\"" + metgmName + "\"]/attribute[@name=\"metgm_p_id\"]");
   93         std::string str_p_id;
   94         short p_id = 0;
   95         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
   96             str_p_id = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
   97             if (str_p_id.empty()) {
   98                 continue;
   99             }
  100             p_id = string2type<size_t>(str_p_id);
  101         } else {
  102             continue;
  103         }
  104 
  105         xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter[@name=\"" + metgmName + "\"]/attribute[@name=\"_FillValue\"]");
  106         std::string str_FillValue;
  107         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  108             str_FillValue = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  109         }
  110 
  111         xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter[@name=\"" + metgmName + "\"]/attribute[@name=\"units\"]");
  112         std::string str_units;
  113         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  114             str_units = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  115         }
  116 
  117         xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter[@name=\"" + metgmName + "\"]/attribute[@name=\"standard_name\"]");
  118         std::string str_standard_name;
  119         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  120             str_standard_name = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  121             if (str_standard_name.empty()) {
  122                 continue;
  123             }
  124             // find all variables with given standard_name value
  125             std::vector<std::string> varNames = cdmRef.findVariables("standard_name", str_standard_name);
  126             for (size_t index = 0; index < varNames.size(); ++index) {
  127                 std::string varName = varNames[index];
  128                 if (cdmRef.hasDimension(varName)) {
  129                     continue;
  130                 }
  131 
  132                 const CDMVariable* pVar = &cdmRef.getVariable(varName);
  133 
  134                 if (!str_units.empty() && !cdmRef.getUnits(varName).empty()) {
  135                     /* check if dimensions convertible */
  136                     Units checker;
  137                     if (!checker.areConvertible(str_units, cdmRef.getUnits(varName))) {
  138                         continue;
  139                     }
  140                 }
  141 
  142                 MetGmConfigurationMappings cfgEntry(p_id, pVar->getName());
  143                 cfgEntry.units_ = str_units.empty() ? std::string() : str_units;
  144 
  145                 if (!str_FillValue.empty())
  146                     cfgEntry.fillValue_ = str_FillValue;
  147 
  148                 xmlConfiguration_.insert(cfgEntry);
  149             }
  150 
  151         } else {
  152             continue;
  153         }
  154     }
  155     // end metgm_parameter
  156 
  157     xpathObj = doc->getXPathObject("/metgm_config/writer/variable");
  158     nodes = xpathObj->nodesetval;
  159     size = (nodes) ? nodes->nodeNr : 0;
  160     for (size_t i = 0; i < size; ++i) {
  161 
  162         xmlNodePtr node = nodes->nodeTab[i];
  163 
  164         std::string kildeName = getXmlProp(node, "name");
  165         if (kildeName.empty()) {
  166             continue;
  167         }
  168 
  169         if (!cdmRef.hasVariable(kildeName)) {
  170             continue;
  171         }
  172 
  173         xmlXPathObject_p xpathObj = doc->getXPathObject("/metgm_config/writer/variable[@name=\"" + kildeName + "\"]/attribute[@name=\"metgm_p_id\"]");
  174         short p_id = 0;
  175         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  176             const std::string str_p_id = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  177             if (str_p_id.empty()) {
  178                 continue;
  179             }
  180             p_id = string2type<size_t>(str_p_id);
  181         } else {
  182             continue;
  183         }
  184 
  185         xpathObj = doc->getXPathObject("/metgm_config/writer/metgm_parameter[@name=\"" + kildeName + "\"]/attribute[@name=\"units\"]");
  186         std::string str_units;
  187         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  188             str_units = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  189         }
  190 
  191         const CDMVariable* pVar = &cdmRef.getVariable(kildeName);
  192 
  193         if (!str_units.empty() && !cdmRef.getUnits(kildeName).empty()) {
  194             /* check if dimensions convertible */
  195             Units checker;
  196             if (!checker.areConvertible(str_units, cdmRef.getUnits(kildeName))) {
  197                 continue;
  198             }
  199         }
  200 
  201         MetGmConfigurationMappings cfgEntry(p_id, pVar->getName());
  202 
  203         xpathObj = doc->getXPathObject("/metgm_config/writer/variable[@name=\"" + kildeName + "\"]/attribute[@name=\"_FillValue\"]");
  204         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  205             cfgEntry.fillValue_ = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  206         }
  207 
  208         xpathObj = doc->getXPathObject("/metgm_config/writer/variable[@name=\"" + kildeName + "\"]/attribute[@name=\"add_offset\"]");
  209         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  210             cfgEntry.addOffset_ = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  211         }
  212 
  213         xpathObj = doc->getXPathObject("/metgm_config/writer/variable[@name=\"" + kildeName + "\"]/attribute[@name=\"scale_factor\"]");
  214         if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) {
  215             cfgEntry.scaleFactor_ = getXmlProp(xpathObj->nodesetval->nodeTab[0], "value");
  216         }
  217 
  218         xmlConfiguration_.insert(cfgEntry);
  219     }
  220 }
  221 
  222 void MetGmCDMWriterImpl::init()
  223 {
  224     for (xml_configuration::const_iterator pIt : sorted_by_pid(xmlConfiguration_)) {
  225         const MetGmConfigurationMappings& entry = *pIt;
  226 
  227         if (std::find_if(cdmConfiguration_.begin(), cdmConfiguration_.end(), MetGmCDMVariableProfileEqName(entry.cdmName_)) != cdmConfiguration_.end()) {
  228             throw CDMException("hmmm... the variable should not be found in cdm profile map");
  229         }
  230 
  231         const CDMVariable* pVariable = &cdmReader->getCDM().getVariable(entry.cdmName_);
  232 
  233         MetGmTagsPtr tags = MetGmTags::createMetGmTagsForWriting(cdmReader, pVariable, metgmHandle_, entry.p_id_);
  234         assert(tags.get());
  235 
  236         if (!tags->data()) {
  237             continue;
  238         }
  239 
  240         MetGmCDMVariableProfile profile(entry.p_id_, entry.cdmName_, tags);
  241         cdmConfiguration_.push_back(profile);
  242     }
  243 }
  244 
  245 void MetGmCDMWriterImpl::write()
  246 {
  247     writeGroup0Data();
  248     writeGroup1Data();
  249     writeGroup2Data();
  250 
  251     writeHeader();
  252 
  253     const CDM& cdmRef = cdmReader->getCDM();
  254     for (const auto& profile : cdmConfiguration_) {
  255         const CDMVariable* pVariable = &cdmRef.getVariable(profile.cdmName_);
  256         writeGroup3Data(profile);
  257         writeGroup4Data(profile);
  258         writeGroup5Data(profile, pVariable);
  259     }
  260 }
  261 
  262 void MetGmCDMWriterImpl::writeGroup0Data()
  263 {
  264     MGM_THROW_ON_ERROR(mgm_set_version(*metgmHandle_, *metgmVersion_));
  265 }
  266 
  267 void MetGmCDMWriterImpl::writeGroup1Data()
  268 {
  269     std::shared_ptr<MetGmGroup1Ptr> pg1 = MetGmGroup1Ptr::createMetGmGroup1PtrForWriting(cdmReader);
  270     MGM_THROW_ON_ERROR(mgm_set_analysis_date_time(*metgmHandle_, pg1->analysisTime()))
  271     MGM_THROW_ON_ERROR(mgm_set_start_date_time(*metgmHandle_, pg1->startTime()))
  272     MGM_THROW_ON_ERROR(mgm_set_free_text(*metgmHandle_, pg1->freeText().c_str()))
  273     MGM_THROW_ON_ERROR(mgm_set_data_type(*metgmHandle_, pg1->dataType()))
  274     MGM_THROW_ON_ERROR(mgm_set_model_type(*metgmHandle_, pg1->modelType().c_str()))
  275     MGM_THROW_ON_ERROR(mgm_set_production_nation(*metgmHandle_, pg1->productNation().c_str()))
  276 }
  277 
  278 void MetGmCDMWriterImpl::writeGroup2Data()
  279 {
  280     const short np = cdmConfiguration_.size();
  281 
  282     MGM_THROW_ON_ERROR(mgm_set_number_of_params(*metgmHandle_, np))
  283 
  284     if (*metgmVersion_ == MGM_Edition2) {
  285 
  286         std::set<short> uniquePid;
  287         for (const MetGmCDMVariableProfile& profile : cdmConfiguration_)
  288             uniquePid.insert(profile.p_id_);
  289 
  290         const short ndp = uniquePid.size();
  291         MGM_THROW_ON_ERROR(mgm_set_number_of_dist_params(*metgmHandle_, ndp))
  292 
  293         size_t index = 0;
  294         for (const short p_id : uniquePid) {
  295 
  296             ++index;
  297 
  298             const MetGmCDMVariableProfileEqPId byPId(p_id);
  299 
  300             size_t ndpr = std::count_if(cdmConfiguration_.begin(), cdmConfiguration_.end(), byPId);
  301 
  302             MGM_THROW_ON_ERROR(mgm_set_param_id(*metgmHandle_, index, p_id))
  303             MGM_THROW_ON_ERROR(mgm_set_ndpr(*metgmHandle_, index, ndpr))
  304 
  305             /**
  306              * TODO: should HD be treated as CDMAttribute?
  307              *
  308              * the HD value should be highest for given parameter
  309              */
  310             const cdm_configuration::iterator pEnd = cdmConfiguration_.end();
  311             cdm_configuration::iterator pIt = std::find_if(cdmConfiguration_.begin(), pEnd, byPId);
  312             const short hd = pIt->hd();
  313 #if 1
  314             for (cdm_configuration::iterator nIt = pIt; (nIt = std::find_if(++nIt, pEnd, byPId)) != pEnd;) {
  315                 if (hd != nIt->hd())
  316                     throw CDMException("change in dimensionality");
  317             }
  318 #endif
  319             MGM_THROW_ON_ERROR(mgm_set_hd(*metgmHandle_, index, hd))
  320         }
  321     }
  322 }
  323 
  324 void MetGmCDMWriterImpl::writeHeader()
  325 {
  326     MGM_THROW_ON_ERROR(mgm_write_header(*metgmFileHandle_, *metgmHandle_))
  327 }
  328 
  329 void MetGmCDMWriterImpl::writeGroup3TimeAxis(const MetGmTagsPtr& tags)
  330 {
  331     if (tags->tTag().get()) {
  332         MGM_THROW_ON_ERROR(tags->set_nt(tags->tTag()->nT()))
  333         MGM_THROW_ON_ERROR(tags->set_dt(tags->tTag()->dT()))
  334     } else {
  335         MGM_THROW_ON_ERROR(tags->set_nt(1))
  336         MGM_THROW_ON_ERROR(tags->set_dt(metgmTimeTag_->dT() * metgmTimeTag_->nT()))
  337     }
  338 }
  339 
  340 void MetGmCDMWriterImpl::writeGroup3HorizontalAxis(const MetGmTagsPtr& tags)
  341 {
  342     // x
  343     MGM_THROW_ON_ERROR(tags->set_dx(tags->xTag()->dx()));
  344     MGM_THROW_ON_ERROR(tags->set_nx(tags->xTag()->nx()));
  345     MGM_THROW_ON_ERROR(tags->set_cx(tags->xTag()->cx()));
  346     // y
  347     MGM_THROW_ON_ERROR(tags->set_dy(tags->yTag()->dy()));
  348     MGM_THROW_ON_ERROR(tags->set_ny(tags->yTag()->ny()));
  349     MGM_THROW_ON_ERROR(tags->set_cy(tags->yTag()->cy()));
  350 }
  351 
  352 void MetGmCDMWriterImpl::writeGroup3VerticalAxis(const MetGmTagsPtr& tags)
  353 {
  354     if (tags->zTag().get()) {
  355         MGM_THROW_ON_ERROR(tags->set_nz(tags->zTag()->nz()));
  356         MGM_THROW_ON_ERROR(tags->set_pr(tags->zTag()->pr()));
  357         MGM_THROW_ON_ERROR(tags->set_pz(tags->zTag()->pz()));
  358     } else {
  359         MGM_THROW_ON_ERROR(tags->set_nz(1));
  360         MGM_THROW_ON_ERROR(tags->set_pr(0));
  361         MGM_THROW_ON_ERROR(tags->set_pz(1));
  362     }
  363 }
  364 
  365 void MetGmCDMWriterImpl::writeGroup3Data(const MetGmCDMVariableProfile& profile)
  366 {
  367     const MetGmTagsPtr& tags = profile.pTags_;
  368     writeGroup3TimeAxis(tags);
  369     writeGroup3HorizontalAxis(tags);
  370     writeGroup3VerticalAxis(tags);
  371     MGM_THROW_ON_ERROR(mgm_write_group3(*metgmFileHandle_, *metgmHandle_, *tags->gp3()));
  372 }
  373 
  374 void MetGmCDMWriterImpl::writeGroup4Data(const MetGmCDMVariableProfile& profile)
  375 {
  376     if (std::shared_ptr<MetGmVerticalTag> ztag = profile.pTags_->zTag()) {
  377         MGM_THROW_ON_ERROR(mgm_write_group4(*metgmFileHandle_, *metgmHandle_, ztag->points().get()));
  378     } else {
  379         /* no z profile for variable */
  380         float f = 0;
  381         MGM_THROW_ON_ERROR(mgm_write_group4(*metgmFileHandle_, *metgmHandle_, &f));
  382     }
  383 }
  384 
  385 void MetGmCDMWriterImpl::writeGroup5Data(const MetGmCDMVariableProfile& profile, const CDMVariable*)
  386 {
  387     MGM_THROW_ON_ERROR(mgm_write_group5(*metgmFileHandle_, *metgmHandle_, profile.pTags_->data().get()));
  388 }
  389 
  390 } // namespace MetNoFimex