Message: Pitfall in materials building Not Logged In (login)
 Next-in-Thread Next-in-Thread
 Next-in-Forum Next-in-Forum

Warning Pitfall in materials building 

Forum: Fast Simulation, Transportation & Others
Date: 22 Jan, 2010
From: Wm. Heintzelman <Wm. Heintzelman>

The design of the class G4NistMaterialBuilder makes it possible for
a Geant user to unknowingly introduce an error in materials building.

A list of pointers to the materials that have already been built
is maintained in class 'G4Material' as 'static G4MaterialTable
theMaterialTable;'.  As materials are built, pointers to them are
added to this table.  When NIST materials are built, they are added
to the table by 'G4NistMaterialBuilder::FindOrBuildMaterial()',
and the index of the NIST material's entry in 'theMaterialTable'
is saved in class 'G4NistMaterialBuilder' in a private array
'std::vector<G4int> matIndex;'.  In subsequent calls to
'G4NistMaterialBuilder::FindOrBuildMaterial' for a NIST material
that has already been built, the routine does not search in the name
array associated with 'theMaterialTable' to determine the index to
use to obtain the pointer to the material from 'theMaterialTable',
but simply uses the index that was previously saved in 'matIndex'.

If the user wants to build a list of materials, some of which have
components that are in the same list, a reasonable design is to
proceed through the list, attempt to build each material in turn,
and if a component is encountered that has not yet been built, to
return later for a another attempt at building the material after
the whole list has been processed.

Suppose the user's BuildMaterial routine begins to build a material
(for clarity, let's call that the target material), and creates
a new instance of the material class for the target and adds its
pointer to 'theMaterialTable'.  It then attempts to add all the
specified constituent materials to the target's definition.
However, if a constituent is encountered that has not yet been built,
it removes the target from 'theMaterialTable' and puts it on a list
for later reconsideration.

Now suppose that several materials A, B, and C have already been
built, and the remaining materials to be built are D, E, and X.
Further suppose D has a NIST constituent, N, and the non-NIST
constituent, X.  The 'G4Material' instance for D is created and
the pointer to D is added to 'theMaterialTable'; N is then built by
'G4NistMaterialBuilder::FindOrBuildMaterial' and added to the table,
which now has pointers to  (A B C D N); the value of 'matIndex' for
material N is set to the value 4, and N is added to the definition
of D.  But in continuing the building of D, X is encountered next.
Because X has not yet been built, building of D is aborted, its
'G4Material' instance is deleted, and its pointer is removed from
the table.  D is placed on the list for later re-consideration.
The table now has pointers to (A B C N).  E is built next,
followed by X, and finally D is built on the  second attempt, so
the table now contains (A B C N E X D), in that order.  However,
when 'G4NistMaterialBuilder::FindOrBuildMaterial' was called for
constituent material N during the second attempt at building D,
because N had previously been built, 'FindOrBuildMaterial' accessed
'matIndex' to retrieve the pointer to N from 'theMaterialTable'.
The index value, however, had not been changed after N was built
and still had the value 4; consequently the pointer used for N in
building material D actually pointed to material E, and material D
was built incorrectly, and its physical properties used in subsequent
calculations will be incorrect.

To avoid problems of this sort, I recommend that 'matIndex' in
'G4NistMaterialBuilder::FindOrBuildMaterial' should not
be used to save the index to the pointer of a built NIST material.
Instead, the material's name should be used to search the list of 
built materials and determine the index value at the time it is 
needed.

Below is output from "diff" comparing the standard 4.9.2 versions of 
G4NistMaterialBuilder.hh and G4NistMaterialBuilder.cc with changed 
versions that eliminate this pitfall.

---------------------------------------------------------------

G4NistMaterialBuilder.hh :
187c187
<   std::vector<G4int>     matIndex;
---
>   std::vector<G4bool>    builtFlag;

---------------------------------------------------------------

G4NistMaterialBuilder.cc :
101d100
<
104,111c103,107
<
<       // Build new Nist material
<       if(matIndex[i] == -1) mat = BuildMaterial(i, isotopes);
<       // Nist material was already built
<       else                  mat = (*theMaterialTable)[matIndex[i]];
<
<       return mat;
<
---
>         // Build Nist material if it hasn't already been built
>         if(~builtFlag[i]) {
>             mat = BuildMaterial(i, isotopes);
>             return mat;
>         }
115c111
<   // Check the list of all materials
---
>   // Check the list of materials already built
190c186
<   matIndex[i] = mat->GetIndex();
---
>   builtFlag[i] = true;
328c324
<   matIndex[idx] = mat->GetIndex();
---
>   builtFlag[idx] = true;
452c448
<   matIndex.push_back(-1);
---
>   builtFlag.push_back(false);

---------------------------------------------------------------

Note: This problem was found when using Geant 4.9.2.

 Add Message Add Message
to: "Pitfall in materials building"

 Subscribe Subscribe

This site runs SLAC HyperNews version 1.11-slac-98, derived from the original HyperNews


[ Geant 4 Home | Geant 4 HyperNews | Search | Request New Forum | Feedback ]