diff options
-rw-r--r-- | chroma/cuda/geometry_types.h | 4 | ||||
-rw-r--r-- | chroma/cuda/photon.h | 55 | ||||
-rw-r--r-- | chroma/geometry.py | 1 | ||||
-rw-r--r-- | chroma/gpu/geometry.py | 5 | ||||
-rw-r--r-- | doc/source/surface.rst | 23 |
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 |