Как читать NetCDF & quot; глобальный атрибут & quot; в переполнении стека

Это мой первый вопрос:

Я пытаюсь прочитать «глобальные атрибуты» из файла NetCDF (используя устаревший API C ++). Под «глобальным атрибутом» я подразумеваю атрибут, который был добавлен в NcFile, а не в NcVar.

Для большинства вещейПример программы netCDF«полезны — но нет примера для» глобальных атрибутов «.

Консультируясь с «netcdfcpp.h», я нахожу несколько вещей:

  • NcFile имеет функцию-член: NcAtt* get_att(NcToken) const;
  • NcAtt не имеет публичного конструктора
  • NcAtt дружит с NcFile: friend class NcFile;
  • NcAtt имеет приватный конструктор: NcAtt( NcFile*, NcToken);
  • NcAtt имеет публичную функцию-член NcValues* values( void ) const;
  • У NcValues ​​есть API, определенный через ncvalues.h заголовок

Моих навыков кодирования недостаточно, чтобы понять, как я возвращаюсь к строке / int / float, хранящейся как NcValue, в классе NcAtt в NcFile.

В приложении приведен пример кода моей проблемы «NetCDF_test.cpp», критическая часть которого отсутствует в реализации функции «LoadNetCDF».

Код компилируется нормально с помощью: (edit: также «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";
}

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

1

Другие решения

Большое спасибо Робу Лэтэму за ссылки на комментированное описание NetCDF API (устаревшая версия C ++). С информацией, предоставленной там, я смог понять это:

NcAtt неотъемлемая форма NcTypedComponent набор функций-членов для доступа к данным, хранящимся в данном NcAtt: (int n == n-й элемент)

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

По вопросам рекламы [email protected]