Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new component for "Reactor" and the associated Event.REACT #44

Merged
merged 3 commits into from
Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion pvtrace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@


# material
from .material.component import Scatterer, Absorber, Luminophore
from .material.component import Scatterer, Absorber, Luminophore, Reactor
from .material.distribution import Distribution
from .material.material import Material
from .material.surface import (
Expand Down
7 changes: 5 additions & 2 deletions pvtrace/algorithm/photon_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pvtrace.scene.node import Node
from pvtrace.light.ray import Ray
from pvtrace.light.event import Event
from pvtrace.material.component import Scatterer, Luminophore
from pvtrace.material.component import Scatterer, Luminophore, Reactor
from pvtrace.geometry.utils import (
distance_between,
close_to_zero,
Expand Down Expand Up @@ -184,7 +184,10 @@ def follow(scene, ray, maxsteps=1000, maxpathlength=np.inf, emit_method="kT"):
history.append((ray, event))
continue
else:
history.append((ray, Event.ABSORB))
if isinstance(component, Reactor):
history.append((ray, Event.REACT))
else:
history.append((ray, Event.ABSORB))
break
else:
ray = ray.propagate(full_distance)
Expand Down
1 change: 1 addition & 0 deletions pvtrace/light/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ class Event(Enum):
EMIT = 5
EXIT = 6
KILL = 7
REACT = 8
41 changes: 41 additions & 0 deletions pvtrace/material/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,47 @@ def is_radiative(self, ray):
return False


class Reactor(Absorber):
"""Describes a reaction mixture: photon absorbed cause photochemical transformation.

Examples
--------
Create `Reactor` with isotropic and constant probability of scattering::

Reactor(1.0)
"""

def __init__(self, coefficient, x=None, name="Reactor", hist=False):
""" coefficient: float, list, tuple or numpy.ndarray
Specifies the absorption coefficient per unit length. Constant values
can be supplied or a spectrum per nanometer per unit length.

If using a list of tuple you should also specify the wavelengths using
the `x` keyword.

If using a numpy array use `column_stack` to supply a single array with
a wavelength and coefficient values::

x: list, tuple of numpy.ndarray (optional)
Wavelength values in nanometers. Required when specifying a the
`coefficient` with an list or tuple.
name: str
A user-defined identifier string
hist: Bool
Specifies how the coefficient spectrum is sampled. If `True` the values
are treated as a histogram. If `False` the values are linearly
interpolated.

"""

super(Reactor, self).__init__(
coefficient,
x=x,
hist=hist,
name=name,
)


class Luminophore(Scatterer):
""" Describes molecule, nanocrystal or material which absorbs and emits light.

Expand Down
52 changes: 52 additions & 0 deletions tests/test_refractored_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,30 @@ def make_embedded_lossy_scene(n1=1.5):
scene = Scene(world)
return scene, world, box

def make_embedded_lossy_scene_w_reactor(n1=1.5):
world = Node(
name="world (air)",
geometry=Sphere(
radius=10.0,
material=Material(refractive_index=1.0)
)
)
box = Node(
name="box (reactor)",
geometry=Box(
(1.0, 1.0, 1.0),
material=Material(
refractive_index=n1,
components=[
Reactor(coefficient=10.0)
]
),
),
parent=world
)
scene = Scene(world)
return scene, world, box

def make_embedded_lumophore_scene(n1=1.5):
world = Node(
name="world (air)",
Expand Down Expand Up @@ -207,6 +231,34 @@ def test_follow_lossy_embedded_scene_1():
assert np.allclose(expected_point, point, atol=EPS_ZERO)


def test_follow_lossy_embedded_scene_w_reactor():
ray = Ray(
position=(0.0, 0.0, -1.0),
direction=(0.0, 0.0, 1.0),
wavelength=555.0,
is_alive=True
)
scene, world, box = make_embedded_lossy_scene_w_reactor()
np.random.seed(0)
path = photon_tracer.follow(scene, ray)
path, events = zip(*path)
positions = [x.position for x in path]
expected_positions = [
(0.00, 0.00, -1.00), # Starting
(0.00, 0.00, -0.50), # Hit box
(0.00, 0.00, -0.3744069237034118), # Absorbed and reacted
]
expected_events = [
Event.GENERATE,
Event.TRANSMIT,
Event.REACT,
]
for expected_point, point, expected_event, event in zip(
expected_positions, positions, expected_events, events):
assert expected_event == event
assert np.allclose(expected_point, point, atol=EPS_ZERO)


def test_follow_embedded_lumophore_scene_1():

ray = Ray(
Expand Down