<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

Hi @agheata, thanks again for all the replies. All very useful. I do still have a problem on this vein, that I don’t think the above answers (unless it does). I have a closed geometry that someone else made (and made it a very different way) so I only have the completed closed geometry that I need to import into a new geometry that I’m creating (a la the first program in your last reply). You said that I could use MakePhysicalNode for this–but I am still very unsure how to do that. MakePhysicalNode only works on the volumes “under” the top volume (that’s my understanding). So I imagine that I would have to AddNode the imported geometry to top (let’s say this happens in the first program in your last reply, where new volumes are created) then use MakePhysicalNode on it. It seemed from what you were saying that I cannot just AddNode the imported volumes to the new top volume, but can using MakePhysicalNode remedy that problem?
I tried to open the geometry (the one to be imported) and save its volumes to a root file, where I can then follow the method in your last reply. I ran into problems with this, so I suspect it may not be the right way, and it also seems a little wrong still.
So the question is thus: Can I import the geometry, use AddNode to add the volumes to the new top volume, then use MakePhysicalNode on those volumes and Align them? (Though I imagine I could without errors, but it might still be wrong.) If not, how do you suggest I do this? Since the geometry is already closed, I do not think I can follow the method you suggested in your last reply. (Though I will be able to use the method for a different purpose, so it was still useful!)
Thanks for the help.

Also, I used the MakePhysicalNode method on a geometry (actually the one I’m worrying about importing) to great effect to rotate and translate the volumes. Just a separate thing, but I suspect it will work wonders when rotating and translating the full finish geometry, once I figure out this problem.

MakePhysicalNode actually clones a logical volume (and content) and reconnects the clone to the parent volume. This cannot be done for the top volume. Adding volumes to an already closed geometry is as I explained not correct, since geometry cannot be opened/closed again. You could try to load the old geometry and to save to file the volumes you still want to add to your new geometry, then load them in a separate session and complete the constructions/close.

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