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

Visualizer bugfixes #4686

Merged
merged 6 commits into from
Mar 10, 2023
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 doc/sphinx/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ To compile |es| on Ubuntu 22.04 LTS, install the following dependencies:

sudo apt install build-essential cmake cython3 python3-pip python3-numpy \
libboost-all-dev openmpi-common fftw3-dev libhdf5-dev libhdf5-openmpi-dev \
python3-scipy python3-opengl libgsl-dev
python3-scipy python3-opengl libgsl-dev freeglut3

Optionally the ccmake utility can be installed for easier configuration:

Expand Down
6 changes: 4 additions & 2 deletions src/core/bond_breakage/bond_breakage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ void clear_queue() { queue.clear(); }
/** @brief Gathers combined queue from all mpi ranks */
Queue gather_global_queue(Queue const &local_queue) {
Queue res = local_queue;
Utils::Mpi::gather_buffer(res, comm_cart);
boost::mpi::broadcast(comm_cart, res, 0);
if (comm_cart.size() > 1) {
Utils::Mpi::gather_buffer(res, comm_cart);
boost::mpi::broadcast(comm_cart, res, 0);
}
return res;
}

Expand Down
7 changes: 4 additions & 3 deletions src/core/collision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,10 @@ void glue_to_surface_bind_part_to_vs(const Particle *const p1,

std::vector<CollisionPair> gather_global_collision_queue() {
std::vector<CollisionPair> res = local_collision_queue;
Utils::Mpi::gather_buffer(res, comm_cart);
boost::mpi::broadcast(comm_cart, res, 0);

if (comm_cart.size() > 1) {
Utils::Mpi::gather_buffer(res, comm_cart);
boost::mpi::broadcast(comm_cart, res, 0);
}
return res;
}

Expand Down
85 changes: 38 additions & 47 deletions src/python/espressomd/visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,17 +590,9 @@ def screenshot(self, path):

# read the pixels
OpenGL.GL.glReadBuffer(OpenGL.GL.GL_COLOR_ATTACHMENT0)
data = OpenGL.GL.glReadPixels(
0,
0,
self.specs['window_size'][0],
self.specs['window_size'][1],
OpenGL.GL.GL_RGB,
OpenGL.GL.GL_FLOAT)

# save image
data = np.flipud(data.reshape((data.shape[1], data.shape[0], 3)))
matplotlib.pyplot.imsave(path, data)
self._make_screenshot(path)

def run(self, integration_steps=1):
"""Convenience method with a simple integration thread.
Expand Down Expand Up @@ -1005,14 +997,12 @@ def _draw_constraints(self):

def _determine_radius(self, part_type):
def radius_by_lj(part_type):
try:
radius = self.system.non_bonded_inter[part_type, part_type].lennard_jones.get_params()[
'sigma'] * 0.5
if radius == 0.0:
radius = self.system.non_bonded_inter[part_type, part_type].wca.get_params()[
'sigma'] * 0.5
except Exception:
radius = 0.5
ia = self.system.non_bonded_inter[part_type, part_type]
radius = 0.5
if hasattr(ia, "lennard_jones"):
radius = ia.lennard_jones.sigma * 0.5
if radius == 0.0 and hasattr(ia, "wca"):
radius = ia.wca.sigma * 0.5
if radius == 0.0:
radius = 0.5
return radius
Expand All @@ -1039,8 +1029,9 @@ def _draw_system_particles(self, color_by_id=False):

# Only change material if type/charge has changed, color_by_id or
# material was reset by arrows
if reset_material or color_by_id or not part_type == part_type_last or \
part_id == self.drag_id or part_id == self.info_id or self.specs['particle_coloring'] == 'node':
if reset_material or color_by_id or part_type != part_type_last or \
part_id == self.drag_id or part_id == self.info_id or \
self.specs['particle_coloring'] == 'node':
reset_material = False

radius = self._determine_radius(part_type)
Expand Down Expand Up @@ -1072,6 +1063,9 @@ def _draw_system_particles(self, color_by_id=False):
elif self.specs['particle_coloring'] == 'node':
color = self._modulo_indexing(
self.specs['particle_type_colors'], self.particles['node'][index])
else:
raise ValueError(
f"Cannot process particle_coloring={self.specs['particle_coloring']}")

# Invert color of highlighted particle
if part_id == self.drag_id or part_id == self.info_id:
Expand Down Expand Up @@ -1118,33 +1112,37 @@ def _draw_system_particles(self, color_by_id=False):
self._draw_arrow_property(
part_id, part_type, self.specs['velocity_arrows_type_scale'],
self.specs['velocity_arrows_type_colors'],
self.specs['velocity_arrows_type_materials'],
self.specs['velocity_arrows_type_radii'], 'velocity')
reset_material = True

if self.specs['force_arrows']:
self._draw_arrow_property(
part_id, part_type, self.specs['force_arrows_type_scale'],
self.specs['force_arrows_type_colors'],
self.specs['force_arrows_type_materials'],
self.specs['force_arrows_type_radii'], 'force')
reset_material = True

if self.specs['director_arrows']:
self._draw_arrow_property(
part_id, part_type, self.specs['director_arrows_type_scale'],
self.specs['director_arrows_type_colors'],
self.specs['director_arrows_type_materials'],
self.specs['director_arrows_type_radii'], 'director')
reset_material = True

def _draw_arrow_property(self, part_id, part_type,
type_scale, type_colors, type_radii, prop):
def _draw_arrow_property(self, part_id, part_type, type_scale,
type_colors, type_materials, type_radii, prop):
sc = self._modulo_indexing(type_scale, part_type)
if sc > 0:
v = self.particles[prop][self.index_from_id[part_id]]
col = self._modulo_indexing(type_colors, part_type)
radius = self._modulo_indexing(type_radii, part_type)
material = self._modulo_indexing(type_materials, part_type)
draw_arrow(self.particles['pos'][self.index_from_id[part_id]],
np.array(v, dtype=float) * sc, radius, col,
self.materials['chrome'], self.specs['quality_arrows'])
self.materials[material], self.specs['quality_arrows'])

def _draw_bonds(self):
half_box_l = self.system.box_l / 2.0
Expand All @@ -1161,8 +1159,9 @@ def _draw_bonds(self):
try:
x_a = self.particles['pos'][self.index_from_id[b[0]]]
x_b = self.particles['pos'][self.index_from_id[b[1]]]
except BaseException:
pass
except Exception:
# skip this bond
continue
dx = x_b - x_a

if np.all(np.abs(dx) < half_box_l):
Expand Down Expand Up @@ -1279,23 +1278,26 @@ def _update_charge_color_range(self):
def _handle_screenshot(self):
if self.take_screenshot:
self.take_screenshot = False
data = OpenGL.GL.glReadPixels(0, 0, self.specs['window_size'][0],
self.specs['window_size'][1],
OpenGL.GL.GL_RGB, OpenGL.GL.GL_FLOAT)
script_name = os.path.splitext(sys.argv[0])[0]

i = 0
while os.path.exists(f"{script_name}_{i:04d}.png"):
i += 1
file_name = f"{script_name}_{i:04d}.png"

data = np.flipud(data.reshape((data.shape[1], data.shape[0], 3)))
matplotlib.pyplot.imsave(file_name, data)
self._make_screenshot(file_name)

self.screenshot_captured = True
self.screenshot_capture_time = time.time()
self.screenshot_capture_txt = f"Saved screenshot {file_name}"

def _make_screenshot(self, filepath):
data = OpenGL.GL.glReadPixels(0, 0, self.specs['window_size'][0],
self.specs['window_size'][1],
OpenGL.GL.GL_RGB, OpenGL.GL.GL_FLOAT)
data = np.flipud(data.reshape((data.shape[1], data.shape[0], 3)))
matplotlib.pyplot.imsave(filepath, data)

def _display_all(self):

OpenGL.GL.glClear(
Expand Down Expand Up @@ -1403,36 +1405,30 @@ def _init_OpenGL_callbacks(self):
def display():
if self.hasParticleData and self.glut_main_loop_started:
self._display_all()
return

# pylint: disable=unused-argument
def keyboard_up(button, x, y):
if isinstance(button, bytes):
button = button.decode("utf-8")
self.keyboard_manager.keyboard_up(button)
return

# pylint: disable=unused-argument
def keyboard_down(button, x, y):
if isinstance(button, bytes):
button = button.decode("utf-8")
self.keyboard_manager.keyboard_down(button)
return

def mouse(button, state, x, y):
self.mouse_manager.mouse_click(button, state, x, y)
return

def motion(x, y):
self.mouse_manager.mouse_move(x, y)
return

def redraw_on_idle():
# don't repost faster than 60 fps
if (time.time() - self.last_draw) > 1.0 / 60.0:
OpenGL.GLUT.glutPostRedisplay()
self.last_draw = time.time()
return

def reshape_callback(w, h):
self._reshape_window(w, h)
Expand All @@ -1449,7 +1445,6 @@ def close_window():
OpenGL.GLUT.glutReshapeFunc(reshape_callback)
OpenGL.GLUT.glutMotionFunc(motion)
OpenGL.GLUT.glutWMCloseFunc(close_window)

OpenGL.GLUT.glutIdleFunc(redraw_on_idle)

def _init_timers(self):
Expand Down Expand Up @@ -1546,10 +1541,9 @@ def _id_to_fcolor(part_id):
def _fcolor_to_id(fcolor):
if (fcolor == [0, 0, 0]).all():
return -1
else:
return int(fcolor[0] * 255) * 256 ** 2 + \
int(fcolor[1] * 255) * 256 + \
int(fcolor[2] * 255) - 1
return int(fcolor[0] * 255) * 256 ** 2 + \
int(fcolor[1] * 255) * 256 + \
int(fcolor[2] * 255) - 1

# pylint: disable=unused-argument
def _set_particle_drag(self, pos, pos_old):
Expand Down Expand Up @@ -1898,7 +1892,6 @@ def __init__(self, shape, particle_type, color, material,
self.box_l = box_l
self.rasterize_resolution = rasterize_resolution
self.pointsize = rasterize_pointsize

self.rasterized_surface_points = None

def draw(self):
Expand Down Expand Up @@ -1928,16 +1921,15 @@ def _rasterize_shape(self):
for i in range(int(resolution[0])):
for j in range(int(resolution[1])):
for k in range(int(resolution[2])):
# some shapes may not have a well-defined distance function in the whole domain
# and may throw upon asking for a distance
# some shapes may not have a well-defined distance function
# in the whole domain and may throw a ValueError
try:
p = np.array([i, j, k]) * spacing
dist, vec = self.shape.call_method(
"calc_distance", position=p.tolist())
if not np.isnan(vec).any() and not np.isnan(
dist) and abs(dist) < spacing:
if not (np.isnan(vec).any() or np.isnan(dist)) \
and abs(dist) < spacing:
points.append((p - vec).tolist())
# domain error translates to ValueError (cython)
except ValueError:
continue
return points
Expand Down Expand Up @@ -2476,7 +2468,6 @@ def draw_cylinder(posA, posB, radius, color, material, quality,

d = posB - posA

# angle,t,length = calcAngle(d)
length = np.linalg.norm(d)
OpenGL.GL.glTranslatef(posA[0], posA[1], posA[2])

Expand Down