【问题标题】:How to read NetCDF "global attribute" in C++如何在 C++ 中读取 NetCDF“全局属性”
【发布时间】:2018-01-04 00:27:11
【问题描述】:

这是我的第一个问题:

我正在尝试从 NetCDF 文件中读取“全局属性”(使用 C++ 旧版 API)。 “全局属性”是指添加到 NcFile 而非 NcVar 的属性。

对于大多数事情,“Example netCDF programs”很有用——但没有“全局属性”的示例。

查阅“netcdfcpp.h”我发现了一些东西:

  • NcFile 有一个成员函数:NcAtt* get_att(NcToken) const;
  • NcAtt 没有公共构造函数
  • NcAtt 是 NcFile 的好友:friend class NcFile;
  • NcAtt 有一个私有构造函数:NcAtt( NcFile*, NcToken);
  • NcAtt 有一个公共成员函数NcValues* values( void ) const;
  • NcValues 有一个通过 ncvalues.h 标头定义的 API

我的编码技能不足以理解我如何在 NcFile 的 NcAtt 类中返回存储为 NcValue 的 string/int/float。

附件是我的问题“NetCDF_test.cpp”的示例代码,在“LoadNetCDF”函数的实现中缺少关键部分。

代码编译成功:(编辑:另外,“TestFile.nc”被正确创建)

g++ -c NetCDF_test.cpp -o NetCDF_test.o

g++ -o NCTEST NetCDF_test.o -lnetcdf_c++ -lnetcdf

示例代码:

#include <iostream> // provides screen output (i.e. std::cout<<)
#include <netcdfcpp.h>

struct MyStructure {
    std::string MyString;
    int MyInt;
    float MyFloat;

    MyStructure();      // default constructor
    int SaveNetCDF(std::string);  // Save the struct content to "global attributes" in NetCDF
    int LoadNetCDF(std::string);  // Load the struct content from "global attributes" in NetCDF

};

MyStructure::MyStructure(void)
{
    MyString = "TestString";
    MyInt = 123;
    MyFloat = 1.23;
}

int MyStructure::SaveNetCDF(std::string OUTPUT_FILENAME)
{
    NcError err(NcError::silent_nonfatal);
    static const int NC_ERR = 2;
    NcFile NetCDF_File(OUTPUT_FILENAME.c_str(), NcFile::Replace);
    if(!NetCDF_File.is_valid()) {return NC_ERR;}

    if(!(NetCDF_File.add_att("MyString",MyString.c_str()))) {return NC_ERR;}
    if(!(NetCDF_File.add_att("MyInt",MyInt))) {return NC_ERR;}
    if(!(NetCDF_File.add_att("MyFloat",MyFloat))) {return NC_ERR;}

    return 0;
}

int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
{

    NcError err(NcError::silent_nonfatal);
    static const int NC_ERR = 2;

    NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
    if(!NetCDF_File.is_valid()) {return NC_ERR;}

    // ???? This is where I am stuck.
    // How do I read the global attribute from the NetCDF_File ??
    return 0;
}


int main()
{
    std::cout<< "START OF TEST.\n";

    MyStructure StructureInstance;  // datamembers initialized by constructor
    StructureInstance.SaveNetCDF("TestFile.nc");

    StructureInstance.MyString = "Change string for sake of testing";
    StructureInstance.MyInt = -987; 
    StructureInstance.MyFloat = -9.87;

    StructureInstance.LoadNetCDF("TestFile.nc");    // data members are supposed to be read from file

    std::cout<< "Now the data members of StructureInstance should be TestString, 123, and 1.23\n";
    std::cout<< StructureInstance.MyString << " ; " << StructureInstance.MyInt << " ; " << StructureInstance.MyFloat <<"\n";
    std::cout<< "END OF TEST.\n";
}

