Creating a class and reading to a Ttree

Hello:

I am trying to read a netCDF file into a ROOT Ttree and have a problem.

I am converting a library called ancio, written by Jason Cristy at
the Pacific Northwest National Laboratory. The original library
opened a netCDF file and read the contents into a struct. The sample
netCDF file I have is from Jonathan Katz and Joerg Hau, included with
their program comspari.

I have removed many functions that acted on the data, and changed the
C struct to C++ class. I thought I could then use

Case B
======
TBranch *branch = tree->Branch(branchname,className,object, bufsize, splitlevel)
object is the address of a pointer to an existing object (derived from TObject).

to create the branch, with the type of the data being recognised.

After many hours of trying the file will compile with out warnings and run.
But I get the error:

“# g++ -Wall -o 4 -I. -lnetcdf root-config --libs mycode.c
[root@blue exp]# ./4
put tree here
Error in TTree::Bronch: Cannot find class:_ncData”

(I assume that ‘Bronch’ is to be ‘Branch’.)

[At this time, the included files will produce this result. I have commented the changes I made that resulted in the errors listed below.]

I thought it was because calloc was being used as the memory manager, but not quite understanding how to change all malloc et. al. calls to ‘new’ I tried one at the end. This works, as demonstrated by uncommenting “else print_ncdata(data);” which prints the dim, var, and att data in the file.

Reading the ROOT manual, I realised I needed to have ClassDef at the bottom of the class declarations.

That results in the file no longer compiling, exiting with the following errors:

g++ -Wall -o 3 -I. -lnetcdf root-config --libs mycode.c

/tmp/ccwJ63eP.o: In function _ncData::_ncData()': mycode.c:(.text._ZN7_ncDataC1Ev[_ncData::_ncData()]+0x12): undefined reference tovtable for _ncData’
/tmp/ccwJ63eP.o: In function TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)': mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference totypeinfo for _ncData’
collect2: ld returned 1 exit status
[root@blue exp]# g++ -Wall -o 3 -I. -lnetcdf root-config --libs mycode.c
/tmp/ccoLjLMH.o: In function _ncData::_ncData()': mycode.c:(.text._ZN7_ncDataC1Ev[_ncData::_ncData()]+0x12): undefined reference tovtable for _ncData’
/tmp/ccoLjLMH.o: In function TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)': mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference totypeinfo for _ncData’
collect2: ld returned 1 exit status

I think from the manual I need to use rootcint but that results in this error:

rootcint code.cxx -c mycode.h

Error: Too many ‘}’ /usr/include/netcdf.h:587:
Segmentation fault

This code depends on the netcdf library, which I compiled myself but is available as an rpm.

I am using Fedora 8

uname -a

Linux blue 2.6.22.18-co-0.8.0 #1 PREEMPT Sun Nov 23 20:33:36 UTC 2008 i686 i686 i386 GNU/Linux

and the default Fedora 8 g++ compiler

g++ -v

Using built-in specs.
Target: i386-redhat-linux
Configured with: …/configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)

I compiled ROOT myself

