def open_mode(ascii_file, mode_index, supercell=[2,2,2], animate=True, n_frames=30, vectors=False, bbox=True, bbox_offset=(0,0,0), scale_factor=1.0, vib_magnitude=1.0, arrow_magnitude=1.0): """ Open v_sim ascii file in Blender Arguments: ascii_file: Path to file mode_index: integer id of mode; 0 corresponds to first mode in ascii file supercell: 3-tuple or list of integer supercell dimensions animate: Boolean: if True, add animation keyframes n_frames: Animation length in frames vectors: Boolean; if True, show arrows bbox: Boolean; if True, show bounding box bbox_loc: Vector or 3-tuple in lattice vector coordinates; position of bbox. Default (0,0,0) (Left front bottom) """ vsim_cell, positions, symbols, vibs = import_vsim(ascii_file) lattice_vectors = cell_vsim_to_vectors(vsim_cell) # Switch to a new empty scene bpy.ops.scene.new(type='EMPTY') # Draw bounding box # if bbox: bbox_offset = Vector(bbox_offset) draw_bounding_box(lattice_vectors, offset=bbox_offset) # Draw atoms for cell_id_tuple in itertools.product(range(supercell[0]),range(supercell[1]),range(supercell[2])): cell_id = Vector(cell_id_tuple) for atom_index, (position, symbol) in enumerate(zip(positions, symbols)): atom = add_atom(position,lattice_vectors,symbol,cell_id=cell_id, name = '{0}_{1}_{2}{3}{4}'.format(atom_index,symbol,*cell_id_tuple), scale_factor=scale_factor) displacement_vector = vibs[mode_index].vectors[atom_index] qpt = vibs[mode_index].qpt B = 2 * math.pi * Matrix(lattice_vectors).inverted().transposed() qpt_cartesian = Vector(qpt) * B if animate: animate_atom_vibs(atom, qpt_cartesian, displacement_vector, n_frames=n_frames, magnitude=vib_magnitude) if vectors: arrow_vector=vector_with_phase(atom, qpt_cartesian, displacement_vector) add_arrow(loc=absolute_position(position, lattice_vectors=lattice_vectors, cell_id=cell_id), rot_euler=vector_to_euler(arrow_vector), scale=arrow_vector.length*arrow_magnitude) # Position camera and colour world # Note that cameras as objects and cameras as 'cameras' have different attributes, # so need to look up camera in bpy.data.cameras to set field of view. field_of_view = 0.5 # Camera field of view in radians camera_x = (lattice_vectors[0][0]/2. + lattice_vectors[2][0]/2.) * supercell[0] camera_y = max(((abs(lattice_vectors[0][0]) + abs(lattice_vectors[2][0]) + 2) * supercell[0], abs(lattice_vectors[2][2]) * supercell[2] + 2)) / (-2. * math.tan(field_of_view/2.)) camera_z = lattice_vectors[2][2]/2. * supercell[2] camera_loc=( camera_x, 1.05 * camera_y, camera_z) bpy.ops.object.camera_add(location=camera_loc,rotation=(math.pi/2,0,0)) camera = bpy.context.object bpy.context.scene.camera = camera bpy.data.cameras[camera.name].angle = field_of_view bpy.context.scene.world = bpy.data.worlds['World'] bpy.data.worlds['World'].horizon_color = [0.5, 0.5, 0.5]
def open_mode(**options): """ Open v_sim ascii file in Blender :param input_file: Path to file :type input_file: str :param camera_rot: Camera tilt adjustment in degrees :type camera_rot: float :param config: Settings from configuration files :type config: configparser.ConfigParser :param mass_weighting: Weight eigenvectors by mass. This has usually already been done when generating the .ascii file, in which case the default value of 0 is acceptable. A value of 1 corresponds to the formally correct mass scaling of m^-0.5 for non-weighted eigenvectors. A value of -1 will REMOVE existing mass-weighting. In-between values may be useful for re-scaling to see the range of movements in a system, but are not physically meaningful. :type mass_weighting: float :param end_frame: The ending frame number of the rendered Animation (default=start_frame+n_frames-1) :type end_frame: int or None :param miller: Miller indices of view :type miller: 3-tuple of floats :param mode_index: id of mode; 0 corresponds to first mode in ascii file :type mode_index: int :param n_frames: Animation length of a single oscillation cycle in frames (default=30) :type n_frames: Positive int :param normalise_vectors: Re-scale vectors so largest arrow is fixed length :type normalise_vectors: bool :param offset_box: Position of bbox in lattice vector coordinates. Default (0,0,0) (Left front bottom) :type offset_box: Vector or 3-tuple :param preview: Enable preview mode - single frame, smaller render :type preview: bool :param scale_arrow: Scale factor for arrows :type scale_arrow: float :param scale_atom: Scale of atoms, relative to covalent radius :type scale_atom: float :param scale_vib: Scale factor for oscillations (angstroms / normalised eigenvector). :type scale_vib: float :param show_box: If True, show bounding box :type show_box: bool :param start_frame: The starting frame number of the rendered animation (default=0) :type start_frame: int or None :param static: if True, ignore frame range and use single frame. Otherwise, add animation keyframes. :type static: bool :param supercell: supercell dimensions :type supercell: 3-tuple or 3-list of ints :param vectors: If True, show arrows :type vectors: bool :param zoom: Camera zoom adjustment :type zoom: float """ # Initialise Opts object, accessing options and user config opts = vsim2blender.Opts(options) # Work out actual frame range. # Priority goes 1. static/preview 2. end_frame 3. n_frames start_frame = opts.get('start_frame', 0) n_frames = opts.get('n_frames', 30) # Preview images default to static, others default to animated preview = opts.get('preview', False) if preview: static = opts.get('static', True) else: static = opts.get('static', False) if static: end_frame = start_frame else: end_frame = opts.get('end_frame', start_frame + n_frames - 1) input_file = opts.get('input_file', False) if input_file: (vsim_cell, positions, symbols, vibs) = import_vsim(input_file) lattice_vectors = cell_vsim_to_vectors(vsim_cell) else: raise Exception('No .ascii file provided') if opts.get('mass_weighting', 0): f = opts.get('mass_weighting', 1) masses = [ float(opts.config['masses'][symbol])**f for symbol in symbols ] else: masses = [1 for symbol in symbols] # Switch to a new empty scene bpy.ops.scene.new(type='EMPTY') # Draw bounding box if (opts.get('show_box', True)): bbox_offset = opts.get('offset_box', (0, 0, 0)) bbox_offset = Vector(bbox_offset) draw_bounding_box(lattice_vectors, offset=bbox_offset) # Draw atoms after checking config mode_index = opts.get('mode_index', 0) supercell = (opts.get('supercell', (2, 2, 2))) vectors = opts.get('vectors', False) normalise_vectors = opts.get('normalise_vectors', False) # Variable for tracking largest arrow max_vector = 0 arrow_objects = [] mass_weighting = opts.get('mass_weighting', 0.) assert type(mass_weighting) == float for cell_id_tuple in itertools.product(range(supercell[0]), range(supercell[1]), range(supercell[2])): cell_id = Vector(cell_id_tuple) for (atom_index, (position, symbol, mass)) in enumerate(zip(positions, symbols, masses)): atom = add_atom(position, lattice_vectors, symbol, cell_id=cell_id, scale_factor=opts.get('scale_atom', 1.), name='{0}_{1}_{2}{3}{4}'.format( atom_index, symbol, *cell_id_tuple), config=opts.config) if vectors or not static: displacement_vector = vibs[mode_index].vectors[atom_index] qpt = vibs[mode_index].qpt B = (2 * math.pi * Matrix(lattice_vectors).inverted().transposed()) qpt_cartesian = Vector(qpt) * B if not static: animate_atom_vibs(atom, qpt_cartesian, displacement_vector, start_frame=start_frame, end_frame=end_frame, n_frames=n_frames, magnitude=opts.get('scale_vib', 1.), mass=mass) if vectors: arrow_vector = vector_with_phase(atom, qpt_cartesian, displacement_vector) scale = arrow_vector.length loc = absolute_position(position, lattice_vectors=lattice_vectors, cell_id=cell_id) # Arrows are scaled by eigenvector magnitude arrow_objects.append( add_arrow(loc=loc, mass=mass, rot_euler=vector_to_euler(arrow_vector), scale=scale)) if vectors: col = str2list(opts.config.get('colours', 'arrow', fallback='0. 0. 0.')) bpy.data.materials['Arrow'].diffuse_color = col # Rescaling; either by clamping max or accounting for cell size if vectors and normalise_vectors: master_scale = opts.get('scale_arrow', 1.) # Compare first element of object scales; they should be isotropic! max_length = max((arrow.scale[0] for arrow in arrow_objects)) for arrow in arrow_objects: arrow.scale *= master_scale / max_length elif vectors: master_scale = opts.get('scale_arrow', 1.) * len(positions) for arrow in arrow_objects: arrow.scale *= master_scale # Position camera and colour world. Note that cameras as objects and # cameras as 'cameras' have different attributes, so need to look up # camera in bpy.data.cameras to set field of view. camera.setup_camera(lattice_vectors, field_of_view=0.2, opts=opts) bpy.context.scene.world = bpy.data.worlds['World'] bpy.data.worlds['World'].horizon_color = str2list( opts.config.get('colours', 'background', fallback='0.5 0.5 0.5'))
def open_mode(**options): """ Open v_sim ascii file in Blender :param input_file: Path to file :type input_file: str :param camera_rot: Camera tilt adjustment in degrees :type camera_rot: float :param config: Settings from configuration files :type config: configparser.ConfigParser :param do_mass_weighting: Weight eigenvectors by mass. This is not usually required. :type do_mass_weighting: bool :param end_frame: The ending frame number of the rendered Animation (default=start_frame+n_frames-1) :type end_frame: int or None :param miller: Miller indices of view :type miller: 3-tuple of floats :param mode_index: id of mode; 0 corresponds to first mode in ascii file :type mode_index: int :param n_frames: Animation length of a single oscillation cycle in frames (default=30) :type n_frames: Positive int :param normalise_vectors: Re-scale vectors so largest arrow is fixed length :type normalise_vectors: bool :param offset_box: Position of bbox in lattice vector coordinates. Default (0,0,0) (Left front bottom) :type offset_box: Vector or 3-tuple :param preview: Enable preview mode - single frame, smaller render :type preview: bool :param scale_arrow: Scale factor for arrows :type scale_arrow: float :param scale_atom: Scale of atoms, relative to covalent radius :type scale_atom: float :param scale_vib: Scale factor for oscillations (angstroms / normalised eigenvector). :type scale_vib: float :param show_box: If True, show bounding box :type show_box: bool :param start_frame: The starting frame number of the rendered animation (default=0) :type start_frame: int or None :param static: if True, ignore frame range and use single frame. Otherwise, add animation keyframes. :type static: bool :param supercell: supercell dimensions :type supercell: 3-tuple or 3-list of ints :param vectors: If True, show arrows :type vectors: bool :param zoom: Camera zoom adjustment :type zoom: float """ # Initialise Opts object, accessing options and user config opts = vsim2blender.Opts(options) # Work out actual frame range. # Priority goes 1. static/preview 2. end_frame 3. n_frames start_frame = opts.get('start_frame', 0) n_frames = opts.get('n_frames', 30) # Preview images default to static, others default to animated preview = opts.get('preview', False) if preview: static = opts.get('static', True) else: static = opts.get('static', False) if static: end_frame = start_frame else: end_frame = opts.get('end_frame', start_frame + n_frames - 1) input_file = opts.get('input_file', False) if input_file: (vsim_cell, positions, symbols, vibs) = import_vsim(input_file) lattice_vectors = cell_vsim_to_vectors(vsim_cell) else: raise Exception('No .ascii file provided') if opts.get('do_mass_weighting', False): masses = [float(opts.config['masses'][symbol]) for symbol in symbols] else: masses = [1 for symbol in symbols] # Switch to a new empty scene bpy.ops.scene.new(type='EMPTY') # Draw bounding box if (opts.get('show_box', True)): bbox_offset = opts.get('offset_box', (0, 0, 0)) bbox_offset = Vector(bbox_offset) draw_bounding_box(lattice_vectors, offset=bbox_offset) # Draw atoms after checking config mode_index = opts.get('mode_index', 0) supercell = (opts.get('supercell', (2, 2, 2))) vectors = opts.get('vectors', False) normalise_vectors = opts.get('normalise_vectors', False) # Variable for tracking largest arrow max_vector = 0 arrow_objects = [] for cell_id_tuple in itertools.product(range(supercell[0]), range(supercell[1]), range(supercell[2])): cell_id = Vector(cell_id_tuple) for (atom_index, (position, symbol, mass)) in enumerate(zip(positions, symbols, masses)): atom = add_atom(position, lattice_vectors, symbol, cell_id=cell_id, name='{0}_{1}_{2}{3}{4}'.format( atom_index, symbol, *cell_id_tuple), config=opts.config) if vectors or not static: displacement_vector = vibs[mode_index].vectors[atom_index] qpt = vibs[mode_index].qpt B = (2 * math.pi * Matrix(lattice_vectors).inverted().transposed()) qpt_cartesian = Vector(qpt) * B if not static: animate_atom_vibs(atom, qpt_cartesian, displacement_vector, start_frame=start_frame, end_frame=end_frame, n_frames=n_frames, magnitude=opts.get('scale_vib', 1.), mass=mass) if vectors: arrow_vector = vector_with_phase(atom, qpt_cartesian, displacement_vector) max_vector = max(max_vector, arrow_vector.length) loc = absolute_position(position, lattice_vectors=lattice_vectors, cell_id=cell_id) # Arrows are scaled by eigenvector magnitude arrow_objects.append( add_arrow(loc=loc, mass=mass, rot_euler=vector_to_euler(arrow_vector), scale=arrow_vector.length)) if vectors: col = str2list(opts.config.get('colours', 'arrow', fallback='0. 0. 0.')) bpy.data.materials['Arrow'].diffuse_color = col # Rescaling; either by clamping max or accounting for cell size if vectors and normalise_vectors: scale = opts.get('scale_arrow', 1.) / max_vector for arrow in arrow_objects: arrow.scale *= scale elif vectors: scale = opts.get('scale_arrow', 1.) * len(positions) for arrow in arrow_objects: arrow.scale *= scale # Position camera and colour world. Note that cameras as objects and # cameras as 'cameras' have different attributes, so need to look up # camera in bpy.data.cameras to set field of view. camera.setup_camera(lattice_vectors, field_of_view=0.2, opts=opts) bpy.context.scene.world = bpy.data.worlds['World'] bpy.data.worlds['World'].horizon_color = str2list(opts.config.get( 'colours', 'background', fallback='0.5 0.5 0.5'))