如何在 C++ 中读取 NetCDF "global attribute"

How to read NetCDF "global attribute" in C++

这是我的第一个问题:

我正在尝试从 NetCDF 文件中读取 "global attributes"(使用旧版 C++ API)。 "global attribute" 我的意思是添加到 NcFile 而不是 NcVar 的属性。

对于大多数情况,“Example netCDF programs”很有用——但没有 "global attributes".

的示例

咨询 "netcdfcpp.h" 我发现了一些事情:

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

附件是我的问题 "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++ 用户指南中的说明非常清楚:http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-cxx/Class-NcAtt.html#Class-NcAtt

"Because attributes are only associated with open netCDF files, there are no public constructors for this class. Use member functions of NcFile and NcVar to get netCDF attributes or add new attributes."

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

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

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

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

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

  • 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——它只有 returns 一个指针。因此直接使用是行不通的:

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;
}