Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions qudarap/QSim.cu
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ __global__ void _QSim_propagate_to_boundary( qsim* sim, sphoton* photon, unsigne
ctx.prd = &dbg->prd ; // no need for local copy when readonly
ctx.s = dbg->s ;
ctx.p = dbg->p ; // need local copy of photon otherwise will have write interference between threads
ctx.current_group_velocity = ctx.s.material1_group_velocity();
ctx.current_material_index = ctx.s.index.x;

unsigned flag = 0u ;
//sim->propagate_to_boundary( flag, p, prd, s, rng, idx, tagr );
Expand Down Expand Up @@ -357,6 +359,8 @@ __global__ void _QSim_propagate_at_boundary_generate( qsim* sim, sphoton* photon
ctx.prd = &dbg->prd ; // no need for local copy when readonly
ctx.s = dbg->s ;
ctx.p = dbg->p ; // need local copy of photon otherwise will have write interference between threads
ctx.current_group_velocity = ctx.s.material1_group_velocity();
ctx.current_material_index = ctx.s.index.x;

quad4& q = (quad4&)ctx.p ;
q.q0.f = q.q1.f ; // non-standard record initial mom and pol into q0, q3
Expand Down Expand Up @@ -402,6 +406,8 @@ __global__ void _QSim_propagate_at_boundary_mutate( qsim* sim, sphoton* photon,
ctx.p = photon[idx] ;
ctx.s = dbg->s ;
ctx.prd = &dbg->prd ;
ctx.current_group_velocity = ctx.s.material1_group_velocity();
ctx.current_material_index = ctx.s.index.x;

quad4& q = (quad4&)ctx.p ;
q.q0.f = q.q1.f ; // non-standard record initial mom and pol into q0, q3
Expand Down Expand Up @@ -441,6 +447,8 @@ __global__ void _QSim_propagate_at_multifilm_mutate( qsim* sim, sphoton* photon,
ctx.p = photon[idx] ;
ctx.s = dbg->s ;
ctx.prd = &dbg->prd ;
ctx.current_group_velocity = ctx.s.material1_group_velocity();
ctx.current_material_index = ctx.s.index.x;

quad4& q = (quad4&)ctx.p ;

Expand Down Expand Up @@ -820,9 +828,3 @@ extern void QSim_multifilm_lookup_all(dim3 numBlocks, dim3 threadsPerBlock, qsim
printf("//QSim_multifilm_lookup width %d height %d \n", width, height );
_QSim_multifilm_lookup_all<<<numBlocks,threadsPerBlock>>>( sim, sample,result , width, height );
}






5 changes: 2 additions & 3 deletions qudarap/QState.hh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once
/**
QState.hh
Expand Down Expand Up @@ -51,6 +51,7 @@
float m1_scattering_length = 1000.f ;
float m1_reemission_prob = 0.f ;
float m1_group_velocity = 300.f ;
float m2_group_velocity = 300.f;

float m2_refractive_index = qenvfloat("M2_REFRACTIVE_INDEX", "1.5" ) ;
float m2_absorption_length = 1000.f ;
Expand All @@ -65,7 +66,7 @@
sstate s ;
s.material1 = make_float4( m1_refractive_index, m1_absorption_length, m1_scattering_length, m1_reemission_prob );
s.material2 = make_float4( m2_refractive_index, m2_absorption_length, m2_scattering_length, m2_reemission_prob );
s.m1group2 = make_float4( m1_group_velocity, 0.f, 0.f, 0.f );
s.m1group2 = make_float4(m1_group_velocity, m2_group_velocity, 0.f, 0.f);
s.surface = make_float4( su_detect, su_absorb, su_reflect_specular, su_reflect_diffuse );
s.optical = make_uint4( 0u, 0u, 0u, 0u ); // x/y/z/w index/type/finish/value
s.index = make_uint4( 0u, 0u, 0u, 0u ); // indices of m1/m2/surf/sensor
Expand Down Expand Up @@ -144,5 +145,3 @@
std::string repr = ss.str();
return repr ;
}


5 changes: 4 additions & 1 deletion qudarap/qbnd.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ Notice that s.optical.x and s.index.z are the same thing.
So half of s.index is extraneous and the m1 index and m2 index
is not much used.

Also only one elemnt of m1group2 is actually used
Also only one element of m1group2 was formerly used. The y slot now carries
material2 group velocity so transmitted segments can carry the correct active
medium timing across boundary crossings.


s.optical.x
Expand Down Expand Up @@ -194,6 +196,7 @@ inline QBND_METHOD void qbnd::fill_state(sstate& s, unsigned boundary, float wav
s.m1group2 = boundary_lookup( wavelength, m1_line, 1); // group_velocity , (unused , unused , unused)
s.material2 = boundary_lookup( wavelength, m2_line, 0); // refractive_index, (absorption_length, scattering_length, reemission_prob) only m2:refractive index actually used
s.surface = boundary_lookup( wavelength, su_line, 0); // detect, , absorb , (reflect_specular), reflect_diffuse [they add to 1. so one not used]
s.set_material2_group_velocity(boundary_lookup(wavelength, m2_line, 1).x);

s.optical = optical[su_line].u ; // 1-based-surface-index-0-meaning-boundary/type/finish/value (type,finish,value not used currently)

Expand Down
17 changes: 15 additions & 2 deletions qudarap/qsim.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/**
qsim.h : GPU side struct prepared CPU side by QSim.hh
========================================================
Expand Down Expand Up @@ -723,7 +723,7 @@
const float& absorption_length = s.material1.y ;
const float& scattering_length = s.material1.z ;
const float& reemission_prob = s.material1.w ;
const float& group_velocity = s.m1group2.x ;
const float& group_velocity = ctx.current_group_velocity;
const float& distance_to_boundary = ctx.prd->q0.f.w ;


Expand Down Expand Up @@ -1184,6 +1184,8 @@

flag = reflect ? BOUNDARY_REFLECT : BOUNDARY_TRANSMIT ;

ctx.current_material_index = reflect ? s.index.x : s.index.y;
ctx.current_group_velocity = reflect ? s.material1_group_velocity() : s.material2_group_velocity();

#if !defined(PRODUCTION) && defined(DEBUG_TAG)
if( flag == BOUNDARY_REFLECT )
Expand Down Expand Up @@ -2249,6 +2251,18 @@

bnd->fill_state(ctx.s, boundary, ctx.p.wavelength, cosTheta, ctx.pidx, base->pidx );

if (ctx.current_material_index == 0u)
{
ctx.current_material_index = ctx.s.index.x;
ctx.current_group_velocity = ctx.s.material1_group_velocity();
}
else if (ctx.s.index.x == ctx.current_material_index)
{
// When the boundary orientation agrees with the carried medium, refresh
// the active velocity from the wavelength-dependent material lookup.
ctx.current_group_velocity = ctx.s.material1_group_velocity();
}

unsigned flag = 0 ;

int command = propagate_to_boundary( flag, rng, ctx );
Expand Down Expand Up @@ -2540,4 +2554,3 @@
p.set_index(photon_id) ;
}
#endif

8 changes: 8 additions & 0 deletions src/g4app.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ struct TrackingAction : G4UserTrackingAction

void PreUserTrackingAction(const G4Track *track) override
{
if (track->GetDefinition() == G4OpticalPhoton::OpticalPhotonDefinition())
{
// Geant4 boundary updates optical velocity via ProposeVelocity, but the
// track must honor the given velocity for post-boundary timing to match.
G4Track *mutable_track = const_cast<G4Track *>(track);
mutable_track->UseGivenVelocity(true);
}

spho *label = STrackInfo::GetRef(track);

if (label == nullptr)
Expand Down
3 changes: 2 additions & 1 deletion sysrap/sctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ struct sctx

sphoton p ;
sstate s ;
float current_group_velocity;
unsigned current_material_index;

#ifndef PRODUCTION
srec rec ;
Expand Down Expand Up @@ -184,4 +186,3 @@ SCTX_METHOD void sctx::end()
}

#endif

10 changes: 5 additions & 5 deletions sysrap/sstate.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#pragma once

#if defined(__CUDACC__) || defined(__CUDABE__)
Expand Down Expand Up @@ -25,7 +25,7 @@
struct sstate
{
float4 material1 ; // refractive_index/absorption_length/scattering_length/reemission_prob
float4 m1group2 ; // group_velocity/spare1/spare2/spare3
float4 m1group2 ; // material1_group_velocity/material2_group_velocity/spare2/spare3
float4 material2 ;
float4 surface ; // detect/absorb/reflect_specular/reflect_diffuse

Expand All @@ -42,6 +42,9 @@
void save(const char* dir) const ;
#endif

SSTATE_METHOD float material1_group_velocity() const { return m1group2.x; }
SSTATE_METHOD float material2_group_velocity() const { return m1group2.y; }
SSTATE_METHOD void set_material2_group_velocity(float gv) { m1group2.y = gv; }

};

Expand Down Expand Up @@ -71,7 +74,7 @@
<< " (refractive_index/absorption_length/scattering_length/reemission_prob) "
<< std::endl
<< " m1group2 " << s.m1group2
<< " (group_velocity/spare1/spare2/spare3) "
<< " (material1_group_velocity/material2_group_velocity/spare2/spare3) "
<< std::endl
<< " material2 " << s.material2
<< " (refractive_index/absorption_length/scattering_length/reemission_prob) "
Expand Down Expand Up @@ -134,6 +137,3 @@
the named field access would be helpful to isolate user code from changes to the struct.

**/



27 changes: 25 additions & 2 deletions tests/compare_ab.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import numpy as np

from optiphy.geant4_version import detect_geant4_version, geant4_series


EXPECTED_DIFF = {
"11.3": [14, 22, 32, 34, 40, 81, 85],
"11.4+": [0, 30, 32, 34, 42, 69, 78, 85, 86],
}


def expected_diff_for_version(version):
return EXPECTED_DIFF[geant4_series(version)]


geant4_version = detect_geant4_version()
expected_diff = expected_diff_for_version(geant4_version)

a = np.load("/tmp/fakeuser/opticks/GEOM/fakegeom/simg4ox/ALL0_no_opticks_event_name/A000/record.npy")
b = np.load("/tmp/fakeuser/opticks/GEOM/fakegeom/simg4ox/ALL0_no_opticks_event_name/B000/f000/record.npy")

print(a.shape)
print(b.shape)
print(f"GEANT4_VERSION={geant4_version}")
print(f"EXPECTED_DIFF={expected_diff}")

assert a.shape == b.shape

diff = [i for i, (a, b) in enumerate(zip(a[:, 1:], b[:, 0:-1])) if not np.allclose(a, b, rtol=0, atol=1e-5)]
# Geant4 and Opticks record one-step-shifted sequences for this test geometry,
# so compare the aligned slices directly, including time.
a_cmp = a[:, 1:]
b_cmp = b[:, 0:-1]

diff = [i for i, (ac, bc) in enumerate(zip(a_cmp, b_cmp)) if not np.allclose(ac, bc, rtol=0, atol=1e-5)]
print(diff)

assert diff == [14, 22, 32, 34, 40, 81, 85]
assert diff == expected_diff
63 changes: 54 additions & 9 deletions tests/test_GPURaytrace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,50 @@

set -e


SEED=42
TOLERANCE=113
PASS=true

GEANT4_VERSION=$(geant4-version version)
GEANT4_SERIES=$(geant4-version series)

declare -Ar SUPPORTED_GEANT4_SERIES=(
["11.3"]=1
["11.4+"]=1
)

declare -Ar EXPECTED_G4_HITS=(
["11.3:cerenkov"]=12672
["11.3:cerenkov_scintillation"]=17473
["11.4+:cerenkov"]=11842
["11.4+:cerenkov_scintillation"]=21411
)

declare -Ar EXPECTED_OPTICKS_HITS=(
["11.3:cerenkov"]=12664
["11.3:cerenkov_scintillation"]=17443
["11.4+:cerenkov"]=11827
["11.4+:cerenkov_scintillation"]=21390
)

set_expected_hits() {
local test_name=$1
local key="${GEANT4_SERIES}:${test_name}"

if [[ -z ${SUPPORTED_GEANT4_SERIES[$GEANT4_SERIES]+x} ]]; then
echo "FAILED: unsupported Geant4 version $GEANT4_VERSION. Add hit-count references for this release."
exit 1
fi

if [[ -z ${EXPECTED_G4_HITS[$key]+x} || -z ${EXPECTED_OPTICKS_HITS[$key]+x} ]]; then
echo "FAILED: unknown test name: $test_name"
exit 1
fi

EXPECTED_G4=${EXPECTED_G4_HITS[$key]}
EXPECTED_OPTICKS=${EXPECTED_OPTICKS_HITS[$key]}
}

check_hits() {
local label=$1
local actual=$2
Expand All @@ -21,8 +60,12 @@ check_hits() {
fi
}

echo "Using Geant4 version $GEANT4_VERSION"

# ---- Test 1: Cerenkov only (opticks_raindrop.gdml) ----
echo "=== Test 1: Cerenkov only (opticks_raindrop.gdml) ==="
set_expected_hits cerenkov

echo "Running GPURaytrace with seed $SEED ..."
OUTPUT=$(USER=fakeuser GEOM=fakegeom GPURaytrace \
-g "$OPTICKS_HOME/tests/geom/opticks_raindrop.gdml" \
Expand All @@ -32,15 +75,17 @@ OUTPUT=$(USER=fakeuser GEOM=fakegeom GPURaytrace \
G4_HITS=$(echo "$OUTPUT" | grep "Geant4: NumHits:" | awk '{print $NF}')
OPTICKS_HITS=$(echo "$OUTPUT" | grep "Opticks: NumHits:" | awk '{print $NF}')

echo "Geant4: NumHits: $G4_HITS (expected 12672 +/- $TOLERANCE)"
echo "Opticks: NumHits: $OPTICKS_HITS (expected 12664 +/- $TOLERANCE)"
echo "Geant4: NumHits: $G4_HITS (expected $EXPECTED_G4 +/- $TOLERANCE)"
echo "Opticks: NumHits: $OPTICKS_HITS (expected $EXPECTED_OPTICKS +/- $TOLERANCE)"

check_hits "Geant4 NumHits" "$G4_HITS" 12672
check_hits "Opticks NumHits" "$OPTICKS_HITS" 12664
check_hits "Geant4 NumHits" "$G4_HITS" "$EXPECTED_G4"
check_hits "Opticks NumHits" "$OPTICKS_HITS" "$EXPECTED_OPTICKS"

# ---- Test 2: Cerenkov + Scintillation (opticks_raindrop_with_scintillation.gdml) ----
echo ""
echo "=== Test 2: Cerenkov + Scintillation (opticks_raindrop_with_scintillation.gdml) ==="
set_expected_hits cerenkov_scintillation

echo "Running GPURaytrace with seed $SEED ..."
OUTPUT=$(USER=fakeuser GEOM=fakegeom GPURaytrace \
-g "$OPTICKS_HOME/tests/geom/opticks_raindrop_with_scintillation.gdml" \
Expand All @@ -50,11 +95,11 @@ OUTPUT=$(USER=fakeuser GEOM=fakegeom GPURaytrace \
G4_HITS=$(echo "$OUTPUT" | grep "Geant4: NumHits:" | awk '{print $NF}')
OPTICKS_HITS=$(echo "$OUTPUT" | grep "Opticks: NumHits:" | awk '{print $NF}')

echo "Geant4: NumHits: $G4_HITS (expected 17473 +/- $TOLERANCE)"
echo "Opticks: NumHits: $OPTICKS_HITS (expected 17443 +/- $TOLERANCE)"
echo "Geant4: NumHits: $G4_HITS (expected $EXPECTED_G4 +/- $TOLERANCE)"
echo "Opticks: NumHits: $OPTICKS_HITS (expected $EXPECTED_OPTICKS +/- $TOLERANCE)"

check_hits "Geant4 NumHits" "$G4_HITS" 17473
check_hits "Opticks NumHits" "$OPTICKS_HITS" 17443
check_hits "Geant4 NumHits" "$G4_HITS" "$EXPECTED_G4"
check_hits "Opticks NumHits" "$OPTICKS_HITS" "$EXPECTED_OPTICKS"

# ---- Summary ----
echo ""
Expand Down
Loading