Home | News | Documentation | Download

<TGDMLWrite::CreateCommonBoolN>: ERROR! Left node is NULL - Boolean Shape will be skipped

Hello,

I’m running into an error–I’m working on a ROOT geometry. I have a program that generates a geometry and then a second program that imports the resulting ROOT geometry file and rotates/translates the whole thing (to change the coordinate system). They are both below. I should note that the first program is VERY simplified from what it really is, to make it easier to debug… (So rotating the whole geometry does actually makes sense.)

The first program runs fine (to make the geometry) but when I try to run the second program I get:

Info in <TGDMLWrite::WriteGDMLfile>: Extracting volumes
Info in <TGDMLWrite::CreateCommonBoolN>: ERROR! Left node is NULL - Boolean Shape will be skipped
Info in <TGDMLWrite::ExtractVolumes>: ERROR! bucket volume was not added, because solid is either not supported or corrupted

I suspect the problem may lie in how I create the composite shape (TGeoCompositeShape) in the first program. I use the composite shape to make a TGeoVolume. In my more complicated geometry I get this problem multiple times too, since I make multiple composite shapes. The second program seems to skip adding the bucket volume to the gdml and root files, and when I draw the geometry at the end of the second program all the volumes are shown.


#include <iostream>
using namespace std;
void makeGeom()
{
 gSystem->Load("libGeom");
 new TGeoManager("world", "the geometry");
 ////// define LAr material
 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoElement *Ar = table->FindElement("Argon");
 TGeoMaterial *LAr = new TGeoMaterial("LAr",Ar, 1.3954);
 TGeoMedium *LArMed = new TGeoMedium("LArMed",1, LAr);

 // this creates a volume with a material (medium) and dimensions
 TGeoTube *bucket_i = new TGeoTube("bucket_i", 0.,30.48,60.96/2.0);
 TGeoBBox *cube_cutout = new TGeoBBox("lcco",31.75875/2.0,34.0022/2.0,32.69235/2.0);
 
 TGeoRotation *rCube = new TGeoRotation("rCube",45.0,0.,0.);
 rCube->RegisterYourself();
 TGeoCompositeShape *sbucket = new TGeoCompositeShape("sbucket","bucket_i-(lcco:rCube)");
 TGeoVolume *bucket = new TGeoVolume("bucket",sbucket,LArMed);

 TGeoVolume *outerVolume = gGeoManager->MakeBox("outerVolume",LArMed,
						   1000.,1000.,1000.);
 
 // define top volume
 TGeoVolume *top = outerVolume;
 top->AddNode(bucket,1);
 gGeoManager->SetTopVolume(top);
 gGeoManager->CloseGeometry();
 gGeoManager->SetTopVisible(); // the TOP is invisible
 top->Draw();

 gGeoManager->Export("TestGeom.gdml");
 gGeoManager->Export("TestGeom.root");
}

Second program:


#include <iostream>
using namespace std;

void rotateGeom()
{
 gSystem->Load("libGeom");
 TFile *f = TFile::Open("TestGeom.root");
 TGeoManager *geo = (TGeoManager*)f->Get("world");
 TGeoVolume *SingleCube = geo->GetVolume("outerVolume"); 

 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoMixture *air = new TGeoMixture("air",2,1.29);
 TGeoElement *N = table->FindElement("N");
 TGeoElement *O = table->FindElement("O");
 air->AddElement(N,0.7);
 air->AddElement(O,0.3);
 TGeoMedium *airMed = new TGeoMedium("airMed",1,air);

 double worldx = 2000.;
 double worldy = 2000.;
 double worldz = 2000.;
 TGeoVolume *world = gGeoManager->MakeBox("world",airMed,worldx,worldy,worldz);

 TGeoRotation *coord = new TGeoRotation("coord",180.,90.,45.);
 TGeoCombiTrans *cSingleCube = new TGeoCombiTrans("cSingleCube",0.,0.,14.60,coord); 
 
 // define top volume
 TGeoVolume *top = world;
 gGeoManager->SetTopVolume(top);
 top->AddNode(SingleCube,1,cSingleCube);
 gGeoManager->CloseGeometry();
 //gGeoManager->SetTopVisible(); // the TOP is invisible
 top->Draw();
 
 gGeoManager->Export("testGeomRotated.root");
 gGeoManager->Export("testGeomRotated.gdml");

}