root


  •                                     *
    
  •    W E L C O M E  to  R O O T       *
    
  •                                     *
    
  • Version 5.22/00 17 December 2008 *
  •                                     *
    
  • You are welcome to visit our Web site *
  •      [root.cern.ch](http://root.cern.ch)            *
    
  •                                     *
    

ROOT 5.22/00 (trunk@26997, Jan 26 2009, 22:17:00 on linux)

Am I failing to include a header file?

tree2.root is created when the
Error in TTree::Bronch: Cannot find class:_ncData
is received. Also, three non-compilable files
were created by the rootcint error. Or, how am I to compile
and then link them?

Thank you.
mycode.h (5.78 KB)
mycode.c (38.5 KB)

You must generate a dictionary for the classes to be put in the Tree.

rootcint -f mycode_dict.cxx -c -p mycode.h to get help on rootcint do

rootcint -h
or alternatively in a root session do

root > .L mycode.h+ root >.x mycode.c+
Rene

Hello:

The source code mycode.h and mycode.c with the netCDF
file trun.nc (a truncated file comprized of a portion of
wt.CDF, from Katz and Hau as previously mentioned) produces
the following output:

g++ -o run_try -I. -lnetcdf root-config --libs mycode.c

[root@localhost newcxx]# ./run_try

Dimensions:

| DIM: scan_number, ID: 0, Length: 1050

Global Attributes:

| ATT: dataset_completeness, ID: 0, Length: 6
| ATT: ms_template_revision, ID: 1, Length: 6
| ATT: netcdf_revision, ID: 2, Length: 6
| ATT: languages, ID: 3, Length: 8
| ATT: dataset_origin, ID: 4, Length: 1
| ATT: dataset_owner, ID: 5, Length: 1
| ATT: netcdf_file_date_time_stamp, ID: 6, Length: 20
| ATT: experiment_title, ID: 7, Length: 19
| ATT: experiment_date_time_stamp, ID: 8, Length: 20
| ATT: operator_name, ID: 9, Length: 1
| ATT: source_file_reference, ID: 10, Length: 30
| ATT: source_file_format, ID: 11, Length: 12
| ATT: source_file_date_time_stamp, ID: 12, Length: 20
| ATT: experiment_type, ID: 13, Length: 25
| ATT: sample_state, ID: 14, Length: 12
| ATT: test_separation_type, ID: 15, Length: 18
| ATT: test_ms_inlet, ID: 16, Length: 19
| ATT: test_ionization_mode, ID: 17, Length: 16
| ATT: test_ionization_polarity, ID: 18, Length: 18
| ATT: test_detector_type, ID: 19, Length: 16
| ATT: test_resolution_type, ID: 20, Length: 20
| ATT: test_scan_function, ID: 21, Length: 10
| ATT: test_scan_direction, ID: 22, Length: 3
| ATT: test_scan_law, ID: 23, Length: 7
| ATT: raw_data_mass_format, ID: 24, Length: 6
| ATT: raw_data_time_format, ID: 25, Length: 6
| ATT: raw_data_intensity_format, ID: 26, Length: 6
| ATT: units, ID: 27, Length: 8
| ATT: scale_factor, ID: 28, Length: 1
| ATT: global_mass_min, ID: 29, Length: 1
| ATT: global_mass_max, ID: 30, Length: 1
| ATT: actual_run_time_length, ID: 31, Length: 1
| ATT: actual_delay_time, ID: 32, Length: 1
| ATT: raw_data_uniform_sampling_flag, ID: 33, Length: 1
| ATT: history, ID: 34, Length: 68
| ATT: NCO, ID: 35, Length: 6

Variables:

VAR: total_intensity, ID: 0, Dimids: (0)
Attributes:
ATT: units, ID: 0, Length: 26
---------------------------------

put tree here
Error in TTree::Bronch: Cannot find class:_ncData
[root@localhost newcxx]#

To fix that problem I am trying to, via rootcint, produce a dictionary
for ROOT to understand my class, as described in the ROOT manual and as
Dr. Brun answered my first question.

Adding ClassDef(_Dimensions, 1);
etc to each class [in mycode.h by removing the // ]
produces the following output:

g++ -Wall -o 1 -I. -lnetcdf root-config --libs mycode.c

/tmp/ccbzpK09.o: In function _ncData::_ncData()': mycode.c:(.text._ZN7_ncDataC1Ev[_ncData::_ncData()]+0x12): undefined reference tovtable for _ncData’
/tmp/ccbzpK09.o: In function TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)': mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference totypeinfo for _ncData’
collect2: ld returned 1 exit status

Adding ClassImp() [in mycode.c by removing // ]
produces the following output:

g++ -Wall -o 1 -I. -lnetcdf root-config --libs mycode.c

/tmp/cca1zjzc.o: In function __static_initialization_and_destruction_0(int, int)': mycode.c:(.text+0x311): undefined reference toROOT::GenerateInitInstance(_Dimensions const*)’
mycode.c:(.text+0x33a): undefined reference to ROOT::GenerateInitInstance(_Attributes const*)' mycode.c:(.text+0x363): undefined reference toROOT::GenerateInitInstance(_Variables const*)’
mycode.c:(.text+0x38c): undefined reference to ROOT::GenerateInitInstance(_ncData const*)' /tmp/cca1zjzc.o: In function_ncData::_ncData()’:
mycode.c:(.text._ZN7_ncDataC1Ev[_ncData::_ncData()]+0x12): undefined reference to vtable for _ncData' /tmp/cca1zjzc.o: In functionTBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)’:
mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference to `typeinfo for _ncData’
collect2: ld returned 1 exit status

Attempting to add a constructor and destructor
(I have been reading C++ books trying to find the correct
syntax) [ by uncommening my attempt in mycode.h ] gives this:

g++ -Wall -o 1 -I. -lnetcdf root-config --libs mycode.c

/tmp/ccqq6i1a.o: In function __static_initialization_and_destruction_0(int, int)': mycode.c:(.text+0x311): undefined reference toROOT::GenerateInitInstance(_Dimensions const*)’
mycode.c:(.text+0x33a): undefined reference to ROOT::GenerateInitInstance(_Attributes const*)' mycode.c:(.text+0x363): undefined reference toROOT::GenerateInitInstance(_Variables const*)’
mycode.c:(.text+0x38c): undefined reference to ROOT::GenerateInitInstance(_ncData const*)' /tmp/ccqq6i1a.o: In functionmain’:
mycode.c:(.text+0x2cf3): undefined reference to _ncData::_ncData()' /tmp/ccqq6i1a.o: In functionTBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)’:
mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference to `typeinfo for _ncData’
collect2: ld returned 1 exit status

So attempting to use rootcint to make a dictionary to perhaps avoid that
I get this output:

rootcint -v4 -f myout.cxx -p mycode.h

Limitation: Reference member not supported. Please use pointer /opt/cern/root/include/TGenericClassInfo.h:46:

This DOES produce myout.cxx, please see attached.
Attempting to compile it results in this error:

g++ -Wall -c -I/opt/cern/root/include myout.cxx

In file included from myout.cxx:26:
/opt/cern/root/include/RtypesImp.h:16:2: error: #error RtypesImp.h should only be included by ROOT dictionaries.

I do not understand what this means. Since I am adapting Jason Cristy’s code, not writing this myself,
I thought that the original program made four structs, now classes,
Struct type Struct name pointer to previous


_Dimensions DimensionsS DimensionsP
_Attributes AttributesS AttributesP
_Variables VariablesS VariablesP
_ncData ncDataS ncDataP
and that the * was a pointer to the S structs (now classes).

I had errors before with rootcint not understanding netcdf.h contents that refer to making a Windows DLL.
I edited that file, but with these errors, the original standard netcdf.h is working.

So the rootcint “Please use pointer /opt/cern/root/include/TGenericClassInfo.h:46”
seems to require a pointer that I do not understand. Line 46 is:
const type_info &fInfo;

Using this LinkDef.h
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class _Dimensions;
#pragma link C++ class _Attributes;
#pragma link C++ class _Variables;
#pragma link C++ class _ncData;
produces the same error:

rootcint -v4 -f newout.cxx -p mycode.h LinkDef.h

Limitation: Reference member not supported. Please use pointer /opt/cern/root/include/TGenericClassInfo.h:46:

How do I correct these mistakes? From reading the 5.16 manual, I think it is related to
information around page 171: Streamers and references.
Thank you.
trun.nc.gz (5.07 KB)
myout.cxx (759 Bytes)
mycode.h (5.37 KB)
mycode.c (38.4 KB)

I changed almost all of the memory allocations from C calloc to C++ new. I had hoped that using new for memory allocation
would allow ROOT to understand my classes. I understand I need to make sure that delete[]
is called when appropriate; and not now correct. But using new (and thus an actual
constructor) doesn’t seem to correct my rootcint problems.

The constructor is now what I think it must be to correctly create a class. But the destructor
I am confused about. This compiles and runs, but trying to put ‘delete’ in front of each
class member (as I saw in a C++ book) resulted in errors or warnings.

When including ClassDef and ClassImp macros, I get the following :
Commenting those eight lines results in the program compiling and running.

$ g++ -Wall -o 8 -I. -lnetcdf root-config --libs mycode.c
/tmp/ccqhCsWI.o: In function __static_initialization_and_destruction_0(int, int)': mycode.c:(.text+0x311): undefined reference toROOT::GenerateInitInstance(_Dimensions const*)’
mycode.c:(.text+0x33a): undefined reference to ROOT::GenerateInitInstance(_Attributes const*)' mycode.c:(.text+0x363): undefined reference toROOT::GenerateInitInstance(_Variables const*)’
mycode.c:(.text+0x38c): undefined reference to ROOT::GenerateInitInstance(_ncData const*)' /tmp/ccqhCsWI.o: In function_ncData::_ncData()’:
mycode.c:(.text._ZN7_ncDataC1Ev[_ncData::_ncData()]+0x12): undefined reference to vtable for _ncData' /tmp/ccqhCsWI.o: In function_Variables::_Variables()’:
mycode.c:(.text._ZN10_VariablesC1Ev[_Variables::_Variables()]+0x12): undefined reference to vtable for _Variables' /tmp/ccqhCsWI.o: In function_Attributes::_Attributes()’:
mycode.c:(.text._ZN11_AttributesC1Ev[_Attributes::_Attributes()]+0x12): undefined reference to vtable for _Attributes' /tmp/ccqhCsWI.o: In function_Dimensions::_Dimensions()’:
mycode.c:(.text._ZN11_DimensionsC1Ev[_Dimensions::_Dimensions()]+0x12): undefined reference to vtable for _Dimensions' /tmp/ccqhCsWI.o: In functionTBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)’:
mycode.c:(.text._ZN5TTree6BranchI7_ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<_ncData>(char const*, char const*, _ncData**, int, int)]+0x14): undefined reference to `typeinfo for _ncData’
collect2: ld returned 1 exit status
mycode.h (7.57 KB)
mycode.c (41.9 KB)

I realized that calling ClassDef and ClassImp would be greatly simpified
if I used the three structs as written and only had the last one as a class.
I’m still trying to get it to compile with out the ‘typedef’ keyword.

I thought I had this working, with only the rootcint error of not placing a ref into the stream. But I didn’t.
010110.mycode.h (5.81 KB)
010110.mycode.c (41 KB)

Hi,

you don’t need to put ClassDef in there. You can keep the structs.

I realize that you have been trying this for a long time now - it’s probably easiest if you could post (maybe as private email) all files needed for the definitions, i.e. all the original netcdf header files and a list of classes that you want to be able to store in a ROOT file.

Cheers, Axel.

This weekend I spent a lot of time on this, and discovered that somewhere I had broken it working with out the ROOT additions. So I think that I have corrected those problems.

Today I backtracked to using four structs and it works, including me being able to print the opened file name.

I am now confused as to where the data in the file is.

data->variable->some_name did not work, but
std::cout << data->infile << std::endl; does.

I am going to try using the ancio library as it was written to see if I can then get the data from the file. If so, then I tell you what struct/class I need. It seems now that the data is placed in the _Variable struct.

Today I moved, I think, the rest of the memory allocations to new/delete.

So I will need to do some work before I post again. And I do try to not post my rookie mistakes.

Again, thanks for you help.

After a year I am working on this again.

I still do not understand how to get the struct into the Ttree. By reading the manual I think that a class does it automatically.

So I have the adapted code:

typedef class _ncData : public TObject
{

public:

/* Stats. */
int fid, ndims, nvars, ngatts, unlimited;

/* Dimensions. */
DimensionsP *dimensions;

/* Global attributes. */
AttributesP *globals;

/* Variables. */
VariablesP *variables;

/* File names. */
char *infile, *outfile;

/* Flags for reading. */
int isopen, getattvalues, getvardata;

/* Flags for writing. */
int mode;

/* Flag to sort data. */
int sort;

/* Time flag. */
int time_flag;

// ClassDef(_ncData, 1);

} ncDataS, *ncDataP;

This produces the typedef either Class [or struct ] _ncData, with an object *ncDataP being used in all of the function definitions (eg. int ncx_read(ncDataP);
int ncx_getdimensions(ncDataP);
int ncx_getdimension(ncDataP,DimensionsP);
int ncx_getglobals(ncDataP);
)

When I uncomment ClassDef(_ncData, 1); I get the error that *ncDataP isn’t known. When I replace _ncData with *ncDataP, it is not defined yet. When placed after the creation of the object, it is out of the class definition.

When I name the class ncDataP it produces errors that it isn’t a pointer. I can not find a lot of information on pointing to a C++ class. Also, then the function prototypes are thought to be casts.

I have again corrected the code so that it compiles and starts to create a Ttree.

How do I refer ClassDef() to an object of the class? Also, where do I place ClassImp? The linkdef.h never works, due to the netCDF header file making undefined referrences to a Windows DLL.

Some day I hope to be able to put a netCDF file’s contents into a Ttree.

Hi,

This code is very C-ish. Try the following:[code]class _ncData : public TObject
{

public:
/* Stats. */
int fid, ndims, nvars, ngatts, unlimited;

/* Dimensions. */
DimensionsP *dimensions;

/* Global attributes. */
AttributesP *globals;

/* Variables. */
VariablesP *variables;

/* File names. */
char *infile, *outfile;

/* Flags for reading. */
int isopen, getattvalues, getvardata;

/* Flags for writing. */
int mode;

/* Flag to sort data. */
int sort;

/* Time flag. */
int time_flag;

ClassDef(ncData, 1);
};

typedef ncData *ncDataP;[/code]Also you must compile this code (and generate a dictionary for it. If the content is in ncData.h, just do .L ncData.h+ on the ROOT command line.

Cheers,
Philippe

Thanks for the help. It did not work but I’m closer than ever before.

Due to Axel’s question I began trying to find the data from the netCDF file in the
struct (or class) and could not. That is because I have over edited the ancio
source and broken it. Retreating to an earlier edit that allows for g++ compilation
with only warnings, I have discovered how to print the data from the struct.

Reading the manual, I discovered from the Event example that, even though _Dimensions,
_Attributes, and _Variables do NOT inherit from TObject, I must include as the last
line of their structs “ClassDef(name, 1);”.

After doing that, and putting ClassImp(name); for all four at the top of the .cxx file
I receive the following error:

g++ -Wall -O2 -o 1 -lnetcdf -lm root-config --libs newcode.cxx
In file included from /opt/cern/root/include/TObject.h:31,
from newcode.h:37,
from newcode.cxx:19:
/opt/cern/root/include/Rtypes.h:35:67: error: snprintf.h: No such file or directory
/opt/cern/root/include/Rtypes.h:36:68: error: strlcpy.h: No such file or directory
newcode.h:79: warning: ‘struct _Dimensions’ has virtual functions but non-virtual destructor
newcode.h:107: warning: ‘struct _Attributes’ has virtual functions but non-virtual destructor
newcode.h:143: warning: ‘struct _Variables’ has virtual functions but non-virtual destructor

I read the top of the Rtypes.h file and see that stdio.h and string.h files are to include
snprintf.h and strlcpy.h, respectively. I do not have them on my Fedora 8 with default
gcc compiler. I compiled ROOT 5.28.00 last night and now get this error, I had been using
5.26.00. This warning comes from #include “/opt/cern/root/include/TObject.h”, not from
trying to inherit from TObject. Before all ROOT warnings were from trying to use
ClassDef() and ClassImp(), commenting them would allow for error free compilation.

I now have the four structs included in LinkDef.h
#ifdef CINT
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class _ncData+;
#pragma link C++ struct _Dimensions+;
#pragma link C++ struct _Attributes+;
#pragma link C++ struct _Variables+;
//#pragma link C++ defined_in newcode.h;
#endif

And get the error
$ rootcint -f G_nc.cxx -p newcode.h LinkDef.h
Limitation: Reference member not supported. Please use pointer /opt/cern/root/include/TGenericClassInfo.h:46:
Does this mean using & somewhere rather than a *? If so, I don’t know what to do to fix it.

I now think that I can edit the code so that all ncDataP are converted to * _ncData. That would put a pointer to the struct in the functions, allow for them to be in the class (?) and make sure that ROOT does not have problems finding the typeinfo and giving that warning? I thought of this last night trying to fall asleep and didn’t have time to check it.

Now I either need to find a fix for the h files not found or return to ROOT 5.26.

Thanks for your help. I’m learning.

[code][quote]I read the top of the Rtypes.h file and see that stdio.h and string.h files are to include
snprintf.h and strlcpy.h, respectively. I do not have them on my Fedora 8 with default
gcc compiler.[/quote]With a proper installation of ROOT v5.28 they should be in the same
directory as TObject.h (i.e. /opt/cern/root/include/).

do NOT inherit from TObject, I must include as the last
line of their structs “ClassDef(name, 1);”.[/code]If your class do not inherit from TObject, you do no have to use ClassDef … however using ClassDef introduce better performance.

Cheers,
Philippe.

I thought I had this understood but now a set back: I discovered that a typedef in
C++ can not have a constructor. Thus, when I thought I had overedited the file, if
I use ncx_DataCALLOC to open the file (as provied in the ancio library as written)
I can then read the data. I had been using _ncData *data = new _ncData. That can
not work.

The following are the macros in the header file, I do not understand how to remove
them.

#ifndef CALLOC
#define CALLOC(n, t) (t *)calloc(n, sizeof(t))
#endif

#ifndef MALLOC
#define MALLOC(n, t) (t *)malloc(n * sizeof(t))
#endif

#ifndef REALLOC
#define REALLOC(p, n, t) (t*) realloc(p, (n) * sizeof(t))
#endif

#ifndef ncx_DataCALLOC
#define ncx_DataCALLOC(DATA)
if( ( DATA = MALLOC(1, ncDataS)) \ /* this is the only use of
== (ncDataP)NULL ) \ ncDataS in the whole code */
memory_fail(FILE,LINE);
init_ncdata(DATA)
#endif

I tried to rewrite this as ncx_DataCALLOC(DATA) init_ncdata(DATA) but it didn’t
work. I thought that the ncDataS and ncDataP usage just tried to see if there was a
struct in memory.

This is the ancio help descriptions of ncx_DataCALLOC and the ncx_read functions.

  • ncx_DataCALLOC(ncDataP): This call will allocate data for the
    structure and initialize the members of the struct. It
    will return the address of the allocated struct. If
    there was an error allocating memory, the program will
    exit with a status of EXIT_FAILURE.

  • int ncx_read(ncDataP): This procedure will read in the entire
    netCDF file populating the supplied struct with all
    dimension, attribute and variable information. A return
    value of EXIT_SUCCESS/EXIT_FAILURE is returned
    indicating whether the procedure was successful or not.

And a sample code fragment on how to use them.

int main()
{
   int success;
   ncDataP data;

       ncx_DataCALLOC(data);

       ncx_setFilename(data, "input.cdf", 1);
       ncx_setFilename(data, "input.cdf", 0);  //this is for output

       if ( ncx_read(data) == EXIT_FAILURE ) {
            free_ncdata(data);
            return EXIT_FAILURE;
       }

This is what I have used to open the the sample netCDF data file that I have and
have been able to output the Total Ion Current data, by adding code at the bottom.

Since the whole program is written using:
typedef struct _ncData
{definition
} ncDataS,*ncDataP;

I thought that I could avoid the typedef, which prevents using a
constructor for the class or struct and prevents ROOT from understanding a
dictionary for the class or struct by using _ncData and *_ncData directly
and prefacing all of the function declarations [eg. ncx_read(ncDataP)] with
ncx_read(class *_ncData) but that results in multiple warnings.

I read that “struct _ncData” or “class _ncData” should work. Putting the function
protypes in the class declarations doesn’t work either.

Is there a way in C++ to declare a Class and to then use that Class in functions?

I know this isn’t exactly a ROOT question, but I can not get ROOT to put the Class
into a Ttree until I can avoid typedefs that ROOT can not understand.

I have thought of opening the struct as written, then trying to put that struct
into a C++ Class, which I could open with new and a constructor and with out
typedef. But I asked in a C++ forum how to copy a C struct to a C++ Class and
received the answer to read a C++ book. I’ve read parts of all available C++ books
and can not find my answers.

Eventually ancio opens the netCDF file with
int ncx_read(ncDataP data)
{
int status;

    /* Error check.
     ****************/
    if(data == (ncDataP)NULL)
    {
            printf("\nNull argument passed to ncx_read.\n");

            /* Return failure. */
            return EXIT_FAILURE;

So that the data are placed in ‘data’ which is a pointer to ncData. Trying to move
that to( *_ncData data) doesn’t work even when I try in main to create data. I’m lost.

typedef struct _ncData {definition } ncDataS,*ncDataP; The C++ way of writing this is: struct _ncData { ... }; typedef _ncData ncDataS; typedef _ncData *ncDataP;I am a bit confused on which part you can change and which part you can not change.

[quote]I discovered that a typedef in C++ can not have a constructor.[/quote]More exactly, whether or not you can use a constructor depends not on whether the entity is a typedef or not but on the target of the typedef. For example with the code above all of this is valid:_nData a(...); ncDataS b(...); ncDataP pointer1 = new _nData(...); ncDataP pointer2 = new ncDataS(...);

Cheers,
Philippe.

Hi,

Are ncx_setFilename and ncx_setFilename function you can/will change? If you can not change it then what you need is a struct that is declared to be a C style struct by doing: extern "C" { struct ncDataS { definition }; }

Cheers,
Philippe.

Dr. Canal:

Thank you for the help.
I returned to a year old highly edited version of ancio, in which I had tried to move all (but some string things I do not understand) memory allocation to new. I had begun to wonder if the lack of variable data in the struct (or class) ncData was due to some being >300,000 and I needed long.

It was that, having removed the ncx_dataCALLOC thing, I needed to put ncx_init, to initialize the struct. I could never get a constructor to do that.

I can now, see attached code and data file, open the file, read and print the Total Intensity data. But still no
TTree. I have commented out the ROOT stuff to see that the program works before trying to put the data into a Ttree.

By removing the comments and having the compiler see the ROOT includes, : public TObject, ClassImp, ClassDef, and the Ttree code in main I can print the data, print the variable type and the variable name.

Then the message
"Error in TTree::Bronch : Cannot find class::ncData.

I removed the _ to simplify typing.

How do I get ROOT to see the class? Is that a missing include file?

I compiled on Fedora 8 default g++ using
g++ -Wall -o 16 -lnetcdf root-config --libs mycode.c

netcdf is the netCDF library. A Fedora rpm is available but I compiled 3.6.3 myself.
trun.nc.gz (5.07 KB)
mycode.h.gz (1.57 KB)
mycode.c.gz (7.43 KB)

I just realized that I forgot to try to create a dictionary for ncData.
Last night rootcint -f G__.cxx -c -p mycode.h LinkDef.h actually produced with out an error the cxx file.
I compiled it
g++ -c -I/opt/cern/root/include G__.cxx and then with the .o file
g++ -shared -Wl -o G__.so G__.o

Then with mycode.cxx
g++ -Wall -o file -lnetcdf -L/my/path/G__.so root-config --libs mycode.cxx

Is that correct? How do I use the dictionary in a stand alone c++ program?

Again, thank you for your help.

Hi,

You are missing the dictionary for your user classes, see root.cern.ch/drupal/faq#n676
This would also explain difficulties in using ClassDef which requires the class to have a dictionary in order to successfully link.

Cheers,
Philippe.

Hello:

I retried all of this again this afternoon, to make sure last night I hadn’t forgotten something. I can make the dictionary, but as long as ClassDef and ClassImp are in the code, I get a Vtable and typedef error and compilation ends. When I comment them, I can compile, print the data, and then get the Tbronch warning.

I thought I had this finally and when I create the dictionary and compile it
and then link with mycode.c I get this:

$ g++ -Wall -lnetcdf -o 17 root-config --libs -L/home/dbrunk/editdesktop/G__.so mycode.c
/tmp/ccUK17CE.o: In function ncData::ncData()': mycode.c:(.text._ZN6ncDataC1Ev[ncData::ncData()]+0x12): undefined reference tovtable for ncData’
/tmp/ccUK17CE.o: In function TBranch* TTree::Branch<ncData>(char const*, char const*, ncData**, int, int)': mycode.c:(.text._ZN5TTree6BranchI6ncDataEEP7TBranchPKcS5_PPT_ii[TBranch* TTree::Branch<ncData>(char const*, char const*, ncData**, int, int)]+0x14): undefined reference totypeinfo for ncData’
collect2: ld returned 1 exit status

This looks like a constructor problem again. I read that writing constructors is
different for a class that inherits from another class, in this case TObject.
How am I to include inheritance from TObject in creating a constructor? I saw that
it should be something like
ncData::ncData() : TObject() but I have yet to get a non-default constructor or work.

This is my LinkDef.h

#ifdef CINT

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class ncData+;
#pragma link C++ struct _Attributes+;
#pragma link C++ struct _Variables+;
#pragma link C++ defined_in mycode.h;

#endif

I HAVE to find a way to NOT use typedef, apparently, so that I can link with ROOT
and have the class recognised.

I have tried using
ncx_read(class *ncData data) in place of typedef ncData *ncDataP and it will not work.
I have found many references to “typedef class [or struct] somethingptr” is to avoid
typing “class [or struct] somethingptr”. But when I put create *ncDataP with out a
typedef declaration, the function prototypes are errors. Typing class in front of ncDataP
in all of them results in
g++ -Wall -o 17 -lnetcdf root-config --libs mycode.c
mycode.c: In function ‘int ncx_read(ncDataP)’:
mycode.c:34: error: ‘data’ has incomplete type
mycode.h:235: error: forward declaration of ‘struct ncDataP’
mycode.c: In function ‘int ncx_read(ncDataP)’:
mycode.c:40: error: expected `)’ before ‘__null’
mycode.c: In function ‘int ncx_getdimensions(ncDataP)’:
mycode.c:133: error: ‘data’ has incomplete type
mycode.h:235: error: forward declaration of ‘struct ncDataP’
mycode.c: At global scope: . . .

