// PosGen_Fill.cc // Contact person:Matthew Mottram // See PosGen_Fill.hh for more details //———————————————————————// #include #include #include #include #include #include #include #include #include #include #include using std::string; using std::vector; namespace RAT { void PosGen_Fill::SetState(G4String newValues) { newValues = trim(newValues); if(newValues.length() == 0)// Empty arg, print help { fStates.push_back(" "); debug << "Current state of this PosGen_Fill:\n\"" << GetState() << "\"\n"; detail << "Format of argument to PosGen_Fill::SetState:" << endl << " \n\"x y z\" with all inputs in [mm], a point in a volume," " or \"name\", the name of a volume." << endl; Log::Die("Please set correctly parameters for the PosGen_Fill "+GetState()); return; } else { fStates.push_back(newValues); fListValid = false; debug << "Current state of this PosGen_Fill:\n\"" << GetState() << " \"\n"; } } G4String PosGen_Fill::GetState() const { std::stringstream result; for(vector::const_iterator it = fStates.begin(); it != fStates.end(); ++it) result << (*it) << " "; return result.str(); } void PosGen_Fill::GeneratePosition(G4ThreeVector& argResult) { // Check if must regenerate list if(!fListValid) { fVolumes.Clear(); fTotalVolume = 0.0; for(unsigned int i = 0; i < fStates.size(); i++) fVolumes.AddString(fStates[i], VolumeList::SELF); for(unsigned int i = 0; i < fVolumes.Size(); i++) fTotalVolume += fVolumes.ComputeVolume(fVolumes.GetVolume(i)); fListValid = true; } // Now can generate a point, first choose the volume const double trialVolume = G4UniformRand() * fTotalVolume; int iVolume = -1; //iVolume incremented each time through, including first for(double cumulativeVolume = 0; trialVolume > cumulativeVolume;) { ++iVolume; cumulativeVolume += fVolumes.ComputeVolume(fVolumes.GetVolume(iVolume)); } // Grab only 1 navigator // it can be shared over all instances since RAT does not run in parallel static G4Navigator* fNavigator = G4TransportationManager::GetTransportationManager()->GetNavigatorForTracking(); // calculate the size of the volume double volsize= fVolumes.ComputeVolume(fVolumes.GetVolume(iVolume)); #ifdef RAT_DEBUG_GENFILL info << "PosGen_Fill::GeneratePosition : Sampling volume : " << fVolumes.GetVolume(iVolume)->GetName() << newline; #endif // Extract the solid G4VSolid* solid = fVolumes.GetVolume(iVolume)->GetLogicalVolume()->GetSolid(); // Now calculate the bounding box, in local coordinates (to solid) and its size double x0, y0, z0, x1, y1, z1, extSize; G4VoxelLimits voxelLimits; // Defaults to "infinite" limits. G4AffineTransform affineTransform; // Defaults to no transform solid->CalculateExtent(kXAxis, voxelLimits, affineTransform, x0,x1); solid->CalculateExtent(kYAxis, voxelLimits, affineTransform, y0,y1); solid->CalculateExtent(kZAxis, voxelLimits, affineTransform, z0,z1); //compute the size of extent extSize=(x1-x0)*(y1-y0)*(z1-z0); double sizeRatio = extSize/volsize; unsigned int maxtries = 100000 * (unsigned int)ceil(sizeRatio); unsigned int iTrial; // NFB: Fixed the generator logic that fails for volumes with off-centered daughters // like NCD anchors (daughters of inner_av) // The method is slightly inefficient if the volume to be used is one of the external layers // For example, if we wanted to generate a point in the av, it would build // a bounding box that would also sample points in the inner_av, until it found a point // that actually belonged to the AV. // Now test positions until one is found in the relevant volume for(iTrial = 0; iTrial < maxtries; iTrial++) { // Now the trial local coordinate (to solid) can be generated // If G4UniformRand is called directly in G4ThreeVector constructor this has been shown // to produce different results on Mac and Linux machines, so explicitly declare // the random numbers G4double rand1 = G4UniformRand(); G4double rand2 = G4UniformRand(); G4double rand3 = G4UniformRand(); G4ThreeVector trialPos( x0 + rand1 * (x1 - x0), y0 + rand2 * (y1 - y0), z0 + rand3 * (z1 - z0)); #ifdef RAT_DEBUG_GENFILL info << "PosGen_Fill::GeneratePosition : Local trial position : ( " << trialPos.x() << " , " << trialPos.y() << " , " << trialPos.z() << " )" << newline; #endif // Transform this coordinate into global coordinates fVolumes.GetTransform(iVolume).ApplyPointTransform(trialPos); #ifdef RAT_DEBUG_GENFILL info << "PosGen_Fill::GeneratePosition : Global trial position : ( " << trialPos.x() << " , " << trialPos.y() << " , " << trialPos.z() << " )" << newline; #endif // Check if trialPos is within chosen volume // The logic below was flawed and was modified to correct for bug #1392 // See PosGen_FillExp for details G4VPhysicalVolume *trialVolumePhys = fNavigator->LocateGlobalPointAndSetup(trialPos,NULL,false,true); if (trialVolumePhys == fVolumes.GetVolume(iVolume)) { argResult = trialPos; return; } #ifdef RAT_DEBUG_GENFILL else { warn << "Failed position because of volume [" << trialVolume->GetName() << "] : (" << trialPos.x() << " , " << trialPos.y() << " , " << trialPos.z() << ")" << newline; } #endif } std::string volName = fVolumes.GetVolume(iVolume)->GetName(); Log::Die(dformat("PosGen_Fill::GeneratePosition failed in %d attempts to find position in volume %s ",iTrial, volName.c_str() ) ); } } // namespace RAT