I would greatly appreciate help to solve this problem! If you need anything else from me, feel free to ask.

Thank you,

Sam Fogarty

___

_ROOT Version: 6.12/06
_Platform: linux
_Compiler:_ Not Provided
___

@agheata Is this something you can help with?

Hi Sam,

Unfortunately loading a closed geometry, modifying and closing it again is invalid. You can adopt a different approach called “misalignment”, described here. You can see how this work in action running the tutorial geom/geodemo.C, clicking on Aligned and then Un-aligned button. This however does not work for components of a composite shape. You can try to re-create a composite shape based on the old one, changing the rotation, then provide this shape to the Align method of the corresponding physical node.

Hi @agheata,

Thanks for the response. I do not understand what you mean that you cannot load a closed geometry, modify it, and close it again. This is something I have done with no problems before–where I loaded a closed geometry, rotated it, and then used AddNode to a world volume. But you’re saying this is invalid? In what way? The makeGeom.C program (the more complicated one I haven’t shown here) does that and seems to produce a useable geometry.

Calling CloseGeometry() for a closed geometry is not forbidden, but produces no effect (just returns). However CloseGeometry is needed for several tasks after finalizing the geometry hierarchy, notably geometry checking and optimization of navigation structure. Rotating some volume or adding new nodes will not be therefore correctly taken into account. It depends what you do with the geometry after, visualization may work if you play with it in this way, but navigation definitely not.
I now realized that you are trying to rotate the content of the world volume, and not a component of the composite. The way to do that is to create an intermediate container below the top volume, put all content inside that, Close geometry, then read it back and Align it. Like in:

#include <iostream>
using namespace std;
void makegeom()
{
 gSystem->Load("libGeom");
 new TGeoManager("world", "the geometry");
 ////// define LAr material
 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoElement *Ar = table->FindElement("Argon");
 TGeoMaterial *LAr = new TGeoMaterial("LAr",Ar, 1.3954);
 TGeoMedium *LArMed = new TGeoMedium("LArMed",1, LAr);

 // this creates a volume with a material (medium) and dimensions
 TGeoTube *bucket_i = new TGeoTube("bucket_i", 0.,30.48,60.96/2.0);
 TGeoBBox *cube_cutout = new TGeoBBox("lcco",31.75875/2.0,34.0022/2.0,32.69235/2.0);
 
 TGeoRotation *rCube = new TGeoRotation("rCube",45.0,0.,0.);
 rCube->RegisterYourself();
 TGeoCompositeShape *sbucket = new TGeoCompositeShape("sbucket","bucket_i-(lcco:rCube)");
 TGeoVolume *bucket = new TGeoVolume("bucket",sbucket,LArMed);

 TGeoVolume *outerVolume = gGeoManager->MakeBox("outerVolume",LArMed,
               1000.,1000.,1000.);
 outerVolume->AddNode(bucket,1);
 
 // define top volume
 TGeoVolume *top = gGeoManager->MakeBox("top",LArMed,
               2000.,2000.,2000.);
 top->AddNode(outerVolume,1);
 gGeoManager->SetTopVolume(top);
 gGeoManager->CloseGeometry();
 //gGeoManager->SetTopVisible(); // the TOP is invisible
 top->Draw();

 gGeoManager->Export("TestGeom.gdml");
 gGeoManager->Export("TestGeom.root");
}

and then:

#include <iostream>
using namespace std;

