import os
import sys
import platform
import glob
[docs]class file_options:
def __init__(self,num_caps,time=[0,1],flow=[1,1],gui=True,distal_resistance=0):
"""
Set the parameters for vascular construction
and simulation for SimVascular python interface.
"""
self.set_geometry_options()
self.set_loft_options()
self.set_solid_options(num_caps)
self.set_mesh_options()
self.set_pipeline_steps(gui=gui)
self.set_directories()
if len(time) > 2:
self.simulation_parameters(fourier_mode=10,period=time[-1],bct_point_number=2*len(time),distal_resistance=distal_resistance)
else:
self.simulation_parameters(distal_resistance=distal_resistance)
self.flow_parameters(time=time,flow=flow)
self.rom_parameters()
[docs] def set_geometry_options(self,number_samples=50,use_distance_alignment_method=True):
geometry_options = {'number_samples': number_samples,
'use_distance_alignment_method': use_distance_alignment_method}
self.geometry_options = geometry_options
return
[docs] def set_loft_options(self,u_knot_span_type=None,v_parametric_span_type=None,
u_parametric_span_type=None,v_knot_span_type=None,
v_degree=None,u_degree=None,boundary_face_angle=45):
loft_param = [u_knot_span_type,v_parametric_span_type,
u_parametric_span_type,v_knot_span_type,
v_degree,u_degree]
loft_param = [param is None for param in loft_param]
if all(loft_param):
loft_options = {'default': True,
'changes': '',
'angle':boundary_face_angle}
else:
loft_options = {'default': False,
'changes': '',
'angle':boundary_face_angle}
# Check Knot Span Values
if u_knot_span_type is not None:
if u_knot_span_type not in ['derivative','equal','average']:
print('Invalid knot span type\n\nMust be one of:\n "derivative"\n "equal"\n "average"\n')
print('Will default to "derivative" type.')
else:
loft_options['changes'] += 'options.u_knot_span_type = {}\n'.format(u_knot_span_type)
if v_knot_span_type is not None:
if v_knot_span_type not in ['derivative','equal','average']:
print('Invalid knot span type\n\nMust be one of:\n "derivative"\n "equal"\n "average"\n')
print('Will default to "average" type.')
else:
loft_options['changes'] += 'options.v_knot_span_type = {}\n'.format(v_knot_span_type)
# Check Parametric Span Values
if v_parametric_span_type is not None:
if v_parametric_span_type not in ['centripetal','equal','chord']:
print('Invalid knot span type\n\nMust be one of:\n "centripetal"\n "equal"\n "chord"\n')
print('Will default to "chord" type.')
else:
loft_options['changes'] += 'options.v_parametric_span_type = {}\n'.format(v_parametric_span_type)
if u_parametric_span_type is not None:
if u_parametric_span_type not in ['centripetal','equal','chord']:
print('Invalid knot span type\n\nMust be one of:\n "centripetal"\n "equal"\n "chord"\n')
print('Will default to "centripetal" type.')
else:
loft_options['changes'] += 'options.u_parametric_span_type = {}\n'.format(u_parametric_span_type)
if v_degree is not None:
if not isinstance(v_degree,int):
print('v_degree must be an integer')
print('Will default to v_degree = 2')
else:
loft_options['changes'] += 'options.v_degree = {}\n'.format(v_degree)
if u_degree is not None:
if not isinstance(u_degree,int):
print('v_degree must be an integer')
print('Will default to u_degree = 2')
else:
loft_options['changes'] += 'options.u_degree = {}\n'.format(u_degree)
self.loft_options = loft_options
return
[docs] def set_solid_options(self,num_caps,minimum_face_cells=200,hmin=0.02,hmax=0.02,
face_edge_size=0.02,boundary_face_angle=45):
#Check input types
if not isinstance(minimum_face_cells,int):
print('minimum_face_cells must be a positive int > 0')
print('Using default value')
minimum_face_cells=200
if not isinstance(hmin,float):
print('hmin must be a float < 1')
print('Using default value')
hmin=0.02
if not isinstance(hmax,float):
print('hmax must be a float hmin =< hmax < 1')
print('Using default value')
hmax=0.02
if not isinstance(face_edge_size,float):
print('face_edge_size must be a float < 1')
print('Using default value')
face_edge_size=0.02
if boundary_face_angle > 90 or boundary_face_angle < 0:
print('boundary_face_angle must be greater than 0 and less than 90')
print('Using default value')
boundary_face_angle = 45
solid_options = {'minimum_face_cells': minimum_face_cells,
'hmin': hmin,
'hmax': hmax,
'face_edge_size': face_edge_size,
'angle': boundary_face_angle,
'num_caps': num_caps}
self.solid_options = solid_options
return
[docs] def set_mesh_options(self,global_edge_size=0.01,surface_mesh_flag=True,
volume_mesh_flag=True,no_merge=False,optimization_level=5,
minimum_dihedral_angle=18.0):
if not isinstance(global_edge_size,float):
print('global_edge_size must be a float less than 1')
print('Using default: global_edge_size = 0.01')
global_edge_size=0.01
if not isinstance(surface_mesh_flag,bool):
print('surface_mesh_flag must be boolean logic')
print('Using default: surface_mesh_flag = True')
surface_mesh_flag = True
if not isinstance(volume_mesh_flag,bool):
print('volume_mesh_flag must be boolean logic')
print('Using default: volume_mesh_flag = True')
volume_mesh_flag = True
if not isinstance(no_merge,bool):
print('no_merge must be boolean logic')
print('Using default: no_merge = False')
no_merge = False
if not isinstance(optimization_level,int):
print('optimization_level must be an integer between 0 and 7, inclusive')
print('Using default: optimization_level = 5')
optimization_level = 5
elif optimization_level > 7 or optimization_level < 0:
print('optimization_level must be an integer between 0 and 7, inclusive')
print('Using default: optimization_level = 5')
optimization_level = 5
if not isinstance(minimum_dihedral_angle,float):
print('minimum_dihedral_angle must be a float')
print('Using default: minimum_dihedral_angle = 18')
minimum_dihedral_angle = 18
mesh_options = {'global_edge_size': global_edge_size,
'surface_mesh_flag': surface_mesh_flag,
'volume_mesh_flag': volume_mesh_flag,
'no_merge': no_merge,
'optimization_level': optimization_level,
'minimum_dihedral_angle':minimum_dihedral_angle}
self.mesh_options = mesh_options
return
[docs] def set_pipeline_steps(self,files='all',gui=False):
file_types = ['path','contour','solid',
'mesh','simulation','rom']
# Check parameter values
if not isinstance(files,str):
print('{files} parameter must be a str')
return
if not isinstance(gui,bool):
print('{gui} parameter must be True or False')
return
# Assign Model Constructor Values
file_constructor = {'path': True,
'contour': True,
'solid': True,
'mesh': True,
'simulation': True,
'rom': True,
'gui': gui}
if files == 'all':
pass
else:
if files in file_types:
file_index = file_types.index(files)
for i,f in enumerate(file_types):
if i <= file_index:
pass
else:
file_constructor[f] = False
self.file_constructor = file_constructor
return
[docs] def set_directories(self,outdir=None):
if isinstance(outdir,type(None)):
outdir = os.getcwd()
if isinstance(outdir,str):
if not os.path.isdir(outdir):
print('{} either does not exist or is not accessible'.format(outdir))
return
else:
pass
else:
print('{outdir} should be a str argument if provided')
return
# Assigning Directory Constructor Values
directory_constructor = {'main_folder': None,
'create_main_folder': False,
'data_folder': None,
'mesh_complete_folder': None,
'mesh_surfaces_folder': None,
'postprocessing_folder':None}
if not os.path.isdir(outdir+'/CCO_DATA'):
directory_constructor['create_main_folder'] = True
else:
directory_constructor['create_main_folder'] = False
directory_constructor['main_folder'] = outdir+os.sep+'CCO_DATA'
number = len(glob.glob(directory_constructor['main_folder']+os.sep+'CCO_*'))
directory_constructor['data_folder'] = directory_constructor['main_folder']+os.sep+'simulation_data{}'.format(number)
directory_constructor['mesh_complete_folder'] = directory_constructor['data_folder']+os.sep+'mesh-complete'
directory_constructor['mesh_surfaces_folder'] = directory_constructor['mesh_complete_folder']+os.sep+'mesh-surfaces'
directory_constructor['centerline_folder'] = directory_constructor['data_folder']+os.sep+'centerlines'
directory_constructor['postprocessing_folder'] = directory_constructor['data_folder']+os.sep+'post'
directory_constructor['rom_folder'] = directory_constructor['data_folder']+os.sep+'rom'
directory_constructor['rom_0D_folder'] = directory_constructor['rom_folder']+os.sep+'zeroD'
directory_constructor['rom_1D_folder'] = directory_constructor['rom_folder']+os.sep+'oneD'
directory_constructor['main_folder'] = directory_constructor['main_folder'].replace('\\','\\\\')
directory_constructor['data_folder'] = directory_constructor['data_folder'].replace('\\','\\\\')
directory_constructor['mesh_complete_folder'] = directory_constructor['mesh_complete_folder'].replace('\\','\\\\')
directory_constructor['mesh_surfaces_folder'] = directory_constructor['mesh_surfaces_folder'].replace('\\','\\\\')
directory_constructor['centerline_folder'] = directory_constructor['centerline_folder'].replace('\\','\\\\')
directory_constructor['postprocessing_folder'] = directory_constructor['postprocessing_folder'].replace('\\','\\\\')
directory_constructor['rom_folder'] = directory_constructor['rom_folder'].replace('\\','\\\\')
directory_constructor['rom_0D_folder'] = directory_constructor['rom_0D_folder'].replace('\\','\\\\')
directory_constructor['rom_1D_folder'] = directory_constructor['rom_1D_folder'].replace('\\','\\\\')
self.directory_constructor = directory_constructor
self.number = number
self.filename = directory_constructor['main_folder']+os.sep+'CCO_{}.py'.format(number)
self.filename = self.filename.replace('\\','\\\\')
self.name = 'CCO_{}'.format(number)
return
[docs] def simulation_parameters(self,svpre_name='cco',fluid_density=1.06,
fluid_viscosity=0.04, initial_pressure=0,
initial_velocity=[0.0001,0.0001,0.0001],
bct_analytical_shape='parabolic',
inflow_file='inflow',
period=1,bct_point_number=2,
fourier_mode=1,pressures=0,
svsolver='solver',number_timesteps=200,
timestep_size=0.02,number_restarts=50,
number_force_surfaces=1,
surface_id_force_calc=1,
force_calc_method='Velocity Based',
print_avg_solution=True,
print_error_indicators=False,
varying_time_from_file=True,
step_construction='0 1 0 1',
pressure_coupling='Implicit',
backflow_stabilization=0.2,
residual_control=True,
residual_criteria=0.01,
minimum_req_iter=2,
svLS_type='NS',num_krylov=100,
num_solves_per_left=1,
tolerance_momentum=0.05,
tolerance_continuity=0.4,
tolerance_svLS_NS=0.4,
max_iter_NS=2,max_iter_momentum=4,
max_iter_continuity=400,
time_integration_rule='Second Order',
time_integration_rho=0.5,
flow_advection_form='Convective',
quadrature_interior=2,
quadrature_boundary=3,procs=24,
svpost='cco',start=0,vtu=True,
vtp=False,vtkcombo=False,
all_arg=True,wss=False,
sim_units_mm=False,
sim_units_cm=True,
global_edge_size=0.01,
distal_resistance=0):
# Assign PreSolver Constructor Values
presolver_constructor = {'name': svpre_name,
'fluid_density': fluid_density,
'fluid_viscosity': fluid_viscosity,
'initial_pressure': initial_pressure,
'initial_velocity': initial_velocity,
'bct_analytical_shape': bct_analytical_shape,
'inflow_file': inflow_file+'_3d.flow',
'period': period,
'bct_point_number': bct_point_number,
'fourier_mode': fourier_mode,
'pressures': pressures}
# Assign Solver Constructor Values
solver_constructor = {'name': svsolver,
'fluid_density': fluid_density,
'fluid_viscosity': fluid_viscosity,
'number_timesteps': number_timesteps,
'timestep_size': timestep_size,
'number_restarts': number_restarts,
'number_force_surfaces': number_force_surfaces,
'surface_id_force_calc': surface_id_force_calc,
'force_calc_method': force_calc_method,
'print_avg_solution': print_avg_solution,
'print_error_indicators':print_error_indicators,
'varying_time_from_file':varying_time_from_file,
'step_construction': step_construction,
'pressure_coupling': pressure_coupling,
'backflow_stabilization':backflow_stabilization,
'residual_control': residual_control,
'residual_criteria': residual_criteria,
'minimum_req_iter': minimum_req_iter,
'svLS_type': svLS_type,
'num_krylov': num_krylov,
'num_solves_per_left': num_solves_per_left,
'tolerance_momentum': tolerance_momentum,
'tolerance_continuity': tolerance_continuity,
'tolerance_svLS_NS': tolerance_svLS_NS,
'max_iter_NS': max_iter_NS,
'max_iter_momentum': max_iter_momentum,
'max_iter_continuity': max_iter_continuity,
'time_integration_rule': time_integration_rule,
'time_integration_rho': time_integration_rho,
'flow_advection_form': flow_advection_form,
'quadrature_interior': quadrature_interior,
'quadrature_boundary': quadrature_boundary,
'global_edge_size': global_edge_size,
'distal_resistance': distal_resistance}
indir = self.directory_constructor['data_folder']+'/{}-procs_case'.format(procs)
outdir = self.directory_constructor['postprocessing_folder']
if sim_units_mm and sim_units_cm:
print('Must pick one unit scale. Not both.')
print('Exiting without assigning postprocessing parameters.')
return
postsolver_constructor = {'name': svpost,
'start': start,
'stop': number_timesteps,
'incr': number_restarts,
'vtu': vtu,
'vtp': vtp,
'vtkcombo': vtkcombo,
'all': all_arg,
'wss': wss,
'indir': indir,
'sim_units_mm': sim_units_mm,
'sim_units_cm': sim_units_cm,
'outdir': outdir}
self.presolver_constructor = presolver_constructor
self.solver_constructor = solver_constructor
self.postsolver_constructor = postsolver_constructor
return
[docs] def flow_parameters(self,inflow_file='inflow',time=[0,1],flow=[1,1]):
flow_constructor = {'inflow_file': inflow_file,
'time': time,
'flow': flow}
self.flow_constructor = flow_constructor
[docs] def rom_parameters(self,inflow='inflow_rom.flow',zeroD=True,oneD=True,time_step=0.001,
number_time_steps=1000):
rom0D_constructor = {'create': zeroD,
'model_order': 0,
'time_step': time_step,
'number_time_steps': number_time_steps,
'inflow_file': inflow}
rom1D_constructor = {'create': oneD,
'model_order': 1,
'time_step': time_step,
'number_time_steps': number_time_steps,
'inflow_file': inflow}
self.rom_constructor = {'0D': rom0D_constructor,
'1D': rom1D_constructor}
return