【问题讨论】:

    标签: c++ netcdf


    【解决方案1】:

    C++ 用户指南中清楚地说明了这一点:http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcAtt.html#Class-NcAtt

    "由于属性只与打开的 netCDF 文件相关联,因此该类没有公共构造函数。使用 NcFile 和 NcVar 的成员函数获取 netCDF 属性或添加新属性。"

    全局属性是文件上的属性(与变量属性相反,变量属性是变量上的属性)

    NetCDF_File.num_atts() 返回多少个全局属性。 get_att() 方法(以各种方式重载)将为您提供一个属性。

    咨询http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcFile.html#Class-NcFile

    【讨论】:

      【解决方案2】:

      非常感谢 Rob Latham 提供了指向 NetCDF API(旧版 C++)的注释描述的链接。根据那里提供的信息,我能够弄清楚:

      NcAtt 固有形式 NcTypedComponent 一组成员函数,用于访问存储在给定 NcAtt 中的数据:(int n == n-th 元素)

      • ncbyte as_ncbyte( int n ) const
      • char as_char( int n ) const
      • short as_short( int n ) const
      • int as_int( int n ) const
      • nclong as_nclong( int n ) const // deprecated
      • long as_long( int n ) const
      • float as_float( int n ) const
      • double as_double( int n ) const
      • char* as_string( int n ) const

      但是,NcAtt 的构造函数仍然是私有的,对现有 NcAtt 的唯一访问点是通过 NcFile 成员函数NcVar* get_var(NcToken name) const——它只返回一个指针。因此直接使用是行不通的:

      int MyInt = MyNcFile.get_att("MyInt").as_int(0); // DOES NOT COMPILE

      但是,取消引用 get_att 返回的指针就可以了。

      int MyInt = (*MyNcFile.get_att("MyInt")).as_int(0); // WORKS

      为了完整起见,我在下面包含了MyStructure::LoadNetCDF 的实现,用于我的原始问题的示例代码。

      int MyStructure::LoadNetCDF(std::string INPUT_FILENAME)
      {
          NcError err(NcError::silent_nonfatal);
          static const int NC_ERR = 2;
      
          NcFile NetCDF_File(INPUT_FILENAME.c_str(), NcFile::ReadOnly);
          if(!NetCDF_File.is_valid()) {return NC_ERR;}
      
          // NcAtt constructor is private, but one can obtain the pointer to an existing NcAtt
          NcAtt* PointerToMyIntNcAtt = NetCDF_File.get_att("MyInt"); 
          // Now, using the dereferencing operator one has access to the member functions that NcAtt inherents from NcTypedComponent
          if(!(*PointerToMyIntNcAtt).is_valid()) {return NC_ERR;}
          std::cout<< "Is MyInt a valid NcAtt? "<< (*PointerToMyIntNcAtt).is_valid()<<"\n";
      
          // The concise way of writing the access to NetCDF "global attributes"" of type int/float/string
          MyInt = (*NetCDF_File.get_att("MyInt")).as_int(0);
          MyFloat = (*NetCDF_File.get_att("MyFloat")).as_float(0);
          MyString = (*NetCDF_File.get_att("MyString")).as_string(0);
      
          return 0;
      }
      

      【讨论】:

      • 你不能用NetCDF_File-&gt;as_int(0) 替换(*NetCDF_File).as_int(0) 吗?
      • 我相信这是读取与 NcVar 关联的属性的方法——但它不适用于“全局属性”,因为显然没有实现运算符。当我使用“->”运算符进行编译时,出现以下错误:error: base operand of ‘-&gt;’ has non-pointer type ‘NcFile’
      • 糟糕,应该是:NetCDF_File.get_att("MyInt")-&gt;as_int(0)...还是失败了?
      • 是的,我确认这种方法也有效。所以我们有了它:有两种方法有效。 (1) 使用解引用运算符的“INDIRECTION” (*a.b();“a 指向的对象具有成员 b”); (2)“结构引用”(a->b();“a 指向的对象的成员 b”)。我想我刚刚学了一点 C/C++。酷。
      猜你喜欢
      • 2021-08-12
      • 2021-08-03
      • 1970-01-01
      • 2020-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-03
      相关资源
      最近更新 更多