void rotateGeom()
{
 gSystem->Load("libGeom");
 TFile *f = TFile::Open("TestGeom.root");
 TGeoManager *geo = (TGeoManager*)f->Get("world");

 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoMixture *air = new TGeoMixture("air",2,1.29);
 TGeoElement *N = table->FindElement("N");
 TGeoElement *O = table->FindElement("O");
 air->AddElement(N,0.7);
 air->AddElement(O,0.3);
 TGeoMedium *airMed = new TGeoMedium("airMed",1,air);

 TGeoRotation *coord = new TGeoRotation("coord",180.,90.,45.);
 TGeoCombiTrans *cSingleCube = new TGeoCombiTrans("cSingleCube",0.,0.,14.60,coord); 

 // You can only align physical nodes below the top level
 auto node = gGeoManager->MakePhysicalNode("/top_1/outerVolume_1");
 node->Align(cSingleCube); // You could even change the shape of outerVolume here

 //gGeoManager->SetTopVisible(); // the TOP is invisible
 gGeoManager->GetTopVolume()->Draw();
 
 gGeoManager->Export("testGeomRotated.root");
 gGeoManager->Export("testGeomRotated.gdml");

}

I still don’t understand why after writing once your geometry and reading it back, writing it again gives the CompositeShape error (even if you do not rotate the geometry. Looking into that.

I think this may work for my problem. But I have another question. There is a geometry that I’m importing, and it has many subvolumes in it. So I do something like this (using the definition of airMed above):

 gSystem->Load("libGeom");
 new TGeoManager("world", "the geometry");
 TFile *f = TFile::Open("SingleCube.root");
 TGeoManager *geo = (TGeoManager*)f->Get("Default");
 TGeoVolume *LArCube = geo->GetTopVolume();
 TGeoVolume *top = gGeoManager->MakeBox("top",airMed,2000.,2000.,2000.);
 top->AddNode(LArCube,1);
 gGeoManager->SetTopVolume(top);
 gGeoManager->CloseGeometry();

But you’re saying that I can’t do this (right?). Should I still use MakePhysicalNode like above or something else? I’m confused if I can-- or how I would-- since I can’t change how the SingleCube.root geometry is made, unlike the makeGeom.C example above. And I’m adding that geometry to my new one. How should I go about this?

Thanks again.

No, you cannot do this (copy a volume from one geometry and put it into another) but you can use indeed MakePhysicalVolume. Rotating a physical volume will rotate all its content. You can even rotate separately volumes represented by the same logical volume. If you have several physical volumes that you need to move separately, you have to create multiple physical volumes to handle this.

Okay, so how about this:

gSystem->Load("libGeom");
 TFile *f = TFile::Open("SingleCube.root");
 TGeoManager *geo = (TGeoManager*)f->Get("Default");
 TGeoVolume *LArCube = geo->GetTopVolume();

TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoMixture *air = new TGeoMixture("air",2,1.29);
 TGeoElement *N = table->FindElement("N");
 TGeoElement *O = table->FindElement("O");
 air->AddElement(N,0.7);
 air->AddElement(O,0.3);
 TGeoMedium *airMed = new TGeoMedium("airMed",1,air);

 TGeoVolume *top = gGeoManager->MakeBox("top",airMed,2000.,2000.,2000.);
TGeoRotation *coord = new TGeoRotation("coord",180.,90.,45.);
 TGeoCombiTrans *cSingleCube = new TGeoCombiTrans("cSingleCube",0.,0.,14.60,coord); 

 top->AddNode(LArCube,1);
 // then add more volumes I make here
 gGeoManager->SetTopVolume(top);
 auto node = gGeoManager->MakePhysicalNode("/top_1/volSingleCube_1");
 node->Align(cSingleCube); 

 gGeoManager->CloseGeometry();
 gGeoManager->Export("testGeom.root");
 gGeoManager->Export("testGeom.gdml");

I sense that this may have problems, based on what you have said. If so, what do you suggest I change? Do I still need to AddNode the imported volume, or is that something I need to abandon? I don’t know how to MakePhysicalNode for the imported geometry without doing something like

TGeoManager *geo = (TGeoManager*)f->Get("Default");
TGeoVolume *LArCube = geo->GetTopVolume();

Which resets the TGeoManager. Is there a way to get a volume from a TFile without resetting the TGeoManager? I’m not sure if that is the path forward.

OK Sam, if you need to move volumes in a separate session and possibly add new volumes, you can do the following: just write just the volumes you want to move/keep in the geometry file, instead of exporting the full geometry, as in:

#include <iostream>
using namespace std;
void makegeom()
{
 gSystem->Load("libGeom");
 new TGeoManager("world", "the geometry");
 ////// define LAr material
 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoElement *Ar = table->FindElement("Argon");
 TGeoMaterial *LAr = new TGeoMaterial("LAr",Ar, 1.3954);
 TGeoMedium *LArMed = new TGeoMedium("LArMed",1, LAr);

 // this creates a volume with a material (medium) and dimensions
 TGeoTube *bucket_i = new TGeoTube("bucket_i", 0.,30.48,60.96/2.0);
 TGeoBBox *cube_cutout = new TGeoBBox("lcco",31.75875/2.0,34.0022/2.0,32.69235/2.0);
 
 TGeoRotation *rCube = new TGeoRotation("rCube",45.0,0.,0.);
 rCube->RegisterYourself();
 TGeoCompositeShape *sbucket = new TGeoCompositeShape("sbucket","bucket_i-(lcco:rCube)");
 TGeoVolume *bucket = new TGeoVolume("bucket",sbucket,LArMed);

 TGeoVolume *outerVolume = gGeoManager->MakeBox("outerVolume",LArMed,
               1000.,1000.,1000.);
 outerVolume->AddNode(bucket,1);
 
 double worldx = 2000.;
 double worldy = 2000.;
 double worldz = 2000.;
 TGeoVolume *world = gGeoManager->MakeBox("world",LArMed,worldx,worldy,worldz);
 world->AddNode(outerVolume, 1);
 gGeoManager->SetTopVolume(world);
 gGeoManager->CloseGeometry();
 world->Draw();

 TFile::Open("outerVolume.root", "RECREATE");
 outerVolume->Write(); // You can write also other volumes to the same file - this writes also the daughter volumes
}

Then you read the unplaced volumes from the file in a separate session, and treat them as if they were already fully defined (including their children volumes connected in the hierarchy) and add them as nodes, with the transformations you want, as in:

#include <iostream>
using namespace std;

void rotateGeom()
{
 gSystem->Load("libGeom");
 TGeoManager *geom = new TGeoManager("geom", "");
 // Import the volume from file and register it to the geomety
 TFile *f = TFile::Open("outerVolume.root");
 TGeoVolume *outerVolume = (TGeoVolume*)f->Get("outerVolume");
 geom->AddVolume(outerVolume);

 TGeoElementTable *table = gGeoManager->GetElementTable();
 TGeoMixture *air = new TGeoMixture("air",2,1.29);
 TGeoElement *N = table->FindElement("N");
 TGeoElement *O = table->FindElement("O");
 air->AddElement(N,0.7);
 air->AddElement(O,0.3);
 TGeoMedium *airMed = new TGeoMedium("airMed",1,air);

 TGeoRotation *coord = new TGeoRotation("coord",180.,90.,45.);
 TGeoCombiTrans *cSingleCube = new TGeoCombiTrans("cSingleCube",0.,0.,14.60,coord); 

 double worldx = 2000.;
 double worldy = 2000.;
 double worldz = 2000.;
 TGeoVolume *world = geom->MakeBox("world",airMed,worldx,worldy,worldz);
 geom->SetTopVolume(world);
 world->AddNode(outerVolume,1,cSingleCube);
 geom->CloseGeometry();
 //gGeoManager->SetTopVisible(); // the TOP is invisible


 //gGeoManager->SetTopVisible(); // the TOP is invisible
 world->Draw();
 
 geom->Export("testGeomRotated.root");
 geom->Export("testGeomRotated.gdml");

}

Note that you should set the top volume and CloseGeometry() in the second session, since this is not already done (as before when you loaded the full geometry)
Hope this helps