summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chroma/cuda/geometry_types.h4
-rw-r--r--chroma/cuda/photon.h55
-rw-r--r--chroma/geometry.py1
-rw-r--r--chroma/gpu/geometry.py5
-rw-r--r--doc/source/surface.rst23
5 files changed, 40 insertions, 48 deletions
diff --git a/chroma/cuda/geometry_types.h b/chroma/cuda/geometry_types.h
index f82f372..46226b2 100644
--- a/chroma/cuda/geometry_types.h
+++ b/chroma/cuda/geometry_types.h
@@ -14,8 +14,6 @@ struct Material
// surface models
enum {
SURFACE_DEFAULT, // specular + diffuse + absorption + detection
- SURFACE_SPECULAR, // perfect specular reflector
- SURFACE_DIFFUSE, // perfect diffuse reflector
SURFACE_COMPLEX, // use complex index of refraction
SURFACE_WLS // wavelength-shifting reemission
};
@@ -25,7 +23,6 @@ struct Surface
float *detect;
float *absorb;
float *reemit;
- float *reflect;
float *reflect_diffuse;
float *reflect_specular;
float *eta;
@@ -71,3 +68,4 @@ struct Geometry
};
#endif
+
diff --git a/chroma/cuda/photon.h b/chroma/cuda/photon.h
index 09430e9..4ec1cea 100644
--- a/chroma/cuda/photon.h
+++ b/chroma/cuda/photon.h
@@ -332,7 +332,7 @@ propagate_at_specular_reflector(Photon &p, State &s)
p.history |= REFLECT_SPECULAR;
return CONTINUE;
-} // reflect_specular
+} // propagate_at_specular_reflector
__device__ int
propagate_at_diffuse_reflector(Photon &p, State &s, curandState &rng)
@@ -348,17 +348,17 @@ propagate_at_diffuse_reflector(Photon &p, State &s, curandState &rng)
p.history |= REFLECT_DIFFUSE;
return CONTINUE;
-} // reflect_diffuse
+} // propagate_at_diffuse_reflector
__device__ int
propagate_complex(Photon &p, State &s, curandState &rng, Surface* surface, bool use_weights=false)
{
float detect = interp_property(surface, p.wavelength, surface->detect);
+ float reflect_specular = interp_property(surface, p.wavelength, surface->reflect_specular);
+ float reflect_diffuse = interp_property(surface, p.wavelength, surface->reflect_diffuse);
float n2_eta = interp_property(surface, p.wavelength, surface->eta);
float n2_k = interp_property(surface, p.wavelength, surface->k);
- float uniform_sample = curand_uniform(&rng);
-
// thin film optical model, adapted from RAT PMT optical model by P. Jones
cuFloatComplex n1 = make_cuFloatComplex(s.refractive_index1, 0.0f);
cuFloatComplex n2 = make_cuFloatComplex(n2_eta, n2_k);
@@ -475,28 +475,33 @@ propagate_complex(Photon &p, State &s, curandState &rng, Surface* surface, bool
}
if (use_weights && detect > 0.0f) {
- p.history |= SURFACE_ABSORB;
p.history |= SURFACE_DETECT;
p.weight *= detect;
return BREAK;
}
- if (uniform_sample < absorb) {
- // absorb
- p.history |= SURFACE_ABSORB;
+ float uniform_sample = curand_uniform(&rng);
+ if (uniform_sample < absorb) {
// detection probability is conditional on absorption here
float uniform_sample_detect = curand_uniform(&rng);
if (uniform_sample_detect < detect)
p.history |= SURFACE_DETECT;
+ else
+ p.history |= SURFACE_ABSORB;
return BREAK;
}
- else if (uniform_sample < absorb + reflect) {
- return propagate_at_diffuse_reflector(p, s, rng);
+ else if (uniform_sample < absorb + reflect || !surface->transmissive) {
+ // reflect, specularly (default) or diffusely
+ float uniform_sample_reflect = curand_uniform(&rng);
+ if (uniform_sample_reflect < reflect_diffuse)
+ return propagate_at_diffuse_reflector(p, s, rng);
+ else
+ return propagate_at_specular_reflector(p, s);
}
else {
- // transmit
+ // refract and transmit
p.direction = rotate(s.surface_normal, PI-refracted_angle, incident_plane_normal);
p.polarization = cross(incident_plane_normal, p.direction);
p.polarization /= norm(p.polarization);
@@ -509,7 +514,8 @@ __device__ int
propagate_at_wls(Photon &p, State &s, curandState &rng, Surface *surface, bool use_weights=false)
{
float absorb = interp_property(surface, p.wavelength, surface->absorb);
- float reflect = interp_property(surface, p.wavelength, surface->reflect);
+ float reflect_specular = interp_property(surface, p.wavelength, surface->reflect_specular);
+ float reflect_diffuse = interp_property(surface, p.wavelength, surface->reflect_diffuse);
float reemit = interp_property(surface, p.wavelength, surface->reemit);
float uniform_sample = curand_uniform(&rng);
@@ -519,12 +525,11 @@ propagate_at_wls(Photon &p, State &s, curandState &rng, Surface *surface, bool u
float survive = 1.0f - absorb;
absorb = 0.0f;
p.weight *= survive;
- reflect /= survive;
+ reflect_diffuse /= survive;
+ reflect_specular /= survive;
}
if (uniform_sample < absorb) {
- p.history |= SURFACE_ABSORB;
-
float uniform_sample_reemit = curand_uniform(&rng);
if (uniform_sample_reemit < reemit) {
p.history |= SURFACE_REEMIT;
@@ -532,10 +537,16 @@ propagate_at_wls(Photon &p, State &s, curandState &rng, Surface *surface, bool u
return propagate_at_diffuse_reflector(p, s, rng); // reemit isotropically (eh?)
}
+ p.history |= SURFACE_ABSORB;
return BREAK;
}
- else if (uniform_sample < absorb + reflect) {
- return propagate_at_diffuse_reflector(p, s, rng);
+ else if (uniform_sample < absorb + reflect_specular + reflect_diffuse) {
+ // choose how to reflect, defaulting to diffuse
+ float uniform_sample_reflect = curand_uniform(&rng) * (reflect_specular + reflect_diffuse);
+ if (uniform_sample_reflect < reflect_specular)
+ return propagate_at_specular_reflector(p, s);
+ else
+ return propagate_at_diffuse_reflector(p, s, rng);
}
else {
p.history |= SURFACE_TRANSMIT;
@@ -549,18 +560,14 @@ propagate_at_surface(Photon &p, State &s, curandState &rng, Geometry *geometry,
{
Surface *surface = geometry->surfaces[s.surface_index];
- if (surface->model == SURFACE_SPECULAR)
- return propagate_at_specular_reflector(p, s);
- else if (surface->model == SURFACE_DIFFUSE)
- return propagate_at_diffuse_reflector(p, s, rng);
- else if (surface->model == SURFACE_COMPLEX)
+ if (surface->model == SURFACE_COMPLEX)
return propagate_complex(p, s, rng, surface, use_weights);
else if (surface->model == SURFACE_WLS)
return propagate_at_wls(p, s, rng, surface, use_weights);
else {
- // if no surface model is specified, do a combination of specular and
+ // use default surface model: do a combination of specular and
// diffuse reflection, detection, and absorption based on relative
- // probabilties (i.e. the "old" behavior)
+ // probabilties
// since the surface properties are interpolated linearly, we are
// guaranteed that they still sum to 1.0.
diff --git a/chroma/geometry.py b/chroma/geometry.py
index 416a6e7..19294be 100644
--- a/chroma/geometry.py
+++ b/chroma/geometry.py
@@ -175,7 +175,6 @@ class Surface(object):
self.set('detect', 0)
self.set('absorb', 0)
self.set('reemit', 0)
- self.set('reflect', 0)
self.set('reflect_diffuse', 0)
self.set('reflect_specular', 0)
self.set('eta', 0)
diff --git a/chroma/gpu/geometry.py b/chroma/gpu/geometry.py
index f74d32d..ff71b56 100644
--- a/chroma/gpu/geometry.py
+++ b/chroma/gpu/geometry.py
@@ -83,8 +83,6 @@ class GPUGeometry(object):
absorb_gpu = ga.to_gpu(absorb)
reemit = interp_material_property(wavelengths, surface.reemit)
reemit_gpu = ga.to_gpu(reemit)
- reflect = interp_material_property(wavelengths, surface.reflect)
- reflect_gpu = ga.to_gpu(reflect)
reflect_diffuse = interp_material_property(wavelengths, surface.reflect_diffuse)
reflect_diffuse_gpu = ga.to_gpu(reflect_diffuse)
reflect_specular = interp_material_property(wavelengths, surface.reflect_specular)
@@ -99,7 +97,6 @@ class GPUGeometry(object):
self.surface_data.append(detect_gpu)
self.surface_data.append(absorb_gpu)
self.surface_data.append(reemit_gpu)
- self.surface_data.append(reflect_gpu)
self.surface_data.append(reflect_diffuse_gpu)
self.surface_data.append(reflect_specular_gpu)
self.surface_data.append(eta_gpu)
@@ -108,7 +105,7 @@ class GPUGeometry(object):
surface_gpu = \
make_gpu_struct(surface_struct_size,
- [detect_gpu, absorb_gpu, reemit_gpu, reflect_gpu,
+ [detect_gpu, absorb_gpu, reemit_gpu,
reflect_diffuse_gpu,reflect_specular_gpu,
eta_gpu, k_gpu, reemission_cdf_gpu,
np.uint32(surface.model),
diff --git a/doc/source/surface.rst b/doc/source/surface.rst
index a9b61d1..0ed142b 100644
--- a/doc/source/surface.rst
+++ b/doc/source/surface.rst
@@ -3,7 +3,7 @@ Surface Models
Chroma includes a variety of surface models, which control the interaction of photons with objects. The ``Surface`` class contains many (typically wavelength-dependent) surface parameters, some of which apply to each surface model.
-To select a particular model for a surface, set ``surface.model = MODEL`` where ``MODEL`` is one of ``{ SURFACE_DEFAULT, SURFACE_SPECULAR, SURFACE_DIFFUSE, SURFACE_COMPLEX, SURFACE_WLS }``.
+To select a particular model for a surface, set ``surface.model = MODEL`` where ``MODEL`` is one of ``{ SURFACE_DEFAULT, SURFACE_COMPLEX, SURFACE_WLS }``.
``SURFACE_DEFAULT``
-------------------
@@ -19,27 +19,17 @@ Parameters::
unsigned int n
float step
float wavelength0
-
-``SURFACE_SPECULAR``
---------------------
-
-A perfect specular reflector. Behavior is identical to ``SURFACE_DEFAULT`` with 100% specular reflection at all wavelengths, but is marginally faster. This model has no parameters.
-
-``SURFACE_DIFFUSE``
--------------------
-
-A perfect diffuse reflector. Behavior is identical to ``SURFACE_DEFAULT`` with 100% diffuse reflection at all wavelengths, but is marginally faster. This model has no parameters.
``SURFACE_COMPLEX``
-------------------
-This surface model uses a complex index of refraction (``eta``, ``k``) to compute transmission, (specular) reflection, and absorption probabilities. Surfaces may also be photon detectors, but the detection probability is conditional on detection (``detect`` should be normalized to 1). If a surface is not transmissive (``bool transmissive``), transmitted photons are absorbed.
-
-This model accounts for incoming photon polarization in its calculations.
+This surface model uses a complex index of refraction (``eta``, ``k``) to compute transmission, (specular) reflection, and absorption probabilities, taking into account the incoming photon polarization and surface thickness (``thickness``). Surfaces may also be photon detectors, but detection is conditional on absorption so ``detect`` should be normalized independently. Reflection may be either specular or diffuse, with probabilities given in ``reflect_specular`` and ``reflect_diffuse``; these should sum to 1 at each wavelength. By default surfaces are not transmissive (use ``bool transmissive`` to set), and transmitted photons are absorbed.
Parameters::
float *detect
+ float *reflect_specular
+ float *reflect_diffuse
float *eta
float *k
unsigned int n
@@ -51,12 +41,13 @@ Parameters::
``SURFACE_WLS``
---------------
-A model of wavelength-shifting surfaces. Surfaces may absorb and reflect (these probabilities should sum to 1). Reflection is diffuse. If a photon is absorbed, it may be reemitted with a probability given in ``float *reemit`` (normalized to 1). The reemission spectrum CDF is defined in ``float* reemission_cdf``. The CDF must start at 0 and end at 1. This model does not enforce conservation of energy, and cannot reemit multiple photons!
+This surface model is used for wavelength-shifting surfaces. Surfaces may absorb, specularly reflect, diffusely reflect, or transmit photons; ``1 - absorb - reflect_diffuse - reflect_specular`` gives the transmission probability. If a photon is absorbed, it may be reemitted with a probability given in ``float *reemit``. The reemission spectrum CDF is defined in ``float* reemission_cdf``. The CDF must start at 0 and end at 1. This model does not enforce conservation of energy, and cannot reemit multiple photons!
Parameters::
float *absorb
- float *reflect
+ float *reflect_specular
+ float *reflect_diffuse
float *reemit
float *reemission_cdf
unsigned int n