Files
geant4/source/processes/optical/src/G4OpBoundaryProcess.cc
T
2020-12-04 12:30:43 +01:00

1457 lines
46 KiB
C++

//
// ********************************************************************
// * 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. *
// ********************************************************************
//
////////////////////////////////////////////////////////////////////////
// Optical Photon Boundary Process Class Implementation
////////////////////////////////////////////////////////////////////////
//
// File: G4OpBoundaryProcess.cc
// Description: Discrete Process -- reflection/refraction at
// optical interfaces
// Version: 1.1
// Created: 1997-06-18
// Modified: 1998-05-25 - Correct parallel component of polarization
// (thanks to: Stefano Magni + Giovanni Pieri)
// 1998-05-28 - NULL Rindex pointer before reuse
// (thanks to: Stefano Magni)
// 1998-06-11 - delete *sint1 in oblique reflection
// (thanks to: Giovanni Pieri)
// 1998-06-19 - move from GetLocalExitNormal() to the new
// method: GetLocalExitNormal(&valid) to get
// the surface normal in all cases
// 1998-11-07 - NULL OpticalSurface pointer before use
// comparison not sharp for: std::abs(cost1) < 1.0
// remove sin1, sin2 in lines 556,567
// (thanks to Stefano Magni)
// 1999-10-10 - Accommodate changes done in DoAbsorption by
// changing logic in DielectricMetal
// 2001-10-18 - avoid Linux (gcc-2.95.2) warning about variables
// might be used uninitialized in this function
// moved E2_perp, E2_parl and E2_total out of 'if'
// 2003-11-27 - Modified line 168-9 to reflect changes made to
// G4OpticalSurface class ( by Fan Lei)
// 2004-02-02 - Set theStatus = Undefined at start of DoIt
// 2005-07-28 - add G4ProcessType to constructor
// 2006-11-04 - add capability of calculating the reflectivity
// off a metal surface by way of a complex index
// of refraction - Thanks to Sehwook Lee and John
// Hauptman (Dept. of Physics - Iowa State Univ.)
// 2009-11-10 - add capability of simulating surface reflections
// with Look-Up-Tables (LUT) containing measured
// optical reflectance for a variety of surface
// treatments - Thanks to Martin Janecek and
// William Moses (Lawrence Berkeley National Lab.)
// 2013-06-01 - add the capability of simulating the transmission
// of a dichronic filter
// 2017-02-24 - add capability of simulating surface reflections
// with Look-Up-Tables (LUT) developed in DAVIS
//
// Author: Peter Gumplinger
// adopted from work by Werner Keil - April 2/96
//
////////////////////////////////////////////////////////////////////////
#include "G4ios.hh"
#include "G4SystemOfUnits.hh"
#include "G4PhysicalConstants.hh"
#include "G4OpProcessSubType.hh"
#include "G4GeometryTolerance.hh"
#include "G4VSensitiveDetector.hh"
#include "G4ParallelWorldProcess.hh"
#include "G4TransportationManager.hh"
#include "G4LogicalBorderSurface.hh"
#include "G4LogicalSkinSurface.hh"
#include "G4OpticalParameters.hh"
#include "G4OpBoundaryProcess.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4OpBoundaryProcess::G4OpBoundaryProcess(const G4String& processName,
G4ProcessType type)
: G4VDiscreteProcess(processName, type)
{
Initialise();
if(verboseLevel > 0)
{
G4cout << GetProcessName() << " is created " << G4endl;
}
SetProcessSubType(fOpBoundary);
theStatus = Undefined;
theModel = glisur;
theFinish = polished;
theReflectivity = 1.;
theEfficiency = 0.;
theTransmittance = 0.;
theSurfaceRoughness = 0.;
prob_sl = 0.;
prob_ss = 0.;
prob_bs = 0.;
fRealRIndexMPV = nullptr;
fImagRIndexMPV = nullptr;
Material1 = nullptr;
Material2 = nullptr;
OpticalSurface = nullptr;
kCarTolerance = G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
iTE = iTM = 0;
thePhotonMomentum = 0.;
Rindex1 = Rindex2 = 1.;
cost1 = cost2 = sint1 = sint2 = 0.;
idx = idy = 0;
DichroicVector = nullptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4OpBoundaryProcess::~G4OpBoundaryProcess() {}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::PreparePhysicsTable(const G4ParticleDefinition&)
{
Initialise();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::Initialise()
{
G4OpticalParameters* params = G4OpticalParameters::Instance();
SetInvokeSD(params->GetBoundaryInvokeSD());
SetVerboseLevel(params->GetBoundaryVerboseLevel());
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VParticleChange* G4OpBoundaryProcess::PostStepDoIt(const G4Track& aTrack,
const G4Step& aStep)
{
theStatus = Undefined;
aParticleChange.Initialize(aTrack);
aParticleChange.ProposeVelocity(aTrack.GetVelocity());
// Get hyperStep from G4ParallelWorldProcess
// NOTE: PostSetpDoIt of this process to be invoked after
// G4ParallelWorldProcess!
const G4Step* pStep = &aStep;
const G4Step* hStep = G4ParallelWorldProcess::GetHyperStep();
if(hStep)
pStep = hStep;
G4bool isOnBoundary =
(pStep->GetPostStepPoint()->GetStepStatus() == fGeomBoundary);
if(isOnBoundary)
{
Material1 = pStep->GetPreStepPoint()->GetMaterial();
Material2 = pStep->GetPostStepPoint()->GetMaterial();
}
else
{
theStatus = NotAtBoundary;
if(verboseLevel > 1)
BoundaryProcessVerbose();
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
G4VPhysicalVolume* thePrePV = pStep->GetPreStepPoint()->GetPhysicalVolume();
G4VPhysicalVolume* thePostPV = pStep->GetPostStepPoint()->GetPhysicalVolume();
if(verboseLevel > 1)
{
G4cout << " Photon at Boundary! " << G4endl;
if(thePrePV)
G4cout << " thePrePV: " << thePrePV->GetName() << G4endl;
if(thePostPV)
G4cout << " thePostPV: " << thePostPV->GetName() << G4endl;
}
if(aTrack.GetStepLength() <= kCarTolerance)
{
theStatus = StepTooSmall;
if(verboseLevel > 1)
BoundaryProcessVerbose();
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle();
thePhotonMomentum = aParticle->GetTotalMomentum();
OldMomentum = aParticle->GetMomentumDirection();
OldPolarization = aParticle->GetPolarization();
if(verboseLevel > 1)
{
G4cout << " Old Momentum Direction: " << OldMomentum << G4endl
<< " Old Polarization: " << OldPolarization << G4endl;
}
G4ThreeVector theGlobalPoint = pStep->GetPostStepPoint()->GetPosition();
G4bool valid;
// ID of Navigator which limits step
G4int hNavId = G4ParallelWorldProcess::GetHypNavigatorID();
auto iNav = G4TransportationManager::GetTransportationManager()
->GetActiveNavigatorsIterator();
theGlobalNormal = (iNav[hNavId])->GetGlobalExitNormal(theGlobalPoint, &valid);
if(valid)
{
theGlobalNormal = -theGlobalNormal;
}
else
{
G4ExceptionDescription ed;
ed << " G4OpBoundaryProcess/PostStepDoIt(): "
<< " The Navigator reports that it returned an invalid normal" << G4endl;
G4Exception(
"G4OpBoundaryProcess::PostStepDoIt", "OpBoun01", EventMustBeAborted, ed,
"Invalid Surface Normal - Geometry must return valid surface normal");
}
if(OldMomentum * theGlobalNormal > 0.0)
{
#ifdef G4OPTICAL_DEBUG
G4ExceptionDescription ed;
ed << " G4OpBoundaryProcess/PostStepDoIt(): theGlobalNormal points in a "
"wrong direction. "
<< G4endl
<< " The momentum of the photon arriving at interface (oldMomentum)"
<< " must exit the volume cross in the step. " << G4endl
<< " So it MUST have dot < 0 with the normal that Exits the new "
"volume (globalNormal)."
<< G4endl << " >> The dot product of oldMomentum and global Normal is "
<< OldMomentum * theGlobalNormal << G4endl
<< " Old Momentum (during step) = " << OldMomentum << G4endl
<< " Global Normal (Exiting New Vol) = " << theGlobalNormal << G4endl
<< G4endl;
G4Exception("G4OpBoundaryProcess::PostStepDoIt", "OpBoun02",
EventMustBeAborted, // Or JustWarning to see if it happens
// repeatedly on one ray
ed,
"Invalid Surface Normal - Geometry must return valid surface "
"normal pointing in the right direction");
#else
theGlobalNormal = -theGlobalNormal;
#endif
}
G4MaterialPropertyVector* RindexMPV = nullptr;
G4MaterialPropertiesTable* MPT = Material1->GetMaterialPropertiesTable();
if(MPT)
{
RindexMPV = MPT->GetProperty(kRINDEX);
}
else
{
theStatus = NoRINDEX;
if(verboseLevel > 1)
BoundaryProcessVerbose();
aParticleChange.ProposeLocalEnergyDeposit(thePhotonMomentum);
aParticleChange.ProposeTrackStatus(fStopAndKill);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
if(RindexMPV)
{
Rindex1 = RindexMPV->Value(thePhotonMomentum, idx_rindex1);
}
else
{
theStatus = NoRINDEX;
if(verboseLevel > 1)
BoundaryProcessVerbose();
aParticleChange.ProposeLocalEnergyDeposit(thePhotonMomentum);
aParticleChange.ProposeTrackStatus(fStopAndKill);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
theReflectivity = 1.;
theEfficiency = 0.;
theTransmittance = 0.;
theSurfaceRoughness = 0.;
theModel = glisur;
theFinish = polished;
G4SurfaceType type = dielectric_dielectric;
RindexMPV = nullptr;
OpticalSurface = nullptr;
G4LogicalSurface* Surface =
G4LogicalBorderSurface::GetSurface(thePrePV, thePostPV);
if(Surface == nullptr)
{
if(thePostPV->GetMotherLogical() == thePrePV->GetLogicalVolume())
{
Surface = G4LogicalSkinSurface::GetSurface(thePostPV->GetLogicalVolume());
if(Surface == nullptr)
{
Surface =
G4LogicalSkinSurface::GetSurface(thePrePV->GetLogicalVolume());
}
}
else
{
Surface = G4LogicalSkinSurface::GetSurface(thePrePV->GetLogicalVolume());
if(Surface == nullptr)
{
Surface =
G4LogicalSkinSurface::GetSurface(thePostPV->GetLogicalVolume());
}
}
}
if(Surface)
{
OpticalSurface =
dynamic_cast<G4OpticalSurface*>(Surface->GetSurfaceProperty());
}
if(OpticalSurface)
{
type = OpticalSurface->GetType();
theModel = OpticalSurface->GetModel();
theFinish = OpticalSurface->GetFinish();
G4MaterialPropertiesTable* sMPT =
OpticalSurface->GetMaterialPropertiesTable();
if(sMPT)
{
if(theFinish == polishedbackpainted || theFinish == groundbackpainted)
{
RindexMPV = sMPT->GetProperty(kRINDEX);
if(RindexMPV)
{
Rindex2 = RindexMPV->Value(thePhotonMomentum, idx_rindex_surface);
}
else
{
theStatus = NoRINDEX;
if(verboseLevel > 1)
BoundaryProcessVerbose();
aParticleChange.ProposeLocalEnergyDeposit(thePhotonMomentum);
aParticleChange.ProposeTrackStatus(fStopAndKill);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
}
fRealRIndexMPV = sMPT->GetProperty(kREALRINDEX);
fImagRIndexMPV = sMPT->GetProperty(kIMAGINARYRINDEX);
iTE = iTM = 1;
G4MaterialPropertyVector* pp;
if((pp = sMPT->GetProperty(kREFLECTIVITY)))
{
theReflectivity = pp->Value(thePhotonMomentum, idx_reflect);
}
else if(fRealRIndexMPV && fImagRIndexMPV)
{
CalculateReflectivity();
}
if((pp = sMPT->GetProperty(kEFFICIENCY)))
{
theEfficiency = pp->Value(thePhotonMomentum, idx_eff);
}
if((pp = sMPT->GetProperty(kTRANSMITTANCE)))
{
theTransmittance = pp->Value(thePhotonMomentum, idx_trans);
}
if(sMPT->ConstPropertyExists(kSURFACEROUGHNESS))
{
theSurfaceRoughness = sMPT->GetConstProperty(kSURFACEROUGHNESS);
}
if(theModel == unified)
{
prob_sl = (pp = sMPT->GetProperty(kSPECULARLOBECONSTANT))
? pp->Value(thePhotonMomentum, idx_lobe)
: 0.;
prob_ss = (pp = sMPT->GetProperty(kSPECULARSPIKECONSTANT))
? pp->Value(thePhotonMomentum, idx_spike)
: 0.;
prob_bs = (pp = sMPT->GetProperty(kBACKSCATTERCONSTANT))
? pp->Value(thePhotonMomentum, idx_back)
: 0.;
}
} // end of if(sMPT)
else if(theFinish == polishedbackpainted || theFinish == groundbackpainted)
{
aParticleChange.ProposeLocalEnergyDeposit(thePhotonMomentum);
aParticleChange.ProposeTrackStatus(fStopAndKill);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
} // end of if(OpticalSurface)
// DIELECTRIC-DIELECTRIC
if(type == dielectric_dielectric)
{
if(theFinish == polished || theFinish == ground)
{
if(Material1 == Material2)
{
theStatus = SameMaterial;
if(verboseLevel > 1)
BoundaryProcessVerbose();
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
MPT = Material2->GetMaterialPropertiesTable();
if(MPT)
{
RindexMPV = MPT->GetProperty(kRINDEX);
}
if(RindexMPV)
{
Rindex2 = RindexMPV->Value(thePhotonMomentum, idx_rindex2);
}
else
{
theStatus = NoRINDEX;
if(verboseLevel > 1)
BoundaryProcessVerbose();
aParticleChange.ProposeLocalEnergyDeposit(thePhotonMomentum);
aParticleChange.ProposeTrackStatus(fStopAndKill);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
}
if(theFinish == polishedbackpainted || theFinish == groundbackpainted)
{
DielectricDielectric();
}
else
{
G4double rand = G4UniformRand();
if(rand > theReflectivity + theTransmittance)
{
DoAbsorption();
}
else if(rand > theReflectivity)
{
theStatus = Transmission;
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
else
{
if(theFinish == polishedfrontpainted)
{
DoReflection();
}
else if(theFinish == groundfrontpainted)
{
theStatus = LambertianReflection;
DoReflection();
}
else
{
DielectricDielectric();
}
}
}
}
else if(type == dielectric_metal)
{
DielectricMetal();
}
else if(type == dielectric_LUT)
{
DielectricLUT();
}
else if(type == dielectric_LUTDAVIS)
{
DielectricLUTDAVIS();
}
else if(type == dielectric_dichroic)
{
DielectricDichroic();
}
else
{
G4ExceptionDescription ed;
ed << " PostStepDoIt(): Illegal boundary type." << G4endl;
G4Exception("G4OpBoundaryProcess", "OpBoun04", JustWarning, ed);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
NewMomentum = NewMomentum.unit();
NewPolarization = NewPolarization.unit();
if(verboseLevel > 1)
{
G4cout << " New Momentum Direction: " << NewMomentum << G4endl
<< " New Polarization: " << NewPolarization << G4endl;
BoundaryProcessVerbose();
}
aParticleChange.ProposeMomentumDirection(NewMomentum);
aParticleChange.ProposePolarization(NewPolarization);
if(theStatus == FresnelRefraction || theStatus == Transmission)
{
G4MaterialPropertyVector* groupvel =
Material2->GetMaterialPropertiesTable()->GetProperty(kGROUPVEL);
if(groupvel)
{
aParticleChange.ProposeVelocity(
groupvel->Value(thePhotonMomentum, idx_groupvel));
}
}
if(theStatus == Detection && fInvokeSD)
InvokeSD(pStep);
return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::BoundaryProcessVerbose() const
{
G4cout << " *** ";
if(theStatus == Undefined)
G4cout << "Undefined";
else if(theStatus == Transmission)
G4cout << "Transmission";
else if(theStatus == FresnelRefraction)
G4cout << "FresnelRefraction";
else if(theStatus == FresnelReflection)
G4cout << "FresnelReflection";
else if(theStatus == TotalInternalReflection)
G4cout << "TotalInternalReflection";
else if(theStatus == LambertianReflection)
G4cout << "LambertianReflection";
else if(theStatus == LobeReflection)
G4cout << "LobeReflection";
else if(theStatus == SpikeReflection)
G4cout << "SpikeReflection";
else if(theStatus == BackScattering)
G4cout << "BackScattering";
else if(theStatus == PolishedLumirrorAirReflection)
G4cout << "PolishedLumirrorAirReflection";
else if(theStatus == PolishedLumirrorGlueReflection)
G4cout << "PolishedLumirrorGlueReflection";
else if(theStatus == PolishedAirReflection)
G4cout << "PolishedAirReflection";
else if(theStatus == PolishedTeflonAirReflection)
G4cout << "PolishedTeflonAirReflection";
else if(theStatus == PolishedTiOAirReflection)
G4cout << "PolishedTiOAirReflection";
else if(theStatus == PolishedTyvekAirReflection)
G4cout << "PolishedTyvekAirReflection";
else if(theStatus == PolishedVM2000AirReflection)
G4cout << "PolishedVM2000AirReflection";
else if(theStatus == PolishedVM2000GlueReflection)
G4cout << "PolishedVM2000GlueReflection";
else if(theStatus == EtchedLumirrorAirReflection)
G4cout << "EtchedLumirrorAirReflection";
else if(theStatus == EtchedLumirrorGlueReflection)
G4cout << "EtchedLumirrorGlueReflection";
else if(theStatus == EtchedAirReflection)
G4cout << "EtchedAirReflection";
else if(theStatus == EtchedTeflonAirReflection)
G4cout << "EtchedTeflonAirReflection";
else if(theStatus == EtchedTiOAirReflection)
G4cout << "EtchedTiOAirReflection";
else if(theStatus == EtchedTyvekAirReflection)
G4cout << "EtchedTyvekAirReflection";
else if(theStatus == EtchedVM2000AirReflection)
G4cout << "EtchedVM2000AirReflection";
else if(theStatus == EtchedVM2000GlueReflection)
G4cout << "EtchedVM2000GlueReflection";
else if(theStatus == GroundLumirrorAirReflection)
G4cout << "GroundLumirrorAirReflection";
else if(theStatus == GroundLumirrorGlueReflection)
G4cout << "GroundLumirrorGlueReflection";
else if(theStatus == GroundAirReflection)
G4cout << "GroundAirReflection";
else if(theStatus == GroundTeflonAirReflection)
G4cout << "GroundTeflonAirReflection";
else if(theStatus == GroundTiOAirReflection)
G4cout << "GroundTiOAirReflection";
else if(theStatus == GroundTyvekAirReflection)
G4cout << "GroundTyvekAirReflection";
else if(theStatus == GroundVM2000AirReflection)
G4cout << "GroundVM2000AirReflection";
else if(theStatus == GroundVM2000GlueReflection)
G4cout << "GroundVM2000GlueReflection";
else if(theStatus == Absorption)
G4cout << "Absorption";
else if(theStatus == Detection)
G4cout << "Detection";
else if(theStatus == NotAtBoundary)
G4cout << "NotAtBoundary";
else if(theStatus == SameMaterial)
G4cout << "SameMaterial";
else if(theStatus == StepTooSmall)
G4cout << "StepTooSmall";
else if(theStatus == NoRINDEX)
G4cout << "NoRINDEX";
else if(theStatus == Dichroic)
G4cout << "Dichroic Transmission";
G4cout << " ***" << G4endl;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ThreeVector G4OpBoundaryProcess::GetFacetNormal(
const G4ThreeVector& Momentum, const G4ThreeVector& Normal) const
{
G4ThreeVector facetNormal;
if(theModel == unified || theModel == LUT || theModel == DAVIS)
{
/* This function codes alpha to a random value taken from the
distribution p(alpha) = g(alpha; 0, sigma_alpha)*std::sin(alpha),
for alpha > 0 and alpha < 90, where g(alpha; 0, sigma_alpha) is a
gaussian distribution with mean 0 and standard deviation sigma_alpha. */
G4double sigma_alpha = 0.0;
if(OpticalSurface)
sigma_alpha = OpticalSurface->GetSigmaAlpha();
if(sigma_alpha == 0.0)
{
return Normal;
}
G4double f_max = std::min(1.0, 4. * sigma_alpha);
G4double alpha, phi, sinAlpha; //, cosPhi, sinPhi;
do
{ // Loop checking, 13-Aug-2015, Peter Gumplinger
do
{ // Loop checking, 13-Aug-2015, Peter Gumplinger
alpha = G4RandGauss::shoot(0.0, sigma_alpha);
} while(G4UniformRand() * f_max > std::sin(alpha) || alpha >= halfpi);
phi = G4UniformRand() * twopi;
sinAlpha = std::sin(alpha);
facetNormal.set(sinAlpha * std::cos(phi), sinAlpha * std::sin(phi),
std::cos(alpha));
facetNormal.rotateUz(Normal);
} while(Momentum * facetNormal >= 0.0);
}
else
{
G4double polish = 1.0;
if(OpticalSurface)
polish = OpticalSurface->GetPolish();
if(polish < 1.0)
{
do
{ // Loop checking, 13-Aug-2015, Peter Gumplinger
G4ThreeVector smear;
do
{ // Loop checking, 13-Aug-2015, Peter Gumplinger
smear.setX(2. * G4UniformRand() - 1.);
smear.setY(2. * G4UniformRand() - 1.);
smear.setZ(2. * G4UniformRand() - 1.);
} while(smear.mag() > 1.0);
facetNormal = Normal + (1. - polish) * smear;
} while(Momentum * facetNormal >= 0.0);
facetNormal = facetNormal.unit();
}
else
{
facetNormal = Normal;
}
}
return facetNormal;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::DielectricMetal()
{
G4int n = 0;
G4double rand, EdotN;
G4ThreeVector A_trans, A_paral;
do
{
++n;
rand = G4UniformRand();
if(rand > theReflectivity && n == 1)
{
if(rand > theReflectivity + theTransmittance)
{
DoAbsorption();
}
else
{
theStatus = Transmission;
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
break;
}
else
{
if(fRealRIndexMPV && fImagRIndexMPV)
{
if(n > 1)
{
CalculateReflectivity();
if(!G4BooleanRand(theReflectivity))
{
DoAbsorption();
break;
}
}
}
if(theModel == glisur || theFinish == polished)
{
DoReflection();
}
else
{
if(n == 1)
ChooseReflection();
if(theStatus == LambertianReflection)
{
DoReflection();
}
else if(theStatus == BackScattering)
{
NewMomentum = -OldMomentum;
NewPolarization = -OldPolarization;
}
else
{
if(theStatus == LobeReflection)
{
if(fRealRIndexMPV && fImagRIndexMPV)
{
//
}
else
{
theFacetNormal = GetFacetNormal(OldMomentum, theGlobalNormal);
}
}
NewMomentum =
OldMomentum - 2. * OldMomentum * theFacetNormal * theFacetNormal;
EdotN = OldPolarization * theFacetNormal;
A_trans = (sint1 > 0.0) ? OldMomentum.cross(theFacetNormal).unit()
: OldPolarization;
A_paral = NewMomentum.cross(A_trans).unit();
if(iTE > 0 && iTM > 0)
{
NewPolarization = -OldPolarization + (2. * EdotN) * theFacetNormal;
}
else if(iTE > 0)
{
NewPolarization = -A_trans;
}
else if(iTM > 0)
{
NewPolarization = -A_paral;
}
}
}
OldMomentum = NewMomentum;
OldPolarization = NewPolarization;
}
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(NewMomentum * theGlobalNormal < 0.0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::DielectricLUT()
{
G4int thetaIndex, phiIndex;
G4double AngularDistributionValue, thetaRad, phiRad, EdotN;
G4ThreeVector PerpendicularVectorTheta, PerpendicularVectorPhi;
theStatus = G4OpBoundaryProcessStatus(
G4int(theFinish) + (G4int(NoRINDEX) - G4int(groundbackpainted)));
G4int thetaIndexMax = OpticalSurface->GetThetaIndexMax();
G4int phiIndexMax = OpticalSurface->GetPhiIndexMax();
G4double rand;
do
{
rand = G4UniformRand();
if(rand > theReflectivity)
{
if(rand > theReflectivity + theTransmittance)
{
DoAbsorption();
}
else
{
theStatus = Transmission;
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
break;
}
else
{
// Calculate Angle between Normal and Photon Momentum
G4double anglePhotonToNormal = OldMomentum.angle(-theGlobalNormal);
// Round to closest integer: LBNL model array has 91 values
G4int angleIncident = G4lrint(anglePhotonToNormal / CLHEP::deg);
// Take random angles THETA and PHI,
// and see if below Probability - if not - Redo
do
{
thetaIndex = G4RandFlat::shootInt(thetaIndexMax - 1);
phiIndex = G4RandFlat::shootInt(phiIndexMax - 1);
// Find probability with the new indeces from LUT
AngularDistributionValue = OpticalSurface->GetAngularDistributionValue(
angleIncident, thetaIndex, phiIndex);
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(!G4BooleanRand(AngularDistributionValue));
thetaRad = (-90 + 4 * thetaIndex) * pi / 180.;
phiRad = (-90 + 5 * phiIndex) * pi / 180.;
// Rotate Photon Momentum in Theta, then in Phi
NewMomentum = -OldMomentum;
PerpendicularVectorTheta = NewMomentum.cross(theGlobalNormal);
if(PerpendicularVectorTheta.mag() < kCarTolerance)
{
PerpendicularVectorTheta = NewMomentum.orthogonal();
}
NewMomentum = NewMomentum.rotate(anglePhotonToNormal - thetaRad,
PerpendicularVectorTheta);
PerpendicularVectorPhi = PerpendicularVectorTheta.cross(NewMomentum);
NewMomentum = NewMomentum.rotate(-phiRad, PerpendicularVectorPhi);
// Rotate Polarization too:
theFacetNormal = (NewMomentum - OldMomentum).unit();
EdotN = OldPolarization * theFacetNormal;
NewPolarization = -OldPolarization + (2. * EdotN) * theFacetNormal;
}
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(NewMomentum * theGlobalNormal <= 0.0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::DielectricLUTDAVIS()
{
G4int angindex, random, angleIncident;
G4double ReflectivityValue, elevation, azimuth, EdotN;
G4double anglePhotonToNormal;
G4int LUTbin = OpticalSurface->GetLUTbins();
G4double rand = G4UniformRand();
do
{
anglePhotonToNormal = OldMomentum.angle(-theGlobalNormal);
// Davis model has 90 reflection bins: round down
angleIncident = G4lint(anglePhotonToNormal / CLHEP::deg);
ReflectivityValue = OpticalSurface->GetReflectivityLUTValue(angleIncident);
if(rand > ReflectivityValue)
{
if(theEfficiency > 0.)
{
DoAbsorption();
break;
}
else
{
theStatus = Transmission;
if(angleIncident <= 0.01)
{
NewMomentum = OldMomentum;
break;
}
do
{
random = G4RandFlat::shootInt(1, LUTbin + 1);
angindex =
(((random * 2) - 1)) + angleIncident * LUTbin * 2 + 3640000;
azimuth =
OpticalSurface->GetAngularDistributionValueLUT(angindex - 1);
elevation = OpticalSurface->GetAngularDistributionValueLUT(angindex);
} while(elevation == 0. && azimuth == 0.);
NewMomentum = -OldMomentum;
G4ThreeVector v = theGlobalNormal.cross(-NewMomentum);
G4ThreeVector vNorm = v / v.mag();
G4ThreeVector u = vNorm.cross(theGlobalNormal);
u = u *= (std::sin(elevation) * std::cos(azimuth));
v = vNorm *= (std::sin(elevation) * std::sin(azimuth));
G4ThreeVector w = theGlobalNormal *= (std::cos(elevation));
NewMomentum = G4ThreeVector(u + v + w);
// Rotate Polarization too:
theFacetNormal = (NewMomentum - OldMomentum).unit();
EdotN = OldPolarization * theFacetNormal;
NewPolarization = -OldPolarization + (2. * EdotN) * theFacetNormal;
}
}
else
{
theStatus = LobeReflection;
if(angleIncident == 0)
{
NewMomentum = -OldMomentum;
break;
}
do
{
random = G4RandFlat::shootInt(1, LUTbin + 1);
angindex = (((random * 2) - 1)) + (angleIncident - 1) * LUTbin * 2;
azimuth = OpticalSurface->GetAngularDistributionValueLUT(angindex - 1);
elevation = OpticalSurface->GetAngularDistributionValueLUT(angindex);
} while(elevation == 0. && azimuth == 0.);
NewMomentum = -OldMomentum;
G4ThreeVector v = theGlobalNormal.cross(-NewMomentum);
G4ThreeVector vNorm = v / v.mag();
G4ThreeVector u = vNorm.cross(theGlobalNormal);
u = u *= (std::sin(elevation) * std::cos(azimuth));
v = vNorm *= (std::sin(elevation) * std::sin(azimuth));
G4ThreeVector w = theGlobalNormal *= (std::cos(elevation));
NewMomentum = G4ThreeVector(u + v + w);
// Rotate Polarization too: (needs revision)
NewPolarization = OldPolarization;
}
} while(NewMomentum * theGlobalNormal <= 0.0);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::DielectricDichroic()
{
// Calculate Angle between Normal and Photon Momentum
G4double anglePhotonToNormal = OldMomentum.angle(-theGlobalNormal);
// Round it to closest integer
G4double angleIncident = std::floor(180. / pi * anglePhotonToNormal + 0.5);
if(!DichroicVector)
{
if(OpticalSurface)
DichroicVector = OpticalSurface->GetDichroicVector();
}
if(DichroicVector)
{
G4double wavelength = h_Planck * c_light / thePhotonMomentum;
theTransmittance =
DichroicVector->Value(wavelength / nm, angleIncident, idx, idy) * perCent;
// G4cout << "wavelength: " << std::floor(wavelength/nm)
// << "nm" << G4endl;
// G4cout << "Incident angle: " << angleIncident << "deg" << G4endl;
// G4cout << "Transmittance: "
// << std::floor(theTransmittance/perCent) << "%" << G4endl;
}
else
{
G4ExceptionDescription ed;
ed << " G4OpBoundaryProcess/DielectricDichroic(): "
<< " The dichroic surface has no G4Physics2DVector" << G4endl;
G4Exception("G4OpBoundaryProcess::DielectricDichroic", "OpBoun03",
FatalException, ed,
"A dichroic surface must have an associated G4Physics2DVector");
}
if(!G4BooleanRand(theTransmittance))
{ // Not transmitted, so reflect
if(theModel == glisur || theFinish == polished)
{
DoReflection();
}
else
{
ChooseReflection();
if(theStatus == LambertianReflection)
{
DoReflection();
}
else if(theStatus == BackScattering)
{
NewMomentum = -OldMomentum;
NewPolarization = -OldPolarization;
}
else
{
G4double PdotN, EdotN;
do
{
if(theStatus == LobeReflection)
{
theFacetNormal = GetFacetNormal(OldMomentum, theGlobalNormal);
}
PdotN = OldMomentum * theFacetNormal;
NewMomentum = OldMomentum - (2. * PdotN) * theFacetNormal;
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(NewMomentum * theGlobalNormal <= 0.0);
EdotN = OldPolarization * theFacetNormal;
NewPolarization = -OldPolarization + (2. * EdotN) * theFacetNormal;
}
}
}
else
{
theStatus = Dichroic;
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::DielectricDielectric()
{
G4bool Inside = false;
G4bool Swap = false;
G4bool SurfaceRoughnessCriterionPass = true;
if(theSurfaceRoughness != 0. && Rindex1 > Rindex2)
{
G4double wavelength = h_Planck * c_light / thePhotonMomentum;
G4double SurfaceRoughnessCriterion = std::exp(-std::pow(
(4. * pi * theSurfaceRoughness * Rindex1 * cost1 / wavelength), 2));
SurfaceRoughnessCriterionPass = G4BooleanRand(SurfaceRoughnessCriterion);
}
leap:
G4bool Through = false;
G4bool Done = false;
G4double EdotN;
G4ThreeVector A_trans, A_paral, E1pp, E1pl;
G4double E1_perp, E1_parl;
G4double s1, s2, E2_perp, E2_parl, E2_total, TransCoeff;
G4double E2_abs, C_parl, C_perp;
G4double alpha;
do
{
if(Through)
{
Swap = !Swap;
Through = false;
theGlobalNormal = -theGlobalNormal;
G4SwapPtr(Material1, Material2);
G4SwapObj(&Rindex1, &Rindex2);
}
if(theFinish == polished)
{
theFacetNormal = theGlobalNormal;
}
else
{
theFacetNormal = GetFacetNormal(OldMomentum, theGlobalNormal);
}
// PdotN = OldMomentum * theFacetNormal;
EdotN = OldPolarization * theFacetNormal;
cost1 = -OldMomentum * theFacetNormal;
if(std::abs(cost1) < 1.0 - kCarTolerance)
{
sint1 = std::sqrt(1. - cost1 * cost1);
sint2 = sint1 * Rindex1 / Rindex2; // *** Snell's Law ***
// this isn't a sine as we might
// expect from the name; can be > 1
}
else
{
sint1 = 0.0;
sint2 = 0.0;
}
// TOTAL INTERNAL REFLECTION
if(sint2 >= 1.0)
{
Swap = false;
theStatus = TotalInternalReflection;
if(!SurfaceRoughnessCriterionPass)
theStatus = LambertianReflection;
if(theModel == unified && theFinish != polished)
ChooseReflection();
if(theStatus == LambertianReflection)
{
DoReflection();
}
else if(theStatus == BackScattering)
{
NewMomentum = -OldMomentum;
NewPolarization = -OldPolarization;
}
else
{
// PdotN = OldMomentum * theFacetNormal;
NewMomentum =
OldMomentum - 2. * OldMomentum * theFacetNormal * theFacetNormal;
EdotN = OldPolarization * theFacetNormal;
NewPolarization = -OldPolarization + (2. * EdotN) * theFacetNormal;
}
}
// NOT TIR
else if(sint2 < 1.0)
{
// Calculate amplitude for transmission (Q = P x N)
if(cost1 > 0.0)
{
cost2 = std::sqrt(1. - sint2 * sint2);
}
else
{
cost2 = -std::sqrt(1. - sint2 * sint2);
}
if(sint1 > 0.0)
{
A_trans = (OldMomentum.cross(theFacetNormal)).unit();
E1_perp = OldPolarization * A_trans;
E1pp = E1_perp * A_trans;
E1pl = OldPolarization - E1pp;
E1_parl = E1pl.mag();
}
else
{
A_trans = OldPolarization;
// Here we Follow Jackson's conventions and set the parallel
// component = 1 in case of a ray perpendicular to the surface
E1_perp = 0.0;
E1_parl = 1.0;
}
s1 = Rindex1 * cost1;
E2_perp = 2. * s1 * E1_perp / (Rindex1 * cost1 + Rindex2 * cost2);
E2_parl = 2. * s1 * E1_parl / (Rindex2 * cost1 + Rindex1 * cost2);
E2_total = E2_perp * E2_perp + E2_parl * E2_parl;
s2 = Rindex2 * cost2 * E2_total;
if(theTransmittance > 0.)
TransCoeff = theTransmittance;
else if(cost1 != 0.0)
TransCoeff = s2 / s1;
else
TransCoeff = 0.0;
// NOT TIR: REFLECTION
if(!G4BooleanRand(TransCoeff))
{
Swap = false;
theStatus = FresnelReflection;
if(!SurfaceRoughnessCriterionPass)
theStatus = LambertianReflection;
if(theModel == unified && theFinish != polished)
ChooseReflection();
if(theStatus == LambertianReflection)
{
DoReflection();
}
else if(theStatus == BackScattering)
{
NewMomentum = -OldMomentum;
NewPolarization = -OldPolarization;
}
else
{
NewMomentum =
OldMomentum - 2. * OldMomentum * theFacetNormal * theFacetNormal;
if(sint1 > 0.0)
{ // incident ray oblique
E2_parl = Rindex2 * E2_parl / Rindex1 - E1_parl;
E2_perp = E2_perp - E1_perp;
E2_total = E2_perp * E2_perp + E2_parl * E2_parl;
A_paral = (NewMomentum.cross(A_trans)).unit();
E2_abs = std::sqrt(E2_total);
C_parl = E2_parl / E2_abs;
C_perp = E2_perp / E2_abs;
NewPolarization = C_parl * A_paral + C_perp * A_trans;
}
else
{ // incident ray perpendicular
if(Rindex2 > Rindex1)
{
NewPolarization = -OldPolarization;
}
else
{
NewPolarization = OldPolarization;
}
}
}
}
// NOT TIR: TRANSMISSION
else
{
Inside = !Inside;
Through = true;
theStatus = FresnelRefraction;
if(sint1 > 0.0)
{ // incident ray oblique
alpha = cost1 - cost2 * (Rindex2 / Rindex1);
NewMomentum = (OldMomentum + alpha * theFacetNormal).unit();
A_paral = (NewMomentum.cross(A_trans)).unit();
E2_abs = std::sqrt(E2_total);
C_parl = E2_parl / E2_abs;
C_perp = E2_perp / E2_abs;
NewPolarization = C_parl * A_paral + C_perp * A_trans;
}
else
{ // incident ray perpendicular
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
}
}
OldMomentum = NewMomentum.unit();
OldPolarization = NewPolarization.unit();
if(theStatus == FresnelRefraction)
{
Done = (NewMomentum * theGlobalNormal <= 0.0);
}
else
{
Done = (NewMomentum * theGlobalNormal >= -kCarTolerance);
}
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(!Done);
if(Inside && !Swap)
{
if(theFinish == polishedbackpainted || theFinish == groundbackpainted)
{
G4double rand = G4UniformRand();
if(rand > theReflectivity + theTransmittance)
{
DoAbsorption();
}
else if(rand > theReflectivity)
{
theStatus = Transmission;
NewMomentum = OldMomentum;
NewPolarization = OldPolarization;
}
else
{
if(theStatus != FresnelRefraction)
{
theGlobalNormal = -theGlobalNormal;
}
else
{
Swap = !Swap;
G4SwapPtr(Material1, Material2);
G4SwapObj(&Rindex1, &Rindex2);
}
if(theFinish == groundbackpainted)
theStatus = LambertianReflection;
DoReflection();
theGlobalNormal = -theGlobalNormal;
OldMomentum = NewMomentum;
goto leap;
}
}
}
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4OpBoundaryProcess::GetMeanFreePath(const G4Track&, G4double,
G4ForceCondition* condition)
{
*condition = Forced;
return DBL_MAX;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4OpBoundaryProcess::GetIncidentAngle()
{
G4double PdotN = OldMomentum * theFacetNormal;
G4double magP = OldMomentum.mag();
G4double magN = theFacetNormal.mag();
G4double incidentangle = pi - std::acos(PdotN / (magP * magN));
return incidentangle;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4double G4OpBoundaryProcess::GetReflectivity(G4double E1_perp,
G4double E1_parl,
G4double incidentangle,
G4double RealRindex,
G4double ImaginaryRindex)
{
G4complex Reflectivity, Reflectivity_TE, Reflectivity_TM;
G4complex N1(Rindex1, 0.), N2(RealRindex, ImaginaryRindex);
G4complex CosPhi;
G4complex u(1., 0.); // unit number 1
G4complex numeratorTE; // E1_perp=1 E1_parl=0 -> TE polarization
G4complex numeratorTM; // E1_parl=1 E1_perp=0 -> TM polarization
G4complex denominatorTE, denominatorTM;
G4complex rTM, rTE;
G4MaterialPropertiesTable* MPT = Material1->GetMaterialPropertiesTable();
G4MaterialPropertyVector* ppR = MPT->GetProperty(kREALRINDEX);
G4MaterialPropertyVector* ppI = MPT->GetProperty(kIMAGINARYRINDEX);
if(ppR && ppI)
{
G4double RRindex = ppR->Value(thePhotonMomentum, idx_rrindex);
G4double IRindex = ppI->Value(thePhotonMomentum, idx_irindex);
N1 = G4complex(RRindex, IRindex);
}
// Following two equations, rTM and rTE, are from: "Introduction To Modern
// Optics" written by Fowles
CosPhi = std::sqrt(u - ((std::sin(incidentangle) * std::sin(incidentangle)) *
(N1 * N1) / (N2 * N2)));
numeratorTE = N1 * std::cos(incidentangle) - N2 * CosPhi;
denominatorTE = N1 * std::cos(incidentangle) + N2 * CosPhi;
rTE = numeratorTE / denominatorTE;
numeratorTM = N2 * std::cos(incidentangle) - N1 * CosPhi;
denominatorTM = N2 * std::cos(incidentangle) + N1 * CosPhi;
rTM = numeratorTM / denominatorTM;
// This is my calculaton for reflectivity on a metalic surface
// depending on the fraction of TE and TM polarization
// when TE polarization, E1_parl=0 and E1_perp=1, R=abs(rTE)^2 and
// when TM polarization, E1_parl=1 and E1_perp=0, R=abs(rTM)^2
Reflectivity_TE = (rTE * conj(rTE)) * (E1_perp * E1_perp) /
(E1_perp * E1_perp + E1_parl * E1_parl);
Reflectivity_TM = (rTM * conj(rTM)) * (E1_parl * E1_parl) /
(E1_perp * E1_perp + E1_parl * E1_parl);
Reflectivity = Reflectivity_TE + Reflectivity_TM;
do
{
if(G4UniformRand() * real(Reflectivity) > real(Reflectivity_TE))
{
iTE = -1;
}
else
{
iTE = 1;
}
if(G4UniformRand() * real(Reflectivity) > real(Reflectivity_TM))
{
iTM = -1;
}
else
{
iTM = 1;
}
// Loop checking, 13-Aug-2015, Peter Gumplinger
} while(iTE < 0 && iTM < 0);
return real(Reflectivity);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void G4OpBoundaryProcess::CalculateReflectivity()
{
G4double RealRindex = fRealRIndexMPV->Value(thePhotonMomentum, idx_rrindex);
G4double ImaginaryRindex =
fImagRIndexMPV->Value(thePhotonMomentum, idx_irindex);
// calculate FacetNormal
if(theFinish == ground)
{
theFacetNormal = GetFacetNormal(OldMomentum, theGlobalNormal);
}
else
{
theFacetNormal = theGlobalNormal;
}
cost1 = -OldMomentum * theFacetNormal;
if(std::abs(cost1) < 1.0 - kCarTolerance)
{
sint1 = std::sqrt(1. - cost1 * cost1);
}
else
{
sint1 = 0.0;
}
G4ThreeVector A_trans, A_paral, E1pp, E1pl;
G4double E1_perp, E1_parl;
if(sint1 > 0.0)
{
A_trans = (OldMomentum.cross(theFacetNormal)).unit();
E1_perp = OldPolarization * A_trans;
E1pp = E1_perp * A_trans;
E1pl = OldPolarization - E1pp;
E1_parl = E1pl.mag();
}
else
{
A_trans = OldPolarization;
// Here we Follow Jackson's conventions and we set the parallel
// component = 1 in case of a ray perpendicular to the surface
E1_perp = 0.0;
E1_parl = 1.0;
}
G4double incidentangle = GetIncidentAngle();
// calculate the reflectivity depending on incident angle,
// polarization and complex refractive
theReflectivity = GetReflectivity(E1_perp, E1_parl, incidentangle, RealRindex,
ImaginaryRindex);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4bool G4OpBoundaryProcess::InvokeSD(const G4Step* pStep)
{
G4Step aStep = *pStep;
aStep.AddTotalEnergyDeposit(thePhotonMomentum);
G4VSensitiveDetector* sd = aStep.GetPostStepPoint()->GetSensitiveDetector();
if(sd)
return sd->Hit(&aStep);
else
return false;
}