Import Geant4 11.3.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2024-06-28 13:08:51 +02:00
parent f7b23877ed
commit e58e650b32
5232 changed files with 239416 additions and 244360 deletions
@@ -30,8 +30,6 @@
#include "G4ErrorTarget.hh"
G4ErrorTarget::G4ErrorTarget() {}
G4double G4ErrorTarget::GetDistanceFromPoint( const G4ThreeVector&,
const G4ThreeVector& ) const
{
@@ -26,19 +26,17 @@
// Class G4GeometryManager implementation
//
// 26.07.95, P.Kent - Initial version, including optimisation build
// 12.06.24, J.Apostolakis - Added parallel optimisation in workers
// --------------------------------------------------------------------
#include <iomanip>
#include "G4ios.hh"
#include "G4Timer.hh"
#include "G4GeometryManager.hh"
#include "G4SystemOfUnits.hh"
#include "G4Threading.hh"
#ifdef G4GEOMETRY_VOXELDEBUG
#include "G4ios.hh"
#endif
// Needed for building optimisations
//
#include "G4LogicalVolumeStore.hh"
@@ -52,6 +50,27 @@
#include "G4SolidStore.hh"
#include "G4VSolid.hh"
// Needed for parallel optimisation
#include "G4AutoLock.hh"
namespace // Data structures / mutexes for parallel optimisation
{
// Mutex to obtain a volume to optimise
G4Mutex obtainVolumeMutex = G4MUTEX_INITIALIZER;
// Mutex to lock saving of voxel statistics
G4Mutex voxelStatsMutex = G4MUTEX_INITIALIZER;
// Mutex to provide Statistics Results
G4Mutex statResultsMutex = G4MUTEX_INITIALIZER;
// Mutex to start wall clock (global) timer
G4Mutex wallClockTimerMutex = G4MUTEX_INITIALIZER;
// Mutex to write debug output
G4Mutex outputDbgMutex = G4MUTEX_INITIALIZER;
}
// ***************************************************************************
// Static class data
// ***************************************************************************
@@ -59,6 +78,33 @@
G4ThreadLocal G4GeometryManager* G4GeometryManager::fgInstance = nullptr;
G4ThreadLocal G4bool G4GeometryManager::fIsClosed = false;
// Static *global* class data
G4bool G4GeometryManager::fParallelVoxelOptimisationRequested = true;
// Records User choice - to use parallel voxel optimisation (or not)
G4bool G4GeometryManager::fOptimizeInParallelConfigured = false;
// Configured = requested && available (ie if MT or Threads is used)
// Value calculated during each effort to optimise
std::vector<G4LogicalVolume*> G4GeometryManager::fVolumesToOptimize;
std::vector<G4LogicalVolume*>::iterator G4GeometryManager::fLogVolumeIterator;
std::vector<G4SmartVoxelStat> G4GeometryManager::fGlobVoxelStats;
// Container for statistics
// Derived state
G4bool G4GeometryManager::fVerboseParallel = false;
G4bool G4GeometryManager::fParallelVoxelOptimisationUnderway = false;
G4bool G4GeometryManager::fParallelVoxelOptimisationFinished = false;
G4double G4GeometryManager::fSumVoxelTime = 0.0;
G4int G4GeometryManager::fNumberThreadsReporting = 0;
unsigned int G4GeometryManager::fTotalNumberVolumesOptimized = 0U;
// For Wall clock
G4Timer* G4GeometryManager::fWallClockTimer = nullptr;
G4bool G4GeometryManager::fWallClockStarted = false;
// ***************************************************************************
// Destructor
// ***************************************************************************
@@ -67,6 +113,12 @@ G4GeometryManager::~G4GeometryManager()
{
fgInstance = nullptr;
fIsClosed = false;
if( fWallClockTimer && G4Threading::IsMasterThread() )
{
delete fWallClockTimer;
fWallClockTimer= nullptr;
}
}
// ***************************************************************************
@@ -135,6 +187,11 @@ G4GeometryManager* G4GeometryManager::GetInstance()
if (fgInstance == nullptr)
{
fgInstance = new G4GeometryManager;
if( (fWallClockTimer == nullptr) && G4Threading::IsMasterThread() )
{
fWallClockTimer = new G4Timer;
}
}
return fgInstance;
}
@@ -148,133 +205,599 @@ G4GeometryManager* G4GeometryManager::GetInstanceIfExist()
return fgInstance;
}
// ***************************************************************************
// Simplest user method to request parallel optimisation.
// ***************************************************************************
//
void G4GeometryManager::OptimizeInParallel( G4bool val )
{
RequestParallelOptimisation(val);
}
// ***************************************************************************
// Report about Voxel(isation) of a logical volume.
// ***************************************************************************
//
void
G4GeometryManager::ReportVoxelInfo(G4LogicalVolume* logVolume, std::ostream& os)
{
G4SmartVoxelHeader* head = logVolume->GetVoxelHeader();
if( head != nullptr )
{
os << "** Created optimisations for logical-volume '"
<< std::setw(50) << logVolume->GetName() << "'" << G4endl
<< "- Result VoxelInfo - START: " << " ptr= " << head << G4endl
<< *head
<< "- Result VoxelInfo - END. " << G4endl;
}
else
{
os << "** No optimisation for log-vol " << logVolume->GetName() << G4endl;
}
os << "*** Report Voxel Info: END " << G4endl;
}
// ***************************************************************************
// Creates optimisation info. Builds all voxels if allOpts=true
// otherwise it builds voxels only for replicated volumes.
// ***************************************************************************
// Returns whether optimisation is finished
//
void G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose)
G4bool G4GeometryManager::BuildOptimisations(G4bool allOpts, G4bool verbose)
{
G4Timer timer;
G4Timer allTimer;
std::vector<G4SmartVoxelStat> stats;
if (verbose) { allTimer.Start(); }
G4bool finishedOptimisation = false;
fOptimizeInParallelConfigured = fParallelVoxelOptimisationRequested
&& G4Threading::IsMultithreadedApplication();
G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance();
G4LogicalVolume* volume;
G4SmartVoxelHeader* head;
for (auto & n : *Store)
{
if (verbose) timer.Start();
volume=n;
// For safety, check if there are any existing voxels and
// delete before replacement
//
head = volume->GetVoxelHeader();
delete head;
volume->SetVoxelHeader(nullptr);
if ( ( (volume->IsToOptimise())
&& (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
|| ( (volume->GetNoDaughters()==1)
static unsigned int NumCallsBuildOptimisations = 0; // WORKAROUND - TODO fix
if( fOptimizeInParallelConfigured && (NumCallsBuildOptimisations==0) )
{
PrepareParallelOptimisation(allOpts, verbose);
NumCallsBuildOptimisations++;
}
else
{
BuildOptimisationsSequential(allOpts, verbose);
finishedOptimisation= true;
}
return finishedOptimisation;
}
// ***************************************************************************
// Creates optimisation info. Builds all voxels if allOpts=true
// otherwise it builds voxels only for replicated volumes.
//
// This is the original sequential implementation of this method; was called
// - at first initialisation to create voxels,
// - at re-initialisation if the geometry has changed.
// ***************************************************************************
//
void G4GeometryManager::BuildOptimisationsSequential(G4bool allOpts,
G4bool verbose)
{
G4Timer timer;
G4Timer allTimer;
std::vector<G4SmartVoxelStat> stats;
if (verbose) { allTimer.Start(); }
G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance();
G4LogicalVolume* volume;
G4SmartVoxelHeader* head;
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << G4endl
<< "*** G4GeometryManager::BuildOptimisationsSequential() called on tid "
<< G4Threading::G4GetThreadId() << " all-opts= " << allOpts << G4endl;
#endif
for (auto & n : *Store)
{
if (verbose) timer.Start();
volume=n;
// For safety, check if there are any existing voxels and
// delete before replacement
//
head = volume->GetVoxelHeader();
delete head;
volume->SetVoxelHeader(nullptr);
if ( ( (volume->IsToOptimise())
&& (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
|| ( (volume->GetNoDaughters()==1)
&& (volume->GetDaughter(0)->IsReplicated())
&& (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) )
{
&& (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) )
{
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
<< " Examining logical volume name = "
<< volume->GetName() << G4endl;
G4cout << "** G4GeometryManager::BuildOptimisationsSequential()"
<< " Examining logical volume name = '" << volume->GetName()
<< "' #daughters= " << volume->GetNoDaughters() << G4endl;
#endif
head = new G4SmartVoxelHeader(volume);
if (head != nullptr)
{
volume->SetVoxelHeader(head);
}
else
{
std::ostringstream message;
message << "VoxelHeader allocation error." << G4endl
<< "Allocation of new VoxelHeader" << G4endl
<< " for volume " << volume->GetName() << " failed.";
G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
FatalException, message);
}
if (verbose)
{
timer.Stop();
stats.emplace_back( volume, head,
timer.GetSystemElapsed(),
timer.GetUserElapsed() );
}
}
else
{
// Don't create voxels for this node
head = new G4SmartVoxelHeader(volume);
if (head != nullptr)
{
volume->SetVoxelHeader(head);
}
else
{
std::ostringstream message;
message << "VoxelHeader allocation error." << G4endl
<< "Allocation of new VoxelHeader" << G4endl
<< " for volume '" << volume->GetName() << "' failed.";
G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
FatalException, message);
}
if (verbose)
{
timer.Stop();
stats.emplace_back( volume, head,
timer.GetSystemElapsed(),
timer.GetUserElapsed() );
}
}
else
{
// Don't create voxels for this node
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
<< " Skipping logical volume name = " << volume->GetName()
<< G4endl;
auto numDaughters = volume->GetNoDaughters();
G4cout << "- Skipping logical volume with " << numDaughters
<< " daughters and name = '" << volume->GetName() << "' " << G4endl;
if( numDaughters > 1 )
{
G4cout << "[Placement]";
}
else
{
if( numDaughters == 1 )
{
G4cout << ( volume->GetDaughter(0)->IsReplicated() ? "[Replicated]"
: "[Placement]" );
}
}
G4cout << G4endl;
#endif
}
}
}
if (verbose)
{
allTimer.Stop();
ReportVoxelStats( stats, allTimer.GetSystemElapsed()
+ allTimer.GetUserElapsed() );
allTimer.Stop();
ReportVoxelStats( stats, allTimer.GetSystemElapsed()
+ allTimer.GetUserElapsed() );
}
}
// ***************************************************************************
// Creates optimisation info for the specified volumes subtree.
// Creates a list of logical volumes which will be optimised
// if allOpts=true it lists all voxels
// otherwise it lists only the voxels of replicated volumes.
// This list will be used subsequently to build their voxels.
//
// Note: this method is NOT thread safe!
// It expects to be called only once in each (re)initalisation
// i.e. either by master thread or a selected thread.
// ***************************************************************************
//
void
G4GeometryManager::CreateListOfVolumesToOptimise(G4bool allOpts, G4bool verbose)
{
// Prepare the work - must be called only in one thread !!
G4LogicalVolumeStore* Store = G4LogicalVolumeStore::GetInstance();
if( fVolumesToOptimize.size() > 0)
{
ResetListOfVolumesToOptimise();
}
for (auto & n : *Store)
{
G4LogicalVolume* volume=n;
if ( ( (volume->IsToOptimise())
&& (volume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
|| ( (volume->GetNoDaughters()==1)
&& (volume->GetDaughter(0)->IsReplicated())
&& (volume->GetDaughter(0)->GetRegularStructureId()!=1) ) )
{
fVolumesToOptimize.push_back(volume);
// For safety, must check (later) if there are any existing voxels and
// delete before replacement:
// All 'clients' of this code must do the following:
// delete volume->GetVoxelHeader();
// volume->SetVoxelHeader(nullptr);
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << "- Booking logical volume with " << volume->GetNoDaughters()
<< " daughters and name = '" << volume->GetName() << "' "
<< " -- for optimization (ie voxels will be built for it). " << G4endl;
#endif
}
else
{
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << "- Skipping logical volume with " << volume->GetNoDaughters()
<< " daughters and name = '" << volume->GetName() << "' " << G4endl;
#endif
}
}
if(verbose)
G4cout << "** G4GeometryManager::PrepareOptimisationWork: "
<< " Number of volumes for voxelisation = "
<< fVolumesToOptimize.size() << G4endl;
fLogVolumeIterator = fVolumesToOptimize.begin();
}
// ***************************************************************************
// Obtain a logical volume from the list of volumes to optimise
// Must be thread-safe: its role is to be called in parallel by threads/tasks!
// Critical method for parallel optimisation - must be correct and fast.
// ***************************************************************************
//
G4LogicalVolume* G4GeometryManager::ObtainVolumeToOptimize()
{
G4LogicalVolume* logVolume = nullptr;
G4AutoLock lock(obtainVolumeMutex);
if( fLogVolumeIterator != fVolumesToOptimize.end() )
{
logVolume = *fLogVolumeIterator;
++fLogVolumeIterator;
}
return logVolume;
}
// ***************************************************************************
// Thread-safe method to clear the list of volumes to Optimise.
// ***************************************************************************
//
void G4GeometryManager::ResetListOfVolumesToOptimise()
{
G4AutoLock lock(obtainVolumeMutex);
std::vector<G4LogicalVolume*>().swap(fVolumesToOptimize);
// Swapping with an empty vector in order to empty it
// without calling destructors of logical volumes.
// Must not call clear: i.e. fVolumesToOptimize.clear();
assert(fVolumesToOptimize.empty());
fLogVolumeIterator = fVolumesToOptimize.begin();
fGlobVoxelStats.clear();
// Reset also the statistics of volumes -- to avoid double recording.
}
// ***************************************************************************
// Method which user calls to ask for parallel optimisation (or turn it off).
// ***************************************************************************
//
void G4GeometryManager::RequestParallelOptimisation(G4bool flag, G4bool verbose)
{
fParallelVoxelOptimisationRequested = flag;
if( flag )
{
ConfigureParallelOptimisation(verbose);
}
}
// ***************************************************************************
// Setup up state to enable parallel optimisation by workers.
// ***************************************************************************
//
void G4GeometryManager::ConfigureParallelOptimisation(G4bool verbose)
{
if(verbose)
{
G4cout << "** G4GeometryManager::ConfigureParallelOptimisation() called. "
<< " LEAVING all the work (of voxel optimisation) to the threads/tasks !"
<< G4endl;
}
fParallelVoxelOptimisationRequested = true;
fParallelVoxelOptimisationUnderway = false;
fParallelVoxelOptimisationFinished = false;
// Keep values of options / verbosity for use in threads
fVerboseParallel = verbose;
// New effort -- reset the total time -- and number of threads reporting
fSumVoxelTime = 0.0;
fNumberThreadsReporting = 0;
fTotalNumberVolumesOptimized = 0; // Number of volumes done
fWallClockStarted = false; // Will need to restart it!
}
// ***************************************************************************
// Build voxel optimisation in parallel -- prepare the work for threads/tasks
// ***************************************************************************
//
void
G4GeometryManager::PrepareParallelOptimisation(G4bool allOpts, G4bool verbose)
{
if( verbose )
{
G4cout << "** G4GeometryManager::PrepareParallelOptimisation() called."
<< G4endl;
}
CreateListOfVolumesToOptimise(allOpts, verbose);
ConfigureParallelOptimisation(verbose);
}
// ***************************************************************************
// Method for a thread/task to contribute dynamically to Optimisation
// ***************************************************************************
//
void G4GeometryManager::UndertakeOptimisation()
{
G4bool verbose = fVerboseParallel;
G4LogicalVolume* logVolume = nullptr;
fParallelVoxelOptimisationUnderway = true;
// Start timer - if not already done
if( ( !fWallClockStarted ) && verbose )
{
G4AutoLock startTimeLock(wallClockTimerMutex);
if( !fWallClockStarted )
{
fWallClockTimer->Start();
fWallClockStarted= true;
}
}
G4Timer fetimer;
unsigned int numVolumesOptimized = 0;
while( (logVolume = ObtainVolumeToOptimize()) != nullptr )
{
if (verbose) fetimer.Start();
G4SmartVoxelHeader* head = logVolume->GetVoxelHeader();
delete head;
logVolume->SetVoxelHeader(nullptr);
head = new G4SmartVoxelHeader(logVolume);
// *********************************
logVolume->SetVoxelHeader(head);
if (head != nullptr)
{
++numVolumesOptimized;
}
else
{
G4ExceptionDescription message;
message << "VoxelHeader allocation error." << G4endl
<< "Allocation of new VoxelHeader" << G4endl
<< " for logical volume " << logVolume->GetName()
<< " failed.";
G4Exception("G4GeometryManager::BuildOptimisationsParallel()",
"GeomMgt0003", FatalException, message);
}
if(verbose)
{
fetimer.Stop();
auto feRealElapsed = fetimer.GetRealElapsed();
// Must use 'real' elapsed time -- cannot trust user/system time
// (it accounts for all threads)
G4AutoLock lock(voxelStatsMutex);
fGlobVoxelStats.emplace_back( logVolume, head,
0.0, // Cannot estimate system time
feRealElapsed ); // Use real time instead of user time
fSumVoxelTime += feRealElapsed;
}
}
G4bool allDone = false;
G4int myCount= -1;
myCount = ReportWorkerIsDoneOptimising(numVolumesOptimized);
allDone = IsParallelOptimisationFinished();
if( (allDone && myCount) == G4Threading::GetNumberOfRunningWorkerThreads() )
{
G4int badVolumes = CheckOptimisation(); // Check all voxels are created!
if( badVolumes > 0 )
{
G4ExceptionDescription errmsg;
errmsg <<" Expected that all voxelisation work is done, "
<< "but found that voxels headers are missing in "
<< badVolumes << " volumes.";
G4Exception("G4GeometryManager::UndertakeOptimisation",
"GeomMng002",FatalException, errmsg);
}
// Create report
if( verbose )
{
fWallClockTimer->Stop();
std::ostream& report_stream = std::cout; // G4cout; does not work!
report_stream << G4endl
<< " G4GeometryManager::UndertakeOptimisation()"
<< " - Timing for Voxel Optimisation" << G4endl;
report_stream << " - Elapsed time (real) = " << std::setprecision(4)
<< fWallClockTimer->GetRealElapsed() << " seconds (wall clock) "
<< " , user " << fWallClockTimer->GetUserElapsed() << "seconds "
<< " , system " << fWallClockTimer->GetSystemElapsed() << " seconds."
<< G4endl;
report_stream << " - Sum voxel time (real) = " << fSumVoxelTime
<< " seconds.";
report_stream << std::setprecision(6) << G4endl << G4endl;
ReportVoxelStats( fGlobVoxelStats, fSumVoxelTime, report_stream );
report_stream.flush();
}
}
else
{
WaitForVoxelisationFinish(false);
}
}
// ***************************************************************************
// Ensure that all the work of voxelisation is done.
// Can be called in GeometryManager methods or externally.
// ***************************************************************************
//
void G4GeometryManager::WaitForVoxelisationFinish(G4bool verbose)
{
// Must wait until all workers are done ...
using namespace std::chrono_literals;
unsigned int trials = 0;
auto tid = G4Threading::G4GetThreadId();
std::ostream& out_stream = std::cout; // G4cout; does not work!
while( ! IsParallelOptimisationFinished() )
{
// Each thread must wait until all are done ...
std::this_thread::sleep_for(250ms);
++trials;
}
if( verbose )
{
G4AutoLock lock(outputDbgMutex);
out_stream << G4endl << "** UndertakeOptimisation done on tid= " << tid
<< " after waiting for " << trials << " trials." << G4endl;
out_stream.flush();
}
}
// ***************************************************************************
// Ensure that all logical volumes in list have a voxel-header.
// ***************************************************************************
//
G4int G4GeometryManager::CheckOptimisation()
{
unsigned int numErrors= 0;
for ( auto logical : fVolumesToOptimize ){
if( logical->GetVoxelHeader() == nullptr ){
std::cerr << "G4GeometryManager::CheckOptimisation: ERROR "
<< " logical volume " << logical->GetName() << " has Voxel Header = " << G4endl;
numErrors++;
}
}
return numErrors;
}
// ***************************************************************************
// Report that current thread/task is done optimising.
// A thread call this method to reports that is is done (finished), and how
// many volumes it optimised. The method:
// - increments the count of workers that have finished, and return it;
// - keeps count of number of volumes optimised;
// - if all works is done (ie all workers have reported) it will result
// in the 'Finished' state.
// ***************************************************************************
//
G4int
G4GeometryManager::ReportWorkerIsDoneOptimising(unsigned int numVolumesOptimized)
{
// Check that all are done and, if so, signal that optimisation is finished
G4int orderReporting;
G4AutoLock lock(statResultsMutex);
orderReporting = ++fNumberThreadsReporting;
fTotalNumberVolumesOptimized += numVolumesOptimized;
if (fNumberThreadsReporting == G4Threading::GetNumberOfRunningWorkerThreads())
{
InformOptimisationIsFinished(fVerboseParallel);
}
return orderReporting;
}
// *****************************************************************************
// Inform that all work for parallel optimisation is finished.
// *****************************************************************************
//
void G4GeometryManager::InformOptimisationIsFinished(G4bool verbose)
{
if(verbose)
{
G4cout << "** G4GeometryManager: All voxel optimisation work is completed!"
<< G4endl;
G4cout << " Total number of volumes optimised = "
<< fTotalNumberVolumesOptimized
<< " of " << fVolumesToOptimize.size() << "expected" << G4endl;
G4cout << " Number of workers reporting = "
<< fNumberThreadsReporting
<< " of " << G4Threading::GetNumberOfRunningWorkerThreads()
<< "expected\n";
}
assert ( fTotalNumberVolumesOptimized == fVolumesToOptimize.size() );
assert ( fNumberThreadsReporting == G4Threading::GetNumberOfRunningWorkerThreads() );
fParallelVoxelOptimisationFinished = true;
// fParallelVoxelOptimisationRequested = false; // Maintain request for next one!
fParallelVoxelOptimisationUnderway = false; // It's no longer underway!
}
// ***************************************************************************
// Creates Optimisation info for the specified volumes subtree.
// ***************************************************************************
//
void G4GeometryManager::BuildOptimisations(G4bool allOpts,
G4VPhysicalVolume* pVolume)
{
if (pVolume == nullptr) { return; }
if (pVolume == nullptr) { return; }
// Retrieve the mother logical volume, if not NULL,
// otherwise apply global optimisation for the world volume
//
G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
if (tVolume == nullptr) { return BuildOptimisations(allOpts, false); }
// Retrieve the mother logical volume, if not NULL,
// otherwise apply global optimisation for the world volume
//
G4LogicalVolume* tVolume = pVolume->GetMotherLogical();
if (tVolume == nullptr)
{
BuildOptimisations(allOpts, false);
return;
}
G4SmartVoxelHeader* head = tVolume->GetVoxelHeader();
delete head;
tVolume->SetVoxelHeader(nullptr);
if ( ( (tVolume->IsToOptimise())
&& (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
|| ( (tVolume->GetNoDaughters()==1)
&& (tVolume->GetDaughter(0)->IsReplicated()) ) )
{
head = new G4SmartVoxelHeader(tVolume);
if (head != nullptr)
{
tVolume->SetVoxelHeader(head);
}
else
{
std::ostringstream message;
message << "VoxelHeader allocation error." << G4endl
<< "Allocation of new VoxelHeader" << G4endl
<< " for volume " << tVolume->GetName() << " failed.";
G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
FatalException, message);
}
}
else
{
// Don't create voxels for this node
G4SmartVoxelHeader* head = tVolume->GetVoxelHeader();
delete head;
tVolume->SetVoxelHeader(nullptr);
if ( ( (tVolume->IsToOptimise())
&& (tVolume->GetNoDaughters()>=kMinVoxelVolumesLevel1&&allOpts) )
|| ( (tVolume->GetNoDaughters()==1)
&& (tVolume->GetDaughter(0)->IsReplicated()) ) )
{
head = new G4SmartVoxelHeader(tVolume);
if (head != nullptr)
{
tVolume->SetVoxelHeader(head);
}
else
{
std::ostringstream message;
message << "VoxelHeader allocation error." << G4endl
<< "Allocation of new VoxelHeader" << G4endl
<< " for volume " << tVolume->GetName() << " failed.";
G4Exception("G4GeometryManager::BuildOptimisations()", "GeomMgt0003",
FatalException, message);
}
}
else
{
// Don't create voxels for this node
#ifdef G4GEOMETRY_VOXELDEBUG
G4cout << "**** G4GeometryManager::BuildOptimisations" << G4endl
<< " Skipping logical volume name = " << tVolume->GetName()
<< G4endl;
G4cout << "** G4GeometryManager::BuildOptimisations()" << G4endl
<< " Skipping logical volume name = " << tVolume->GetName()
<< G4endl;
#endif
}
}
// Scan recursively the associated logical volume tree
//
// Scan recursively the associated logical volume tree
//
tVolume = pVolume->GetLogicalVolume();
if (tVolume->GetNoDaughters() != 0)
{
@@ -284,7 +807,7 @@ void G4GeometryManager::BuildOptimisations(G4bool allOpts,
// ***************************************************************************
// Removes all optimisation info.
// Loops over all logical volumes, deleting non-null voxels pointers,
// Loops over all logical volumes, deleting non-null voxels pointers.
// ***************************************************************************
//
void G4GeometryManager::DeleteOptimisations()
@@ -350,9 +873,10 @@ void G4GeometryManager::SetWorldMaximumExtent(G4double extent)
//
void
G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
G4double totalCpuTime )
G4double totalCpuTime,
std::ostream &os )
{
G4cout << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics"
os << "G4GeometryManager::ReportVoxelStats -- Voxel Statistics"
<< G4endl << G4endl;
//
@@ -363,10 +887,10 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
for( i=0; i<nStat; ++i ) { totalMemory += stats[i].GetMemoryUse(); }
G4cout << " Total memory consumed for geometry optimisation: "
os << " Total memory consumed for geometry optimisation: "
<< totalMemory/1024 << " kByte" << G4endl;
G4cout << " Total CPU time elapsed for geometry optimisation: "
<< std::setprecision(2) << totalCpuTime << " seconds"
os << " Total CPU time elapsed for geometry optimisation: "
<< std::setprecision(4) << totalCpuTime << " seconds"
<< std::setprecision(6) << G4endl;
//
@@ -378,12 +902,13 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
return a.GetTotalTime() > b.GetTotalTime();
} );
G4int nPrint = nStat > 10 ? 10 : nStat;
const G4int maxPrint = 20;
G4int nPrint = std::min ( nStat, maxPrint );
if (nPrint != 0)
{
G4cout << "\n Voxelisation: top CPU users:" << G4endl;
G4cout << " Percent Total CPU System CPU Memory Volume\n"
os << "\n Voxelisation: top CPU users:" << G4endl;
os << " Percent Total CPU System CPU Memory Volume\n"
<< " ------- ---------- ---------- -------- ----------"
<< G4endl;
// 12345678901.234567890123.234567890123.234567890123k .
@@ -401,7 +926,7 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
else
{ perc = total*100/totalCpuTime; }
G4cout << std::setprecision(2)
os << std::setprecision(2)
<< std::setiosflags(std::ios::fixed|std::ios::right)
<< std::setw(11) << perc
<< std::setw(13) << total
@@ -425,8 +950,8 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
if (nPrint != 0)
{
G4cout << "\n Voxelisation: top memory users:" << G4endl;
G4cout << " Percent Memory Heads Nodes Pointers Total CPU Volume\n"
os << "\n Voxelisation: top memory users:" << G4endl;
os << " Percent Memory Heads Nodes Pointers Total CPU Volume\n"
<< " ------- -------- ------ ------ -------- ---------- ----------"
<< G4endl;
// 12345678901.2345678901k .23456789.23456789.2345678901.234567890123. .
@@ -438,7 +963,7 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
G4double totTime = stats[i].GetTotalTime();
if (totTime < 0) { totTime = 0.0; }
G4cout << std::setprecision(2)
os << std::setprecision(2)
<< std::setiosflags(std::ios::fixed|std::ios::right)
<< std::setw(11) << G4double(memory*100)/G4double(totalMemory)
<< std::setw(11) << memory/1024 << "k "
@@ -453,3 +978,21 @@ G4GeometryManager::ReportVoxelStats( std::vector<G4SmartVoxelStat> & stats,
<< G4endl;
}
}
// ***************************************************************************
// Check whether parallel optimisation was requested --static (class) method.
// ***************************************************************************
//
G4bool G4GeometryManager::IsParallelOptimisationConfigured()
{
return fOptimizeInParallelConfigured;
}
// ***************************************************************************
// Report whether parallel optimisation is done -- static (class) method.
// ***************************************************************************
//
G4bool G4GeometryManager::IsParallelOptimisationFinished()
{
return fParallelVoxelOptimisationFinished;
}
@@ -377,6 +377,25 @@ G4ThreeVector G4ReflectedSolid::GetPointOnSurface() const
return (*fDirectTransform3D)*G4Point3D(p);
}
//////////////////////////////////////////////////////////////
//
// Return the number of constituents used for construction
// of the solid
G4int G4ReflectedSolid::GetNumOfConstituents() const
{
return fPtrSolid->GetNumOfConstituents();
}
//////////////////////////////////////////////////////////////
//
// Return true if the reflected solid has only planar faces
G4bool G4ReflectedSolid::IsFaceted() const
{
return fPtrSolid->IsFaceted();
}
//////////////////////////////////////////////////////////////////////////
//
// Make a clone of this object
@@ -386,7 +405,6 @@ G4VSolid* G4ReflectedSolid::Clone() const
return new G4ReflectedSolid(*this);
}
//////////////////////////////////////////////////////////////////////////
//
// Stream object contents to an output stream
@@ -440,29 +440,16 @@ G4SmartVoxelHeader::BuildVoxelsWithinLimits(G4LogicalVolume* pVolume,
// 1. Trying all unlimited cartesian axes
// 2. Select axis which gives greatest no slices
G4ProxyVector *pGoodSlices=nullptr, *pTestSlices, *tmpSlices;
G4ProxyVector *pGoodSlices=nullptr, *pTestSlices;
G4double goodSliceScore=kInfinity, testSliceScore;
EAxis goodSliceAxis = kXAxis;
EAxis testAxis = kXAxis;
std::size_t node, maxNode, iaxis;
std::size_t node, maxNode;
G4VoxelLimits noLimits;
// Try all non-limited cartesian axes
//
for (iaxis=0; iaxis<3; ++iaxis)
for ( EAxis testAxis : { kXAxis, kYAxis, kZAxis } )
{
switch(iaxis)
{
case 0:
testAxis = kXAxis;
break;
case 1:
testAxis = kYAxis;
break;
case 2:
testAxis = kZAxis;
break;
}
if (!pLimits.IsLimited(testAxis))
{
pTestSlices = BuildNodes(pVolume,pLimits,pCandidates,testAxis);
@@ -471,9 +458,7 @@ G4SmartVoxelHeader::BuildVoxelsWithinLimits(G4LogicalVolume* pVolume,
{
goodSliceAxis = testAxis;
goodSliceScore = testSliceScore;
tmpSlices = pGoodSlices;
pGoodSlices = pTestSlices;
pTestSlices = tmpSlices;
std::swap( pGoodSlices, pTestSlices);
}
if (pTestSlices != nullptr)
{
@@ -31,13 +31,6 @@
#include "G4SmartVoxelNode.hh"
// --------------------------------------------------------------------
G4Allocator<G4SmartVoxelNode>*& aNodeAllocator()
{
G4ThreadLocalStatic G4Allocator<G4SmartVoxelNode>* _instance = nullptr;
return _instance;
}
// --------------------------------------------------------------------
// Return true if contents equal
//
@@ -1,38 +0,0 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// Class G4SmartVoxelProxy implementation
//
// 12.07.95, P.Kent - Initial version
// --------------------------------------------------------------------
#include "G4SmartVoxelProxy.hh"
// --------------------------------------------------------------------
G4Allocator<G4SmartVoxelProxy>*& aProxyAllocator()
{
G4ThreadLocalStatic G4Allocator<G4SmartVoxelProxy>* _instance = nullptr;
return _instance;
}
@@ -160,6 +160,21 @@ G4ThreeVector G4VSolid::GetPointOnSurface() const
return {0,0,0};
}
//////////////////////////////////////////////////////////////////////////
//
// Returns total number of constituents that was used for construction
// of the solid. For non-Boolean solids the return value is one.
G4int G4VSolid::GetNumOfConstituents() const
{ return 1; }
//////////////////////////////////////////////////////////////////////////
//
// Returns true if the solid has only planar faces, false otherwise.
G4bool G4VSolid::IsFaceted() const
{ return false; }
//////////////////////////////////////////////////////////////////////////
//
// Dummy implementations ...