GMP, MPFR and TTree branches

Hello,

I am having a lot of issues creating TTrees with hi-precision quantities like the ones provided by gmp.h and mpfr.h.

So, long story short, using doubles resulted in errors in my calculations, so I had to create hi-precision objects (type mpfr_t) using the mpfr.h library. The computations are then carried out successfully, but then I am unable to create a TTree with mpfr_t objects.

I admit that I have a lot of confusion on the topic. I wrote a short program trying to accomplish what I’m trying to do:

# include <iostream>
# include "TRandom3.h"
# include "TFile.h"
# include "TTree.h"

# include <gmp.h>     // hi-precision library
# include <mpfr.h>

using namespace std;

void GenerateMPFR(mpfr_t *in);

void test_mpfr(){
  mpfr_t testvar;

  mpfr_init(testvar);

  TFile *fout = new TFile("output.root","recreate");
  TTree *tout = new TTree("tout","Tree out");

  tout->Branch("branch_mpfr", &testvar);

  for(int i=0;i<10;++i){
    GenerateMPFR(&testvar);
    tout->Fill();
  }

  tout->Write();
  fout->Close();
  mpfr_clear(testvar);
  mpfr_free_cache();
}

void GenerateMPFR(mpfr_t *in){
  TRandom3 *r = new TRandom3(0);
  mpfr_set_d(*in, r->Uniform(), MPFR_RNDN);
}

#ifndef __CINT__

int main(int argc, char **argv) {
  if ( argc == 1 ) {
    std::cout << "\n==========> test_mpfr <=============" << std::endl;
    test_mpfr();
  }
  else {
    cout << "Usage:" << endl;
    cout << "./test_mpfr.cc.exe" << endl;
    return 0;
  }

  std::cout << "==> Application finished." << std::endl;

  return 0;
}
#endif /* __CINT __ */

The program gets successfully compiled with the following call to the compiler:

g++ -std=c++11 test_mpfr.cc -o test_mpfr.cc.exe `root-config --libs --cflags` -lMinuit -lmpfr -lgmp -lgmpxx

But when I run the program, I get the following message:

Error in <TTree::Branch>: The pointer specified for branch_mpfr is not of a class or type known to ROOT

And here’s when I start to be confused. Reading online I learned that I have to create a dictionary telling ROOT what to do with the object that I’m trying to pass as branch element. The first thing that I tried to do, then, was to create the shared objects for gmp.h and mpfr.h with:

root[0] .L /path-to-library/gmp.h+
root[1] .L /path-to-library/mpfr.h+

obtaining “.so files", ".d files”, and “*_ACLiC_dict_rdict.pcm” (naively, I’d say that these last files are the dictionary for the library). I would then load these files into my program with the lines:

gSystem->Load("gmp_h.so");
gSystem->Load("mpfr_h.so");

but this doesn’t solve my problem.

Further research showed me that I might have to use a LinkDef.h file, but I am totally clueless on what #pragma code to add, how to implement it, if to #include it in my code, if converting it to a .so file and loading it with gSystem->Load, I even found a reference to roocling to create an additional *.cxx file, but again, I don’t know what to do with the resulting file.

Please help. I’m not asking to straight solve my problem, but at least to point me to some useful resource that I can use to solve my issue.
Thank you.


ROOT Version: 6.12/06
Platform: Linux Mint 18.3
Compiler: g++ 5.4.0


// mpfr_LinkDef.h
#ifdef __ROOTCLING__
#pragma link C++ class mpfr_t+;
#endif

then

rootcling -f mpfr_dict.cxx -c mpfr.h mprf_LinkDef.h

then compiled mpft_dict.cxx and include it in a shared library.

Cheers,
Philippe.

Hello Philippe, thank you for your reply.

I followed your instructions, modified my LinkDef.h as per your suggestion and created the .cxx dictionary via

rootcling -f mpfr_dict.cxx -c /usr/local/include/mpfr.h LinkDef.h

This gave me, as output, the following message:

Warning: Unused class rule: mpfr_t

Anyway, I then compiled the produced .cxx and created a .so object via

g++ -std=c++11 -fPIC -c mpfr_dict.cxx  `root-config --libs --cflags` -lMinuit -lmpfr -lgmp -lgmpxx

g++ -shared -o lib_mpfr.so mpfr_dict.o

finally including it in my program with

gSystem->Load("lib_mpfr.so");

I finally recompiled my code and ran it.
The output, however, was again the same,

Error in <TTree::Branch>: The pointer specified for branch_mpfr is not of a class or type known to ROOT

Did I do anything incorrectly?

not really but

Warning: Unused class rule: mpfr_t

for your purpose is fatal …

Indeed mpft_t (on the version I have access to) is an odd typedef:

typedef __mpfr_struct mpfr_t[1];

so try with

#pragma link C++ class __mpfr_struct+;

but then again:

typedef struct {
  mpfr_prec_t  _mpfr_prec;
  mpfr_sign_t  _mpfr_sign;
  mpfr_exp_t   _mpfr_exp;
  mp_limb_t   *_mpfr_d;
} __mpfr_struct;

and then

/usr/include/gmp-x86_64.h:typedef unsigned int          mp_limb_t;

so __mpfr_struct::_mpfr_d is a pointer to an ‘unsigned int’ which could be pointing to a memory location of one or more integer and so far there is not enough information for ROOT to know how many ints to store.

You would need to figure out what this size is and then we could devise a solution.

Chees,
Philippe.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.