Skip to content

Commit

Permalink
Changes:
Browse files Browse the repository at this point in the history
 - Fixed simulation failing to start when intervals statistics and snapshots are empty.
 - Fixed statistics and snapshot intervals not being saved into the session file.
 - The units for intervals are now in seconds and can be input in scientific from, i.e. '1e-5'.
 - Minor refactoring of file viewers
  • Loading branch information
MrCheatak committed Jul 12, 2024
1 parent dda698e commit 59cc25a
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 161 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ By using the same input data, it is possible to inspect electron scattering prof

Installation
---------------
The simulation requires Python 3.7 or later.
The simulation requires Python 3.9 or later.

Package is available via PyPi: :code:`pip install febid`

Expand Down
2 changes: 1 addition & 1 deletion febid/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def welcome():
print(intro)
command_functions = {
'show_file': febid.show_file.show_structure,
'show_animation': febid.show_animation.show_animation,
'show_animation': febid.show_animation.render_animation,
'gui': start_ui,
'no_gui': Starter().start
}
Expand Down
78 changes: 43 additions & 35 deletions febid/libraries/vtk_rendering/show_animation_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
"""
import os, time
import sys
import numpy as np
import pyvista as pv
import vtk
from datetime import datetime
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QFileDialog as fd

import numpy as np
import vtk

import febid.libraries.vtk_rendering.VTK_Rendering as vr
from febid.libraries.vtk_rendering.VTK_Rendering import Render, read_field_data
from febid.Structure import Structure


def ask_directory():
os.chdir('../../..')
init_dir = os.getcwd()
Expand All @@ -21,6 +22,7 @@ def ask_directory():
app.quit()
return directory


def open_file(directory=''):
"""
Gather files and timestamps sorted in the order of creation
Expand All @@ -35,7 +37,7 @@ def open_file(directory=''):
# directory = '/Users/sandrik1742/Documents/PycharmProjects/FEBID/code/Experiment runs/gr=0'
files = sorted(os.listdir(directory))[:]
n = 0
for i in range(len(files)-1, -1, -1):
for i in range(len(files) - 1, -1, -1):
if os.path.splitext(files[i])[1] != '.vtk':
files.pop(i)
n += 1
Expand All @@ -51,13 +53,17 @@ def open_file(directory=''):

return files, times


def show_animation(directory=None, **kwargs):
if not directory:
directory = ask_directory()
if not directory:
return
result = show_animation(directory, **kwargs)
return result

def show_animation(directory, show='precursor'):

