From 9b110627ee062fb5c3ccf51d2ad26fffd0361ba0 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sat, 16 Sep 2023 10:02:33 -0600 Subject: [PATCH 01/15] adding a fresnel visualization class --- cmeutils/__init__.py | 2 +- cmeutils/visualize.py | 75 +++++++++++++++++++++++++++++++++++++++++++ environment-dev.yml | 1 + environment.yml | 1 + 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 cmeutils/visualize.py diff --git a/cmeutils/__init__.py b/cmeutils/__init__.py index 3d07805..0d2eabd 100644 --- a/cmeutils/__init__.py +++ b/cmeutils/__init__.py @@ -1,4 +1,4 @@ from . import gsd_utils, structure from .__version__ import __version__ -__all__ = ["__version__", "gsd_utils", "structure", "dynamics"] +__all__ = ["__version__", "gsd_utils", "structure", "dynamics", "visualize"] diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py new file mode 100644 index 0000000..4fd8cec --- /dev/null +++ b/cmeutils/visualize.py @@ -0,0 +1,75 @@ +import fresnel +import gsd.hoomd +import numpy as np + + +class FresnelGSD: + def __init__( + self, + material, + gsd_file, + frame=0, + color_dict=None, + camera=fresnel.camera.Orthographic, + ): + self.gsd_file = gsd_file + self._scene = fresnel.Scene() + self.color_dict = color_dict + self._camera = camera + self._snapshot = None + self._frame = None + self.frame = frame + self.material = fresnel.material.Material() + + @property + def geometry(self): + geometry = fresnel.geometry.Sphere( + scene=self._scene, + position=self.positions, + radius=self.radius, + color=fresnel.color.linear(self.colors), + ) + geometry.material = self.material + return geometry + + @property + def snapshot(self): + return self._snapshot + + @property + def frame(self): + return self._frame + + @frame.setter + #TODO: Assert num frames + def frame(self, frame): + self._frame = frame + with gsd.hoomd.open(self.gsd_file) as f: + self._snapshot = f[frame] + + @property + def positions(self): + return self.snapshot.particles.position + + @property + def radius(self): + return self.snapshot.particles.diameter / 2 + + @property + def particle_types(self): + return np.array( + [snapshot.particles.types[i] for i in snap.particles.typeid] + ) + + @property + def colors(self): + if self.color_dict: + return np.array( + [self.color_dict[i] for i in self.particle_types] + ) + else: + return np.array([0.5, 0.25, 0.5]) + + def view(self): + fresnel.preview(self.scene) + diff --git a/environment-dev.yml b/environment-dev.yml index d6a524f..c8d9243 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -2,6 +2,7 @@ name: cmeutils-dev channels: - conda-forge dependencies: + - fresnel - freud - gsd=2.9 - hoomd<4.0=*cpu* diff --git a/environment.yml b/environment.yml index 430031e..519a469 100644 --- a/environment.yml +++ b/environment.yml @@ -2,6 +2,7 @@ name: cmeutils channels: - conda-forge dependencies: + - fresnel - freud - gsd=2.9 - hoomd<4.0=*cpu* From 8a9cc3f9d8058c4e2a56c0ea73c1c8dcea5209a1 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sat, 16 Sep 2023 11:31:59 -0600 Subject: [PATCH 02/15] add material and camera --- cmeutils/visualize.py | 76 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 4fd8cec..3dd0035 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -6,32 +6,90 @@ class FresnelGSD: def __init__( self, - material, gsd_file, frame=0, color_dict=None, - camera=fresnel.camera.Orthographic, + solid=0.1, + roughness=0.3, + specular=0.5, + specular_trans=0, + metal=0, + view_axis=(1, 0, 0) ): + self.scene = fresnel.Scene() self.gsd_file = gsd_file - self._scene = fresnel.Scene() - self.color_dict = color_dict - self._camera = camera self._snapshot = None - self._frame = None + self._frame = 0 self.frame = frame - self.material = fresnel.material.Material() + self._height = 5 + self.color_dict = color_dict + # Set fresnel.material.Material attrs + self.solid = solid + self.roughness = roughness + self.specular = specular + self.specular_trans = specular_trans + self.metal = metal + # Set fresnel.camera attrs + self.view_axis = np.asarray(view_axis) + self._up = np.array([0, 0, 1]) @property def geometry(self): geometry = fresnel.geometry.Sphere( - scene=self._scene, + scene=self.scene, position=self.positions, radius=self.radius, color=fresnel.color.linear(self.colors), ) geometry.material = self.material return geometry + + @property + def material(self): + material = fresnel.material.Material( + primitive_color_mix=1, + solid=self.solid, + roughness=self.roughness, + specular=self.specular, + spec_trans=self.specular_trans, + metal=self.metal + ) + return material + + @property + def camera(self): + camera=fresnel.camera.Orthographic( + position=self.camera_position, + look_at=self.look_at, + up=self.up, + height=self.height + ) + return camera + + @property + def camera_position(self): + return (self.snapshot.configuration.box[:3] * self.view_axis) - 0.5 + + @property + def look_at(self): + return self.snapshot.configuration.box[:3] * -self.view_axis + + @property + def height(self): + return self._height + + @height.setter + def height(self, value): + self._height = value + + @property + def up(self): + return self._up + @up.setter + def up(self, value): + self._up = value + @property def snapshot(self): return self._snapshot @@ -71,5 +129,7 @@ def colors(self): return np.array([0.5, 0.25, 0.5]) def view(self): + self.scene.camera = self.camera + self.scene.geometry = [self.geometry] fresnel.preview(self.scene) From e8bf10bcf3425b8f323942933e68d635e402ba0f Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sat, 16 Sep 2023 12:44:57 -0600 Subject: [PATCH 03/15] add a bunch of properties and setters --- cmeutils/visualize.py | 159 ++++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 43 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 3dd0035..c1db6a7 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -9,29 +9,131 @@ def __init__( gsd_file, frame=0, color_dict=None, + diameter_scale=0.30, solid=0.1, roughness=0.3, specular=0.5, specular_trans=0, metal=0, - view_axis=(1, 0, 0) - ): + view_axis=(1, 0, 0), + height=10 + ): self.scene = fresnel.Scene() self.gsd_file = gsd_file self._snapshot = None self._frame = 0 self.frame = frame - self._height = 5 + self._height = height self.color_dict = color_dict + self._diameter_scale = diameter_scale # Set fresnel.material.Material attrs self.solid = solid - self.roughness = roughness - self.specular = specular - self.specular_trans = specular_trans - self.metal = metal + self._roughness = roughness + self._specular = specular + self._specular_trans = specular_trans + self._metal = metal # Set fresnel.camera attrs - self.view_axis = np.asarray(view_axis) + self._view_axis = np.asarray(view_axis) self._up = np.array([0, 0, 1]) + self.build_view() + + @property + def frame(self): + return self._frame + + @frame.setter + #TODO: Assert num frames + def frame(self, frame): + self._frame = frame + with gsd.hoomd.open(self.gsd_file) as f: + self._snapshot = f[frame] + + @property + def snapshot(self): + return self._snapshot + + @property + def diameter_scale(self): + return self._diameter_scale + + @diameter_scale.setter + def diameter_scale(self, value): + self._diameter_scale = value + + @property + def color_dict(self): + return self._color_dict + + @color_dict.setter + def color_dict(self, value): + self._color_dict = value + + def set_type_color(self, particle_type, color): + self._color_dict[particle_type] = color + + @property + def solid(self): + return self._solid + + @solid.setter + def solid(self, value): + self._solid = value + + @property + def roughness(self): + return self._roughness + + @roughness.setter + def roughness(self, value): + self._roughness = value + + @property + def specular(self): + return self._specular + + @specular.setter + def specular(self, value): + self._specular = value + + @property + def specular_trans(self): + return self._specular_trans + + @specular_trans.setter + def specular_trans(self, value): + self._specular_trans = value + + @property + def metal(self): + return self._metal + + @metal.setter + def metal(self, value): + self._metal = value + + @property + def view_axis(self): + return self._view_axis + + @view_axis.setter + def view_axis(self, value): + self._view_axis = np.asarray(value) + + @property + def up(self): + return self._up + + @up.setter + def up(self, value): + self._up = value + + @property + def height(self): + return self._height + + @height.setter + def height(self, value): + self._height = value @property def geometry(self): @@ -74,36 +176,6 @@ def camera_position(self): def look_at(self): return self.snapshot.configuration.box[:3] * -self.view_axis - @property - def height(self): - return self._height - - @height.setter - def height(self, value): - self._height = value - - @property - def up(self): - return self._up - - @up.setter - def up(self, value): - self._up = value - - @property - def snapshot(self): - return self._snapshot - - @property - def frame(self): - return self._frame - - @frame.setter - #TODO: Assert num frames - def frame(self, frame): - self._frame = frame - with gsd.hoomd.open(self.gsd_file) as f: - self._snapshot = f[frame] @property def positions(self): @@ -111,12 +183,15 @@ def positions(self): @property def radius(self): - return self.snapshot.particles.diameter / 2 + return self.snapshot.particles.diameter * self.diameter_scale @property def particle_types(self): return np.array( - [snapshot.particles.types[i] for i in snap.particles.typeid] + [ + self.snapshot.particles.types[i] for + i in self.snapshot.particles.typeid + ] ) @property @@ -128,8 +203,6 @@ def colors(self): else: return np.array([0.5, 0.25, 0.5]) - def view(self): + def build_view(self): self.scene.camera = self.camera self.scene.geometry = [self.geometry] - fresnel.preview(self.scene) - From fba9ae8d23484c8babf7ac2504d06022e36b81a4 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sat, 16 Sep 2023 16:21:16 -0600 Subject: [PATCH 04/15] allow to unwrap positions --- cmeutils/visualize.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index c1db6a7..950042a 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -16,7 +16,8 @@ def __init__( specular_trans=0, metal=0, view_axis=(1, 0, 0), - height=10 + height=10, + device=fresnel.Device() ): self.scene = fresnel.Scene() self.gsd_file = gsd_file @@ -26,6 +27,7 @@ def __init__( self._height = height self.color_dict = color_dict self._diameter_scale = diameter_scale + self._device = device # Set fresnel.material.Material attrs self.solid = solid self._roughness = roughness @@ -36,6 +38,7 @@ def __init__( self._view_axis = np.asarray(view_axis) self._up = np.array([0, 0, 1]) self.build_view() + self._unwrap_positions = False @property def frame(self): @@ -71,6 +74,14 @@ def color_dict(self, value): def set_type_color(self, particle_type, color): self._color_dict[particle_type] = color + @property + def unwrap_positions(self): + return self._unwrap_positions + + @unwrap_positions.setter + def unwrap_positions(self, value): + self._unwrap_positions = value + @property def solid(self): return self._solid @@ -179,7 +190,13 @@ def look_at(self): @property def positions(self): - return self.snapshot.particles.position + if self.unwrap_positions: + pos = self.snapshot.particles.position + imgs = self.snapshot.particles.image + box_lengths = self.snapshot.configuration.box[:3] + return pos + (imgs * box_lengths) + else: + return self.snapshot.particles.position @property def radius(self): From 4524d313d595abbcbf69d3a9670bca8039061937 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sat, 16 Sep 2023 23:44:16 -0600 Subject: [PATCH 05/15] add different view methods --- cmeutils/visualize.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 950042a..b8f48c2 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -20,6 +20,7 @@ def __init__( device=fresnel.Device() ): self.scene = fresnel.Scene() + self._unwrap_positions = False self.gsd_file = gsd_file self._snapshot = None self._frame = 0 @@ -37,8 +38,6 @@ def __init__( # Set fresnel.camera attrs self._view_axis = np.asarray(view_axis) self._up = np.array([0, 0, 1]) - self.build_view() - self._unwrap_positions = False @property def frame(self): @@ -187,7 +186,6 @@ def camera_position(self): def look_at(self): return self.snapshot.configuration.box[:3] * -self.view_axis - @property def positions(self): if self.unwrap_positions: @@ -220,6 +218,24 @@ def colors(self): else: return np.array([0.5, 0.25, 0.5]) - def build_view(self): + def view(self, width=300, height=300): + self.scene.camera = self.camera + self.scene.geometry = [self.geometry] + return fresnel.preview(scene=self.scene, w=width, h=height) + + def path_trace(self, width=300, height=300, samples=64, light_samples=1): + self.scene.camera = self.camera + self.scene.geometry = [self.geometry] + return fresnel.pathtrace( + scene=self.scene, + w=width, + h=height, + samples=samples, + light_samples=light_samples + ) + + def trace(self, width=300, height=300, n_samples=1): self.scene.camera = self.camera self.scene.geometry = [self.geometry] + tracer = fresnel.tracer.Preview(device=self.scene.device, w=width, h=height) + return tracer.render(self.scene) From 95f9d0b05e243ff820d68e5ec44e43457eb1a3a9 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sun, 17 Sep 2023 09:51:30 -0600 Subject: [PATCH 06/15] rearrange, remove property decorators from geometry, matl, camera --- cmeutils/visualize.py | 114 +++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 58 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index b8f48c2..0834368 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -5,37 +5,35 @@ class FresnelGSD: def __init__( - self, - gsd_file, - frame=0, - color_dict=None, - diameter_scale=0.30, - solid=0.1, - roughness=0.3, - specular=0.5, - specular_trans=0, - metal=0, - view_axis=(1, 0, 0), - height=10, - device=fresnel.Device() - ): + self, + gsd_file, + frame=0, + color_dict=None, + diameter_scale=0.30, + solid=0.1, + roughness=0.3, + specular=0.5, + specular_trans=0, + metal=0, + view_axis=(1, 0, 0), + height=10, + device=fresnel.Device() + ): self.scene = fresnel.Scene() - self._unwrap_positions = False self.gsd_file = gsd_file + self._unwrap_positions = False self._snapshot = None self._frame = 0 self.frame = frame self._height = height - self.color_dict = color_dict + self._color_dict = color_dict self._diameter_scale = diameter_scale self._device = device - # Set fresnel.material.Material attrs - self.solid = solid + self._solid = solid self._roughness = roughness self._specular = specular self._specular_trans = specular_trans self._metal = metal - # Set fresnel.camera attrs self._view_axis = np.asarray(view_axis) self._up = np.array([0, 0, 1]) @@ -79,6 +77,7 @@ def unwrap_positions(self): @unwrap_positions.setter def unwrap_positions(self, value): + #TODO assert is bool self._unwrap_positions = value @property @@ -127,6 +126,7 @@ def view_axis(self): @view_axis.setter def view_axis(self, value): + #TODO Assert is 1,3 array self._view_axis = np.asarray(value) @property @@ -145,39 +145,6 @@ def height(self): def height(self, value): self._height = value - @property - def geometry(self): - geometry = fresnel.geometry.Sphere( - scene=self.scene, - position=self.positions, - radius=self.radius, - color=fresnel.color.linear(self.colors), - ) - geometry.material = self.material - return geometry - - @property - def material(self): - material = fresnel.material.Material( - primitive_color_mix=1, - solid=self.solid, - roughness=self.roughness, - specular=self.specular, - spec_trans=self.specular_trans, - metal=self.metal - ) - return material - - @property - def camera(self): - camera=fresnel.camera.Orthographic( - position=self.camera_position, - look_at=self.look_at, - up=self.up, - height=self.height - ) - return camera - @property def camera_position(self): return (self.snapshot.configuration.box[:3] * self.view_axis) - 0.5 @@ -218,14 +185,45 @@ def colors(self): else: return np.array([0.5, 0.25, 0.5]) + def geometry(self): + geometry = fresnel.geometry.Sphere( + scene=self.scene, + position=self.positions, + radius=self.radius, + color=fresnel.color.linear(self.colors), + ) + geometry.material = self.material() + return geometry + + def material(self): + material = fresnel.material.Material( + primitive_color_mix=1, + solid=self.solid, + roughness=self.roughness, + specular=self.specular, + spec_trans=self.specular_trans, + metal=self.metal + ) + return material + + def camera(self): + camera=fresnel.camera.Orthographic( + position=self.camera_position, + look_at=self.look_at, + up=self.up, + height=self.height + ) + return camera + + def view(self, width=300, height=300): - self.scene.camera = self.camera - self.scene.geometry = [self.geometry] + self.scene.camera = self.camera() + self.scene.geometry = [self.geometry()] return fresnel.preview(scene=self.scene, w=width, h=height) def path_trace(self, width=300, height=300, samples=64, light_samples=1): - self.scene.camera = self.camera - self.scene.geometry = [self.geometry] + self.scene.camera = self.camera() + self.scene.geometry = [self.geometry()] return fresnel.pathtrace( scene=self.scene, w=width, @@ -235,7 +233,7 @@ def path_trace(self, width=300, height=300, samples=64, light_samples=1): ) def trace(self, width=300, height=300, n_samples=1): - self.scene.camera = self.camera - self.scene.geometry = [self.geometry] + self.scene.camera = self.camera() + self.scene.geometry = [self.geometry()] tracer = fresnel.tracer.Preview(device=self.scene.device, w=width, h=height) return tracer.render(self.scene) From 87c30c16c02d7e63db0ff8de2fb1984f7e6cc76c Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sun, 17 Sep 2023 19:06:55 -0600 Subject: [PATCH 07/15] add some checks and errors to the setters --- cmeutils/visualize.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 0834368..8f44e1a 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -21,6 +21,8 @@ def __init__( ): self.scene = fresnel.Scene() self.gsd_file = gsd_file + with gsd.hoomd.open(gsd_file) as traj: + self._n_frames = len(traj) self._unwrap_positions = False self._snapshot = None self._frame = 0 @@ -42,8 +44,11 @@ def frame(self): return self._frame @frame.setter - #TODO: Assert num frames def frame(self, frame): + if frame > self._n_frames - 1: + raise ValueError( + f"The GSD file only has {self._n_frames} frames." + ) self._frame = frame with gsd.hoomd.open(self.gsd_file) as f: self._snapshot = f[frame] @@ -66,9 +71,18 @@ def color_dict(self): @color_dict.setter def color_dict(self, value): + if not isinstance(value, dict): + raise ValueError( + "Pass in a dicitonary with " + "keys of particle type, values of color" + ) self._color_dict = value def set_type_color(self, particle_type, color): + if not particle_type in set(self.particle_types): + raise ValueError( + f"Particle type of {particle_type} is not in the Snapshot" + ) self._color_dict[particle_type] = color @property @@ -77,7 +91,11 @@ def unwrap_positions(self): @unwrap_positions.setter def unwrap_positions(self, value): - #TODO assert is bool + if not isinstance(value, bool): + raise ValueError( + "Set to True or False where " + "True uses unwrapped particle positions" + ) self._unwrap_positions = value @property From 656044f2974a453b0823f108e9b22de1a5544eaa Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 01:14:31 +0000 Subject: [PATCH 08/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cmeutils/visualize.py | 85 +++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 44 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 8f44e1a..996f709 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -17,7 +17,7 @@ def __init__( metal=0, view_axis=(1, 0, 0), height=10, - device=fresnel.Device() + device=fresnel.Device(), ): self.scene = fresnel.Scene() self.gsd_file = gsd_file @@ -25,9 +25,9 @@ def __init__( self._n_frames = len(traj) self._unwrap_positions = False self._snapshot = None - self._frame = 0 + self._frame = 0 self.frame = frame - self._height = height + self._height = height self._color_dict = color_dict self._diameter_scale = diameter_scale self._device = device @@ -46,9 +46,7 @@ def frame(self): @frame.setter def frame(self, frame): if frame > self._n_frames - 1: - raise ValueError( - f"The GSD file only has {self._n_frames} frames." - ) + raise ValueError(f"The GSD file only has {self._n_frames} frames.") self._frame = frame with gsd.hoomd.open(self.gsd_file) as f: self._snapshot = f[frame] @@ -73,15 +71,15 @@ def color_dict(self): def color_dict(self, value): if not isinstance(value, dict): raise ValueError( - "Pass in a dicitonary with " - "keys of particle type, values of color" + "Pass in a dicitonary with " + "keys of particle type, values of color" ) self._color_dict = value def set_type_color(self, particle_type, color): if not particle_type in set(self.particle_types): raise ValueError( - f"Particle type of {particle_type} is not in the Snapshot" + f"Particle type of {particle_type} is not in the Snapshot" ) self._color_dict[particle_type] = color @@ -95,7 +93,7 @@ def unwrap_positions(self, value): raise ValueError( "Set to True or False where " "True uses unwrapped particle positions" - ) + ) self._unwrap_positions = value @property @@ -144,7 +142,7 @@ def view_axis(self): @view_axis.setter def view_axis(self, value): - #TODO Assert is 1,3 array + # TODO Assert is 1,3 array self._view_axis = np.asarray(value) @property @@ -169,37 +167,35 @@ def camera_position(self): @property def look_at(self): - return self.snapshot.configuration.box[:3] * -self.view_axis + return self.snapshot.configuration.box[:3] * -self.view_axis @property def positions(self): if self.unwrap_positions: - pos = self.snapshot.particles.position - imgs = self.snapshot.particles.image - box_lengths = self.snapshot.configuration.box[:3] - return pos + (imgs * box_lengths) + pos = self.snapshot.particles.position + imgs = self.snapshot.particles.image + box_lengths = self.snapshot.configuration.box[:3] + return pos + (imgs * box_lengths) else: return self.snapshot.particles.position @property def radius(self): - return self.snapshot.particles.diameter * self.diameter_scale - + return self.snapshot.particles.diameter * self.diameter_scale + @property def particle_types(self): return np.array( - [ - self.snapshot.particles.types[i] for - i in self.snapshot.particles.typeid - ] + [ + self.snapshot.particles.types[i] + for i in self.snapshot.particles.typeid + ] ) @property def colors(self): if self.color_dict: - return np.array( - [self.color_dict[i] for i in self.particle_types] - ) + return np.array([self.color_dict[i] for i in self.particle_types]) else: return np.array([0.5, 0.25, 0.5]) @@ -215,43 +211,44 @@ def geometry(self): def material(self): material = fresnel.material.Material( - primitive_color_mix=1, - solid=self.solid, - roughness=self.roughness, - specular=self.specular, - spec_trans=self.specular_trans, - metal=self.metal + primitive_color_mix=1, + solid=self.solid, + roughness=self.roughness, + specular=self.specular, + spec_trans=self.specular_trans, + metal=self.metal, ) return material def camera(self): - camera=fresnel.camera.Orthographic( - position=self.camera_position, - look_at=self.look_at, - up=self.up, - height=self.height + camera = fresnel.camera.Orthographic( + position=self.camera_position, + look_at=self.look_at, + up=self.up, + height=self.height, ) return camera - def view(self, width=300, height=300): self.scene.camera = self.camera() self.scene.geometry = [self.geometry()] return fresnel.preview(scene=self.scene, w=width, h=height) - + def path_trace(self, width=300, height=300, samples=64, light_samples=1): self.scene.camera = self.camera() self.scene.geometry = [self.geometry()] return fresnel.pathtrace( - scene=self.scene, - w=width, - h=height, - samples=samples, - light_samples=light_samples + scene=self.scene, + w=width, + h=height, + samples=samples, + light_samples=light_samples, ) def trace(self, width=300, height=300, n_samples=1): self.scene.camera = self.camera() self.scene.geometry = [self.geometry()] - tracer = fresnel.tracer.Preview(device=self.scene.device, w=width, h=height) + tracer = fresnel.tracer.Preview( + device=self.scene.device, w=width, h=height + ) return tracer.render(self.scene) From c6806ae37fb3f91796df6aba6777eb7cefae4640 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sun, 17 Sep 2023 22:46:31 -0600 Subject: [PATCH 09/15] add some unit tests, fix a couple init parameters --- cmeutils/tests/base_test.py | 6 ++ cmeutils/tests/test_visualize.py | 100 +++++++++++++++++++++++++++++++ cmeutils/visualize.py | 6 +- 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 cmeutils/tests/test_visualize.py diff --git a/cmeutils/tests/base_test.py b/cmeutils/tests/base_test.py index 826e1c9..9551568 100644 --- a/cmeutils/tests/base_test.py +++ b/cmeutils/tests/base_test.py @@ -5,6 +5,8 @@ import pytest from pymbar.testsystems import correlated_timeseries_example +from cmeutils.visualize import FresnelGSD + asset_dir = path.join(path.dirname(__file__), "assets") @@ -63,6 +65,10 @@ def p3ht_xml(self): def correlated_data_tau100_n10000(self): return correlated_timeseries_example(N=10000, tau=100, seed=432) + @pytest.fixture + def p3ht_fresnel(self): + return FresnelGSD(gsd_file=path.join(asset_dir, "p3ht.gsd")) + def create_frame(i, add_bonds, images, seed=42): np.random.seed(seed) diff --git a/cmeutils/tests/test_visualize.py b/cmeutils/tests/test_visualize.py new file mode 100644 index 0000000..516fcfa --- /dev/null +++ b/cmeutils/tests/test_visualize.py @@ -0,0 +1,100 @@ +import numpy as np +import pytest + +from cmeutils.visualize import FresnelGSD +from cmeutils.tests.base_test import BaseTest + + +class TestFresnelGSD(BaseTest): + def test_view(self, p3ht_fresnel): + p3ht_fresnel.view() + + def test_path_frace(self, p3ht_fresnel): + p3ht_fresnel.path_trace(samples=10, light_samples=1) + + def test_frace(self, p3ht_fresnel): + p3ht_fresnel.trace() + + def test_scale_diameter(self, p3ht_fresnel): + p3ht_fresnel.diameter_scale = 0.6 + assert p3ht_fresnel.diameter_scale == 0.6 + assert np.array_equal(p3ht_fresnel.radius, np.ones_like(p3ht_fresnel.radius)*0.60) + + def test_update_snapshot(self, gsdfile): + test_fresnel = FresnelGSD(gsd_file=gsdfile) + snap = test_fresnel.snapshot + positions = test_fresnel.positions + test_fresnel.frame = 2 + snap2 = test_fresnel.snapshot + positions2 = test_fresnel.positions + assert test_fresnel.frame == 2 + assert snap is not snap2 + + def test_color_dict(self, p3ht_fresnel): + p3ht_fresnel.color_dict = { + "c3": np.array([0.5, 0.5, 0.5]), + "cc": np.array([0.5, 0.5, 0.5]), + "cd": np.array([0.5, 0.5, 0.5]), + "h4": np.array([0.5, 0.5, 0.5]), + "ha": np.array([0.5, 0.5, 0.5]), + "hc": np.array([0.5, 0.5, 0.5]), + "ss": np.array([0.5, 0.5, 0.5]), + } + p3ht_fresnel.set_type_color(particle_type="c3", color=(0.1, 0.1, 0.1)) + assert np.array_equal(p3ht_fresnel.color_dict["c3"], np.array([0.1, 0.1, 0.1])) + + def test_set_color_no_type(self, p3ht_fresnel): + with pytest.raises(ValueError): + p3ht_fresnel.set_type_color("ca", (0.1, 0.1, 0.1)) + + def test_set_bad_frame(self, p3ht_fresnel): + with pytest.raises(ValueError): + p3ht_fresnel.frame = 10 + + def test_solid(self, p3ht_fresnel): + p3ht_fresnel.solid = 0.5 + assert p3ht_fresnel.solid == 0.5 + material = p3ht_fresnel.material() + assert material.solid == 0.5 + + def test_roughness(self, p3ht_fresnel): + p3ht_fresnel.roughness = 0.5 + assert p3ht_fresnel.roughness == 0.5 + material = p3ht_fresnel.material() + assert material.roughness == 0.5 + + def test_specular(self, p3ht_fresnel): + p3ht_fresnel.specular = 0.5 + assert p3ht_fresnel.specular == 0.5 + material = p3ht_fresnel.material() + assert material.specular == 0.5 + + def test_specular_trans(self, p3ht_fresnel): + p3ht_fresnel.specular_trans = 0.5 + assert p3ht_fresnel.specular_trans == 0.5 + material = p3ht_fresnel.material() + assert material.spec_trans == 0.5 + + def test_metal(self, p3ht_fresnel): + p3ht_fresnel.metal = 0.5 + assert p3ht_fresnel.metal == 0.5 + material = p3ht_fresnel.material() + assert material.metal == 0.5 + + def test_geometry(self, p3ht_fresnel): + geometry = p3ht_fresnel.geometry() + for i, j in zip(p3ht_fresnel.positions, geometry.position): + assert np.array_equal(i, j) + for i, j in zip(p3ht_fresnel.radius, geometry.radius): + assert i == j + + def test_height(self, p3ht_fresnel): + p3ht_fresnel.height = 5 + assert p3ht_fresnel.height == 5 + camera = p3ht_fresnel.camera() + assert camera.height == 5 + + def test_up(self, p3ht_fresnel): + p3ht_fresnel.up = np.array([1, 0, 0]) + camera = p3ht_fresnel.camera() + assert np.array_equal(camera.up, np.array([1, 0, 0])) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 8f44e1a..fb95cd7 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -17,13 +17,15 @@ def __init__( metal=0, view_axis=(1, 0, 0), height=10, + up=(0, 0, 1), + unwrap_positions=False, device=fresnel.Device() ): self.scene = fresnel.Scene() self.gsd_file = gsd_file with gsd.hoomd.open(gsd_file) as traj: self._n_frames = len(traj) - self._unwrap_positions = False + self._unwrap_positions = unwrap_positions self._snapshot = None self._frame = 0 self.frame = frame @@ -37,7 +39,7 @@ def __init__( self._specular_trans = specular_trans self._metal = metal self._view_axis = np.asarray(view_axis) - self._up = np.array([0, 0, 1]) + self._up = np.asarray(up) @property def frame(self): From a203eb12a24da1874a20266c93df310aecbfc107 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Sep 2023 04:47:12 +0000 Subject: [PATCH 10/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cmeutils/tests/test_visualize.py | 30 +++++++++++++++++------------- cmeutils/visualize.py | 6 +++--- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cmeutils/tests/test_visualize.py b/cmeutils/tests/test_visualize.py index 516fcfa..e799125 100644 --- a/cmeutils/tests/test_visualize.py +++ b/cmeutils/tests/test_visualize.py @@ -1,8 +1,8 @@ import numpy as np import pytest -from cmeutils.visualize import FresnelGSD from cmeutils.tests.base_test import BaseTest +from cmeutils.visualize import FresnelGSD class TestFresnelGSD(BaseTest): @@ -18,7 +18,9 @@ def test_frace(self, p3ht_fresnel): def test_scale_diameter(self, p3ht_fresnel): p3ht_fresnel.diameter_scale = 0.6 assert p3ht_fresnel.diameter_scale == 0.6 - assert np.array_equal(p3ht_fresnel.radius, np.ones_like(p3ht_fresnel.radius)*0.60) + assert np.array_equal( + p3ht_fresnel.radius, np.ones_like(p3ht_fresnel.radius) * 0.60 + ) def test_update_snapshot(self, gsdfile): test_fresnel = FresnelGSD(gsd_file=gsdfile) @@ -32,16 +34,18 @@ def test_update_snapshot(self, gsdfile): def test_color_dict(self, p3ht_fresnel): p3ht_fresnel.color_dict = { - "c3": np.array([0.5, 0.5, 0.5]), - "cc": np.array([0.5, 0.5, 0.5]), - "cd": np.array([0.5, 0.5, 0.5]), - "h4": np.array([0.5, 0.5, 0.5]), - "ha": np.array([0.5, 0.5, 0.5]), - "hc": np.array([0.5, 0.5, 0.5]), - "ss": np.array([0.5, 0.5, 0.5]), + "c3": np.array([0.5, 0.5, 0.5]), + "cc": np.array([0.5, 0.5, 0.5]), + "cd": np.array([0.5, 0.5, 0.5]), + "h4": np.array([0.5, 0.5, 0.5]), + "ha": np.array([0.5, 0.5, 0.5]), + "hc": np.array([0.5, 0.5, 0.5]), + "ss": np.array([0.5, 0.5, 0.5]), } p3ht_fresnel.set_type_color(particle_type="c3", color=(0.1, 0.1, 0.1)) - assert np.array_equal(p3ht_fresnel.color_dict["c3"], np.array([0.1, 0.1, 0.1])) + assert np.array_equal( + p3ht_fresnel.color_dict["c3"], np.array([0.1, 0.1, 0.1]) + ) def test_set_color_no_type(self, p3ht_fresnel): with pytest.raises(ValueError): @@ -68,19 +72,19 @@ def test_specular(self, p3ht_fresnel): assert p3ht_fresnel.specular == 0.5 material = p3ht_fresnel.material() assert material.specular == 0.5 - + def test_specular_trans(self, p3ht_fresnel): p3ht_fresnel.specular_trans = 0.5 assert p3ht_fresnel.specular_trans == 0.5 material = p3ht_fresnel.material() assert material.spec_trans == 0.5 - + def test_metal(self, p3ht_fresnel): p3ht_fresnel.metal = 0.5 assert p3ht_fresnel.metal == 0.5 material = p3ht_fresnel.material() assert material.metal == 0.5 - + def test_geometry(self, p3ht_fresnel): geometry = p3ht_fresnel.geometry() for i, j in zip(p3ht_fresnel.positions, geometry.position): diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 1f5d303..525a4e9 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -19,13 +19,13 @@ def __init__( height=10, up=(0, 0, 1), unwrap_positions=False, - device=fresnel.Device() + device=fresnel.Device(), ): self.scene = fresnel.Scene() self.gsd_file = gsd_file with gsd.hoomd.open(gsd_file) as traj: self._n_frames = len(traj) - self._unwrap_positions = unwrap_positions + self._unwrap_positions = unwrap_positions self._snapshot = None self._frame = 0 self.frame = frame @@ -39,7 +39,7 @@ def __init__( self._specular_trans = specular_trans self._metal = metal self._view_axis = np.asarray(view_axis) - self._up = np.asarray(up) + self._up = np.asarray(up) @property def frame(self): From 2ae3a3fb545c9227035e96306d97f17bfeab2c71 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sun, 17 Sep 2023 23:01:43 -0600 Subject: [PATCH 11/15] add more unit tests --- cmeutils/tests/test_visualize.py | 52 +++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/cmeutils/tests/test_visualize.py b/cmeutils/tests/test_visualize.py index 516fcfa..e113e1c 100644 --- a/cmeutils/tests/test_visualize.py +++ b/cmeutils/tests/test_visualize.py @@ -1,8 +1,8 @@ import numpy as np import pytest -from cmeutils.visualize import FresnelGSD from cmeutils.tests.base_test import BaseTest +from cmeutils.visualize import FresnelGSD class TestFresnelGSD(BaseTest): @@ -18,30 +18,33 @@ def test_frace(self, p3ht_fresnel): def test_scale_diameter(self, p3ht_fresnel): p3ht_fresnel.diameter_scale = 0.6 assert p3ht_fresnel.diameter_scale == 0.6 - assert np.array_equal(p3ht_fresnel.radius, np.ones_like(p3ht_fresnel.radius)*0.60) + assert np.array_equal( + p3ht_fresnel.radius, np.ones_like(p3ht_fresnel.radius) * 0.60 + ) def test_update_snapshot(self, gsdfile): test_fresnel = FresnelGSD(gsd_file=gsdfile) snap = test_fresnel.snapshot - positions = test_fresnel.positions test_fresnel.frame = 2 snap2 = test_fresnel.snapshot - positions2 = test_fresnel.positions assert test_fresnel.frame == 2 assert snap is not snap2 def test_color_dict(self, p3ht_fresnel): p3ht_fresnel.color_dict = { - "c3": np.array([0.5, 0.5, 0.5]), - "cc": np.array([0.5, 0.5, 0.5]), - "cd": np.array([0.5, 0.5, 0.5]), - "h4": np.array([0.5, 0.5, 0.5]), - "ha": np.array([0.5, 0.5, 0.5]), - "hc": np.array([0.5, 0.5, 0.5]), - "ss": np.array([0.5, 0.5, 0.5]), + "c3": np.array([0.5, 0.5, 0.5]), + "cc": np.array([0.5, 0.5, 0.5]), + "cd": np.array([0.5, 0.5, 0.5]), + "h4": np.array([0.5, 0.5, 0.5]), + "ha": np.array([0.5, 0.5, 0.5]), + "hc": np.array([0.5, 0.5, 0.5]), + "ss": np.array([0.5, 0.5, 0.5]), } p3ht_fresnel.set_type_color(particle_type="c3", color=(0.1, 0.1, 0.1)) - assert np.array_equal(p3ht_fresnel.color_dict["c3"], np.array([0.1, 0.1, 0.1])) + assert np.array_equal( + p3ht_fresnel.color_dict["c3"], np.array([0.1, 0.1, 0.1]) + ) + p3ht_fresnel.view() def test_set_color_no_type(self, p3ht_fresnel): with pytest.raises(ValueError): @@ -51,6 +54,25 @@ def test_set_bad_frame(self, p3ht_fresnel): with pytest.raises(ValueError): p3ht_fresnel.frame = 10 + def test_bad_color_dict(self, p3ht_fresnel): + with pytest.raises(ValueError): + p3ht_fresnel.color_dict = np.array([0.1, 0.1, 0.1]) + + def test_set_bad_unwrap_pos(self, p3ht_fresnel): + with pytest.raises(ValueError): + p3ht_fresnel.unwrap_positions = "true" + + def test_unwrap_positions(self, p3ht_fresnel): + assert p3ht_fresnel.unwrap_positions is False + p3ht_fresnel.unwrap_positions = True + assert p3ht_fresnel.unwrap_positions is True + + def test_view_axis(self, p3ht_fresnel): + p3ht_fresnel.view_axis = (1, 1, 1) + assert np.array_equal(np.array([1, 1, 1]), p3ht_fresnel.view_axis) + p3ht_fresnel.view_axis = [0, 1, 1] + assert np.array_equal(np.array([0, 1, 1]), p3ht_fresnel.view_axis) + def test_solid(self, p3ht_fresnel): p3ht_fresnel.solid = 0.5 assert p3ht_fresnel.solid == 0.5 @@ -68,19 +90,19 @@ def test_specular(self, p3ht_fresnel): assert p3ht_fresnel.specular == 0.5 material = p3ht_fresnel.material() assert material.specular == 0.5 - + def test_specular_trans(self, p3ht_fresnel): p3ht_fresnel.specular_trans = 0.5 assert p3ht_fresnel.specular_trans == 0.5 material = p3ht_fresnel.material() assert material.spec_trans == 0.5 - + def test_metal(self, p3ht_fresnel): p3ht_fresnel.metal = 0.5 assert p3ht_fresnel.metal == 0.5 material = p3ht_fresnel.material() assert material.metal == 0.5 - + def test_geometry(self, p3ht_fresnel): geometry = p3ht_fresnel.geometry() for i, j in zip(p3ht_fresnel.positions, geometry.position): From 654ab42bc58116dae6d59a2f6098d44c0594a325 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Sun, 17 Sep 2023 23:04:11 -0600 Subject: [PATCH 12/15] fix conditional --- cmeutils/visualize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 525a4e9..228cfa3 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -79,7 +79,7 @@ def color_dict(self, value): self._color_dict = value def set_type_color(self, particle_type, color): - if not particle_type in set(self.particle_types): + if particle_type not in set(self.particle_types): raise ValueError( f"Particle type of {particle_type} is not in the Snapshot" ) From 2a2290992abe50358d57386421163d5bd53c2b4b Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Mon, 18 Sep 2023 00:47:32 -0600 Subject: [PATCH 13/15] add doc strings, fix test name --- cmeutils/tests/test_visualize.py | 5 +- cmeutils/visualize.py | 91 ++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/cmeutils/tests/test_visualize.py b/cmeutils/tests/test_visualize.py index e113e1c..f0374a9 100644 --- a/cmeutils/tests/test_visualize.py +++ b/cmeutils/tests/test_visualize.py @@ -9,12 +9,9 @@ class TestFresnelGSD(BaseTest): def test_view(self, p3ht_fresnel): p3ht_fresnel.view() - def test_path_frace(self, p3ht_fresnel): + def test_path_trace(self, p3ht_fresnel): p3ht_fresnel.path_trace(samples=10, light_samples=1) - def test_frace(self, p3ht_fresnel): - p3ht_fresnel.trace() - def test_scale_diameter(self, p3ht_fresnel): p3ht_fresnel.diameter_scale = 0.6 assert p3ht_fresnel.diameter_scale == 0.6 diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 228cfa3..c62cee0 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -10,7 +10,7 @@ def __init__( frame=0, color_dict=None, diameter_scale=0.30, - solid=0.1, + solid=0, roughness=0.3, specular=0.5, specular_trans=0, @@ -43,6 +43,9 @@ def __init__( @property def frame(self): + """The frame of the GSD trajectory to use. + The frame determines the particle positions usedin the image. + """ return self._frame @frame.setter @@ -55,10 +58,14 @@ def frame(self, frame): @property def snapshot(self): + """gsd.hoomd.Snapshot loaded from the GSD file. + The snapshot loaded depends on FresnelGSD.frame + """ return self._snapshot @property def diameter_scale(self): + """Scales the snapshot diameter values to set FresnelGSD.radius""" return self._diameter_scale @diameter_scale.setter @@ -67,6 +74,7 @@ def diameter_scale(self, value): @property def color_dict(self): + """Dictionary of key: particle type value: color""" return self._color_dict @color_dict.setter @@ -79,6 +87,16 @@ def color_dict(self, value): self._color_dict = value def set_type_color(self, particle_type, color): + """Set colors for particle types one at a time + + Parameters + ---------- + particle_type : str; required + The particle type found in FresnelGSD.particle_types + or FresnelGSD.snapshot.particles.types + color : np.ndarray, shape=(3,), required + sRGB color of (red, green, blue) values + """ if particle_type not in set(self.particle_types): raise ValueError( f"Particle type of {particle_type} is not in the Snapshot" @@ -87,6 +105,12 @@ def set_type_color(self, particle_type, color): @property def unwrap_positions(self): + """If set to True, then positions of the particles are + unwrapped before creating the image. + This requires that the GSD file snapshots contain accurate + image values (gsd.hoomd.Snapshot.particles.image + + """ return self._unwrap_positions @unwrap_positions.setter @@ -100,6 +124,7 @@ def unwrap_positions(self, value): @property def solid(self): + """Set to 1 to use solid colors regardless of light and angle""" return self._solid @solid.setter @@ -108,6 +133,7 @@ def solid(self, value): @property def roughness(self): + """Sets the material roughness (ranges from 0.1 to 1)""" return self._roughness @roughness.setter @@ -116,6 +142,9 @@ def roughness(self, value): @property def specular(self): + """Determines the strength of the specular highlights + (ranges from 0 to 1) + """ return self._specular @specular.setter @@ -124,6 +153,9 @@ def specular(self, value): @property def specular_trans(self): + """Determines the magnitude of specular light transmission + (ranges from 0 to 1) + """ return self._specular_trans @specular_trans.setter @@ -132,6 +164,9 @@ def specular_trans(self, value): @property def metal(self): + """Set to 0 for dielectric material or 1 for metal + (ranges from 0 to 1) + """ return self._metal @metal.setter @@ -140,6 +175,7 @@ def metal(self, value): @property def view_axis(self): + """Sets the direction and position of the camera""" return self._view_axis @view_axis.setter @@ -149,6 +185,7 @@ def view_axis(self, value): @property def up(self): + """Determines which direction is up""" return self._up @up.setter @@ -157,6 +194,7 @@ def up(self, value): @property def height(self): + """Acts like a zoom. Larger values zoom out, smaller vaues zoom in""" return self._height @height.setter @@ -165,14 +203,22 @@ def height(self, value): @property def camera_position(self): + """The camera position. + Determined from box dimensions are FresnelGSD.view_axis""" return (self.snapshot.configuration.box[:3] * self.view_axis) - 0.5 @property def look_at(self): + """The direction the camera is facing. + By default, uses position directly opposite of camera position + """ return self.snapshot.configuration.box[:3] * -self.view_axis @property def positions(self): + """Particle positions used in the image. + Determined by FresnelGSD.frame + """ if self.unwrap_positions: pos = self.snapshot.particles.position imgs = self.snapshot.particles.image @@ -183,10 +229,15 @@ def positions(self): @property def radius(self): + """Sets the size of the particles. + Determined by the gsd.hoomd.Snapshot.particles.diameter + values and FresnelGSD.diameter_scale + """ return self.snapshot.particles.diameter * self.diameter_scale @property def particle_types(self): + """Array of particle types of length number of particles""" return np.array( [ self.snapshot.particles.types[i] @@ -196,12 +247,16 @@ def particle_types(self): @property def colors(self): + """Generates the colors by particle type, + or sets a default of (0.5, 0.25, 0.5) + """ if self.color_dict: return np.array([self.color_dict[i] for i in self.particle_types]) else: return np.array([0.5, 0.25, 0.5]) def geometry(self): + """Creates and returns a fresnel.geometry.Sphere object""" geometry = fresnel.geometry.Sphere( scene=self.scene, position=self.positions, @@ -212,6 +267,7 @@ def geometry(self): return geometry def material(self): + """Creates and returns a fresnel.material.Material object""" material = fresnel.material.Material( primitive_color_mix=1, solid=self.solid, @@ -223,6 +279,7 @@ def material(self): return material def camera(self): + """Creates and returns a fresnel.camera.Orthographic object""" camera = fresnel.camera.Orthographic( position=self.camera_position, look_at=self.look_at, @@ -232,11 +289,35 @@ def camera(self): return camera def view(self, width=300, height=300): + """Creates an image using fresnel.preview + + Parameters + ---------- + width : int, optional, default 300 + Image width size in pixels + height : int, optional, default 300 + Image height size in pixels + + """ self.scene.camera = self.camera() self.scene.geometry = [self.geometry()] return fresnel.preview(scene=self.scene, w=width, h=height) def path_trace(self, width=300, height=300, samples=64, light_samples=1): + """Creates an image using fresnel.pathtrace + + Parameters + ---------- + width : int, optional, default 300 + Image width size in pixels + height : int, optional, default 300 + Image height size in pixels + samples : int, optional, default 64 + The number of times to sample pixels in the scene + light_samples : int, optional, default=1 + The number of light samples for each pixel sample + + """ self.scene.camera = self.camera() self.scene.geometry = [self.geometry()] return fresnel.pathtrace( @@ -246,11 +327,3 @@ def path_trace(self, width=300, height=300, samples=64, light_samples=1): samples=samples, light_samples=light_samples, ) - - def trace(self, width=300, height=300, n_samples=1): - self.scene.camera = self.camera() - self.scene.geometry = [self.geometry()] - tracer = fresnel.tracer.Preview( - device=self.scene.device, w=width, h=height - ) - return tracer.render(self.scene) From d4eecdb2cb32b3602980d6e889536743e64c3e35 Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Mon, 18 Sep 2023 08:29:10 -0600 Subject: [PATCH 14/15] add more doc strings --- cmeutils/visualize.py | 53 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index c62cee0..73ec5a2 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -8,19 +8,63 @@ def __init__( self, gsd_file, frame=0, + view_axis=(1, 0, 0), color_dict=None, diameter_scale=0.30, + height=10, solid=0, roughness=0.3, specular=0.5, specular_trans=0, metal=0, - view_axis=(1, 0, 0), - height=10, up=(0, 0, 1), unwrap_positions=False, device=fresnel.Device(), ): + """A wrapper class that automatically creates the Fresnel objects + needed to view snapshots from a GSD file. + + Parameters + ---------- + gsd_file : str, required + Path to a GSD file to load + frame : int, optional, default 0 + The frame of the GSD file to load the gsd.hoomd.Snapshot + view_axis : np.ndarray (3,), optional, default (1, 0, 0) + Sets the fresnel.camera attributes of camrea position and direction + color_dict : dict, optional, default None + Set colors for particle types + diameter_scale : float, optional default 0.30 + Scale the diameter values stored in gsd.hoomd.Snapshot + height : float, optional default 10 + Sets the fresnel.camera height attriubute + Acts like a zoom where larger values zooms out + solid : float, optional default 0 + fresnel.material.Material attribute. + Sets solid colors regardless of light and angle + roughness : float, optional default 0.3 + fresnel.material.Material attribute. + Sets the material roughness + specular : float, optional, default 0.5 + fresnel.material.Material attribute. + Sets the strength of specular highlights + specular_trans : float, optional, default 0 + fresnel.material.Material attribute. + Sets magnitude of specular light transmission + metal : float, optional, default 0 + fresnel.material.Material attribute. + Sets the dielectric or metal property value of the particles. + up : np.ndarray (3,), optional, default (0, 0, 1) + fresnel.camera attriubute + Determines which direction is considered up + upwrap_positions: bool, optional, default False + If True, the particle positions are unwrapped in the image + This requires the GSD file snapshot contain accurate values for + gsd.hoomd.Snapshot.particles.image + device, fresnel.Device(), optional + Set the device to be used by the scene and in rendering. + + """ self.scene = fresnel.Scene() self.gsd_file = gsd_file with gsd.hoomd.open(gsd_file) as traj: @@ -181,7 +225,10 @@ def view_axis(self): @view_axis.setter def view_axis(self, value): # TODO Assert is 1,3 array - self._view_axis = np.asarray(value) + new_view_axis = np.asarray(value) + if len(new_view_axis) != 0: + raise ValueError("View axis must be a 3x1 array") + self._view_axis = np.asarray(new_view_axis) @property def up(self): From 749ca98a43a3dcf6f699a3eaf3e5aabbbb81096c Mon Sep 17 00:00:00 2001 From: chrisjonesbsu Date: Mon, 18 Sep 2023 08:33:11 -0600 Subject: [PATCH 15/15] unit test for bad view axis attr --- cmeutils/tests/test_visualize.py | 4 ++++ cmeutils/visualize.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cmeutils/tests/test_visualize.py b/cmeutils/tests/test_visualize.py index f0374a9..650d8df 100644 --- a/cmeutils/tests/test_visualize.py +++ b/cmeutils/tests/test_visualize.py @@ -51,6 +51,10 @@ def test_set_bad_frame(self, p3ht_fresnel): with pytest.raises(ValueError): p3ht_fresnel.frame = 10 + def test_set_bad_view(self, p3ht_fresnel): + with pytest.raises(ValueError): + p3ht_fresnel.view_axis = 10 + def test_bad_color_dict(self, p3ht_fresnel): with pytest.raises(ValueError): p3ht_fresnel.color_dict = np.array([0.1, 0.1, 0.1]) diff --git a/cmeutils/visualize.py b/cmeutils/visualize.py index 73ec5a2..a128886 100644 --- a/cmeutils/visualize.py +++ b/cmeutils/visualize.py @@ -226,7 +226,7 @@ def view_axis(self): def view_axis(self, value): # TODO Assert is 1,3 array new_view_axis = np.asarray(value) - if len(new_view_axis) != 0: + if new_view_axis.shape != (3,): raise ValueError("View axis must be a 3x1 array") self._view_axis = np.asarray(new_view_axis)