Including the ‘struct ncDataP’ warning when ncDataP is from the class ncData! I do not
understand.
Line 133 of mycode.c is
int ncx_getdimensions( class ncDataP data)
so I figured that including class in the function declarations AND in the functions in
the code would work, it clearly doesn’t.

Here is an edited view of the function prototypes:
end of class ncData
} *ncDataP;

/*

  • Prototypes.
    ***************/

int ncx_read(class ncDataP data);
int ncx_getdimensions(class ncDataP data);
int ncx_getdimension( (class ncDataP data), DimensionsP dim);
int ncx_getglobals( class ncDataP data);
int ncx_getattributes( class ncDataP data ,VariablesP var);
int ncx_getattribute( class ncDataP data ,AttributesP att,VariablesP var);

I have tried moving the function prototypes into the class definition but it does
not work.

I keep trying to search the internet for
"use C++ class in function" but can not find what I need. How in C++ does one use
a class in the function?

How do I eliminate using a typedef, and still have the functions point to the
class? I can not find an example of what to do. From what I read, it should be
ncx_func(class *ncData) but that doesn’t work.

If I can discover the workaround to typedef ncData *ncDataP, I think I can finally do this.

[quote]but as long as ClassDef and ClassImp are in the code, I get a Vtable and typedef error and compilation ends[/quote]This means that you do not successfully build, compile and link in the dictionary.

[quote]I HAVE to find a way to NOT use typedef, apparently, so that I can link with ROOT
and have the class recognised.[/quote]That is not the problem … it is an issue with the link line …

[quote]I have tried using
ncx_read(class *ncData data) in place of typedef ncData *ncDataP and it will not work[/quote]and will not work but ncx_read(ncData *data)should work fine.

Philippe.

Dr. Canal:

THANK YOU!

I will head home and try this. I forgot the -l -L thing: so much to learn when you aren’t a programmer.

Again, thank you.