def render_animation(directory, show='precursor'):
"""
Show animated process from series of vtk files.
Files must have consequent creation dates to align correctly
Expand All @@ -77,14 +83,14 @@ def show_animation(directory, show='precursor'):

# Getting data for initialization
structure = Structure()
vtk_obj = vr.pv.read(os.path.join(directory, files[0]))
vtk_obj = pv.read(os.path.join(directory, files[0]))
structure.load_from_vtk(vtk_obj)
cell_size, deposit, precursor, surface_bool, semi_surface_bool, ghosts_bool = structure.cell_size, \
structure.deposit, \
structure.precursor, \
structure.surface_bool, \
structure.semi_surface_bool, \
structure.ghosts_bool
structure.deposit, \
structure.precursor, \
structure.surface_bool, \
structure.semi_surface_bool, \
structure.ghosts_bool
# Determining rendered dataset
if show not in ['precursor', 'deposit', 'temperature']:
raise RuntimeError(f'The specified dataset \'{show}\' is not supported.')
Expand All @@ -102,7 +108,7 @@ def show_animation(directory, show='precursor'):
mask_name = 'deposit'
data = structure.__getattribute__(show)
mask = structure.__getattribute__(mask_name)
t, sim_time, beam_position = vr.read_field_data(vtk_obj) # getting deposition process features
t, sim_time, beam_position = read_field_data(vtk_obj) # getting deposition process features
# Preparing left corner text with times
text = ''
if t:
Expand All @@ -111,12 +117,12 @@ def show_animation(directory, show='precursor'):
text += f'Simulation time: {sim_time:.7f} s \n'

# Setting the setup scene
render = vr.Render(cell_size)
render = Render(cell_size)
render.add_3Darray(data)
render.p.add_text('Adjust the scene for the animation \n and close the window.', position='upper_edge')
cam_pos = render.show()
# Setting the first frame
render = vr.Render(cell_size)
render = Render(cell_size)
# Creating an arrow at beam position
if beam_position is not None:
x_pos, y_pos = beam_position
Expand All @@ -134,7 +140,7 @@ def show_animation(directory, show='precursor'):
render.p.mesh.cell_data[vtk.vtkDataSetAttributes.GhostArrayName()] = index.ravel()
render.p.mesh.set_active_scalars(data_name)
# Adding text
t, sim_time, beam_position = vr.read_field_data(vtk_obj)
t, sim_time, beam_position = read_field_data(vtk_obj)
text = ''
if t:
text += f'Time: {t} \n'
Expand All @@ -148,14 +154,14 @@ def show_animation(directory, show='precursor'):
render.p.add_text(text, position='upper_left', font_size=font_size, name='time')
render.p.add_text(stats, font_size=font_size, position='upper_right', name='stats')
render.show(interactive_update=True, cam_pos=cam_pos)
init_layer = np.count_nonzero(deposit==-2) # substrate layer
total_dep_cells = [np.count_nonzero(deposit[deposit<0])-init_layer] # total number of fully deposited cells
growth_rate=[] # growth rate on each step
init_layer = np.count_nonzero(deposit == -2) # substrate layer
total_dep_cells = [np.count_nonzero(deposit[deposit < 0]) - init_layer] # total number of fully deposited cells
growth_rate = [] # growth rate on each step

# Animation
for i in range(1, len(files)):
# Reading data
vtk_obj = vr.pv.read(os.path.join(directory, files[i]))
vtk_obj = pv.read(os.path.join(directory, files[i]))
# Loading the structure
structure.load_from_vtk(vtk_obj)
cell_size = structure.cell_size
Expand All @@ -167,14 +173,14 @@ def show_animation(directory, show='precursor'):
if show == 'deposit':
mask = surface_bool
if show == 'temperature':
mask = deposit<0
mask = deposit < 0
# Calculating deposition process features
total_dep_cells.append(np.count_nonzero(deposit[deposit < 0]) - init_layer)
volume = int((total_dep_cells[i] + deposit[surface_bool].sum()) * cell_size ** 3)
delta_t = (times[i] - times[i - 1]).total_seconds()
if delta_t < 1: delta_t = 1
growth_rate.append(cell_size ** 3 * (total_dep_cells[i] - total_dep_cells[i - 1]) / delta_t * 60 * 60)
t, sim_time, beam_position = vr.read_field_data(vtk_obj)
t, sim_time, beam_position = read_field_data(vtk_obj)
# Setting up text
# Left corner
text = ''
Expand All @@ -186,17 +192,17 @@ def show_animation(directory, show='precursor'):
stats = f'Cells: {total_dep_cells[i]} \n\
Height: {int(np.nonzero(deposit)[0].max() * cell_size)} nm \n\
Volume: {volume} nm^3 \n\
Frame {i+1}/{len(files)}'
Frame {i + 1}/{len(files)}'
# Updating arrow position
if beam_position is not None:
x_pos, y_pos = beam_position
x, y = int(x_pos / render.cell_size), int(y_pos / render.cell_size)
max_z = structure.deposit[:, y, x].nonzero()[0].max()
render.arrow.SetPosition(x_pos, y_pos, max_z * render.cell_size + 30) # relative to the initial position
# Redrawing the 3D object if necessary
if render.p.mesh.n_cells != data.size: # must redraw if shape changes
if render.p.mesh.n_cells != data.size: # must redraw if shape changes
data_visibility = render.p.renderer.actors[data_name].GetVisibility()
render.p.remove_actor(data_name+'_caption')
render.p.remove_actor(data_name + '_caption')
render.y_pos = 5
render.p.button_widgets.clear()
render.p.remove_actor(data_name)
Expand All @@ -207,7 +213,7 @@ def show_animation(directory, show='precursor'):
render.p.mesh.cell_data[vtk.vtkDataSetAttributes.GhostArrayName()] = index.ravel()
render.p.mesh.set_active_scalars(data_name)
else:
render.p.mesh[data_name] = data.ravel() # new data, ravel() sends a view
render.p.mesh[data_name] = data.ravel() # new data, ravel() sends a view
# Updating hidden cells
index[mask == 0] = vtk.vtkDataSetAttributes.HIDDENCELL
index[mask == 1] = 0 # surface_bool is not bool type and cannot be used directly as index
Expand All @@ -216,19 +222,20 @@ def show_animation(directory, show='precursor'):
render.p.actors['stats'].SetText(3, stats)

# render.p.mesh.cell_data[vtk.vtkDataSetAttributes.GhostArrayName()] = index.ravel()
p=data[mask]
p = data[mask]
# Updating the scalar bar
try:
render.p.update_scalar_bar_range([np.partition(p[p!=p.min()], 4)[2], p.max()])
except: pass
render.p.update_scalar_bar_range([np.partition(p[p != p.min()], 4)[2], p.max()])
except:
pass
render.update()
else: # finishing with a static scene
else: # finishing with a static scene
# Clearing the scene
render.y_pos = 5
render.p.button_widgets.clear()
render.p.clear()
# Reading data
vtk_obj = vr.pv.read(os.path.join(directory, files[-1]))
vtk_obj = pv.read(os.path.join(directory, files[-1]))
# Loading the structure
structure.load_from_vtk(vtk_obj)
cell_size = structure.cell_size
Expand All @@ -241,18 +248,18 @@ def show_animation(directory, show='precursor'):
render.p.update_scalar_bar_range([np.partition(p[p != p.min()], 4)[2], p.max()])
render.p.mesh.cell_data[vtk.vtkDataSetAttributes.GhostArrayName()] = index.ravel()
render.p.mesh.set_active_scalars(data_name)
t, sim_time, beam_position = vr.read_field_data(vtk_obj)
t, sim_time, beam_position = read_field_data(vtk_obj)
text = ''
if t:
text += f'Time: {t} \n'
if sim_time:
text += f'Simulation time: {sim_time:.7f} s \n'
render.p.add_text(text, position='upper_left', font_size=font_size) # showing time passed
render.p.add_text(f'Cells: {total_dep_cells[i-1]} \n' # showing total number of deposited cells
render.p.add_text(f'Cells: {total_dep_cells[i - 1]} \n' # showing total number of deposited cells
f'Height: {int(np.nonzero(deposit)[0].max() * cell_size)} nm \n' # showing current height of the structure
f'Volume: {volume} nm^3 \n'
f'Growth rate: {int(np.asarray(growth_rate).mean())} cell/h \n' # showing average growth rate
f'Frame {i+1}/{len(files)} \n', position='upper_right', font_size=font_size)
f'Frame {i + 1}/{len(files)} \n', position='upper_right', font_size=font_size)
if beam_position is not None:
x_pos, y_pos = beam_position
x, y = int(x_pos / render.cell_size), int(y_pos / render.cell_size)
Expand All @@ -264,6 +271,7 @@ def show_animation(directory, show='precursor'):
cam_pos = render.show(interactive_update=False)
return cam_pos


if __name__ == '__main__':
filenames = None
try:
Expand All @@ -272,4 +280,4 @@ def show_animation(directory, show='precursor'):
print(e.args)
if not filenames:
filenames = ask_directory()
show_animation()
show_animation()
48 changes: 29 additions & 19 deletions febid/libraries/vtk_rendering/show_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,44 @@
import pyvista as pv
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QFileDialog as fd
from febid.libraries.vtk_rendering import VTK_Rendering as vr

from febid.libraries.vtk_rendering.VTK_Rendering import Render, read_field_data
from febid.Structure import Structure

def ask_filenames():

def check_allowed_extensions(filenames, allowed_extensions=['vtk']):
for filename in filenames:
if not any(filename.endswith(ext) for ext in allowed_extensions):
return False
return True


def ask_filenames(allowed_extensions=['vtk']):
os.chdir('../../..')
init_dir = os.getcwd()
app = QApplication(sys.argv)
filenames = fd.getOpenFileName(None, 'Select the file to view', init_dir, 'VTK files (*.vtk);;All files (*)')[0]
extensions = ', '.join([f'*.{ext}' for ext in allowed_extensions])
filenames = fd.getOpenFileName(None, 'Select the file to view', init_dir, f'VTK files ({extensions});;All files (*)')[0]
app.quit()
return filenames


def show_structure(filenames=None, **kwargs):
if not filenames:
filenames = ask_filenames()
result = render_structure(filenames, **kwargs)
return result

def render_structure(filenames, solid=True, deposit=True, precursor=True, surface=True, semi_surface=True, ghost=True):

def render_structure(filenames, solid=True, deposit=True, precursor=True, surface=True, semi_surface=True, ghost=True):
font_size = 12
cam_pos = None
if type(filenames) not in [list, tuple]:
filenames = [filenames]
for filename in filenames:
print(f'Opening file {filename}')
vtk_obj = pv.read(filename)
print(f'Data arrays: {vtk_obj.array_names}')
structure = Structure()
structure.load_from_vtk(vtk_obj)
d = structure.deposit
Expand All @@ -47,35 +59,33 @@ def render_structure(filenames, solid=True, deposit=True, precursor=True, surfac
if p.min() < 0:
p_er += 1
print(f'Checking data.....', end='')
if d_er+p_er:
if d_er + p_er:
print(f'bad cells encountered in data arrays!')
if d_er:
print(f'\t Solid-cell data contains bad cells:')
if d.max() > 1:
print(f'\t Found {np.count_nonzero(d>1)} cells above unity, maximum value is {d.max()}')
print(f'\t Found {np.count_nonzero(d > 1)} cells above unity, maximum value is {d.max()}')
if d.min() < -2:
print(f'\t Found {np.count_nonzero(d<-2)} cells below zero, minimum value is {d.min()}')
print(f'\t Found {np.count_nonzero(d < -2)} cells below zero, minimum value is {d.min()}')
if p_er:
print(f'\t Surface precursor density data contains bad cells:')
if p.max() > 1:
print(f'\t Found {np.count_nonzero(p>1)} cells above unity, maximum value is {p.max()}')
print(f'\t Found {np.count_nonzero(p > 1)} cells above unity, maximum value is {p.max()}')
if p.min() < 0:
print(f'\t Found {np.count_nonzero(p<0)} cells below zero, minimum value is {p.min()}')
print(f'\t Found {np.count_nonzero(p < 0)} cells below zero, minimum value is {p.min()}')
else:
print('ok!')
t, sim_time, beam_position = vr.read_field_data(vtk_obj)
render = vr.Render(structure.cell_size)
cam_pos = render.show_full_structure(structure, True, solid, deposit, precursor, surface, semi_surface, ghost, t, sim_time, beam_position, cam_pos=cam_pos)
t, sim_time, beam_position = read_field_data(vtk_obj)
render = Render(structure.cell_size)
cam_pos = render.show_full_structure(structure, True, solid, deposit, precursor, surface, semi_surface, ghost,
t, sim_time, beam_position, cam_pos=cam_pos)
return cam_pos


if __name__ == '__main__':
filenames = None
try:
filename = sys.argv[1]
except Exception as e:
print(e.args)
if not filenames:
filenames = ask_filenames()

if len(sys.argv) > 1:
filenames = sys.argv[1:]
if not check_allowed_extensions(filenames):
raise ValueError('Only .vtk files are allowed!')
show_structure(filenames, solid=True, deposit=True, precursor=True, surface=True, semi_surface=True, ghost=True)
14 changes: 8 additions & 6 deletions febid/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,15 @@ def _run_febid_interface(self):
Compile simulation parameters and start the simulation
"""
sim_volume_params = self.get_simulation_volume_parameters()
saving_params = {'gather_stats': False, 'gather_stats_interval': None, 'save_snapshot': False, 'snapshot_interval': None,
'filename': None}
saving_params = {'gather_stats': False, 'gather_stats_interval': None, 'save_snapshot': False, 'save_snapshot_interval': None,
'filename': ''}
flag1, flag2 = self._params['save_simulation_data'], self._params['save_structure_snapshot']
saving_params['gather_stats'] = self._params['save_simulation_data']
saving_params['gather_stats_interval'] = float(self._params['simulation_data_interval'])
saving_params['save_snapshot'] = self._params['save_structure_snapshot']
saving_params['save_snapshot_interval'] = float(self._params['structure_snapshot_interval'])
gather_stats = saving_params['gather_stats'] = self._params['save_simulation_data']
if gather_stats:
saving_params['gather_stats_interval'] = float(self._params['simulation_data_interval'])
save_snapshot = saving_params['save_snapshot'] = self._params['save_structure_snapshot']
if save_snapshot:
saving_params['save_snapshot_interval'] = float(self._params['structure_snapshot_interval'])
flag1, flag2, flag3 = self._params['save_simulation_data'], self._params['save_structure_snapshot'], self._params['show_process']
if flag1 or flag2:
try:
Expand Down
Loading

0 comments on commit 59cc25a

Please sign in to comment.