def do(self): universe = context.application.model.universe scaling = numpy.dot(self.parameters.matrix, numpy.linalg.inv(universe.cell.matrix)) primitive.SetProperty( universe, "cell", universe.cell.copy_with(matrix=self.parameters.matrix)) for child in universe.children: if isinstance(child, GLTransformationMixin) and isinstance( child.transformation, Translation): new_transformation = child.transformation.copy_with( t=numpy.dot(scaling, child.transformation.t)) primitive.SetProperty(child, "transformation", new_transformation)
def do(self): victims = context.application.cache.nodes edit_properties = context.application.edit_properties # Copy the old state, only the supported field names old_states = {} for victim in victims: old_state = victim.__getstate__() tmp = {} for attribute_name in edit_properties.attribute_names: value = old_state.get(attribute_name, None) if value is not None: tmp[attribute_name] = value old_states[victim] = tmp # Let the user make changes edit_properties.run(victims) for changed_name in edit_properties.changed_names: for victim, old_state in old_states.iteritems(): old_value = old_state.get(changed_name) if old_value is None: old_value = victim.properties_by_name[ changed_name].default(victim) primitive.SetProperty(victim, changed_name, old_value, done=True)
def do(self): # A) collect all extra attributes of the selected nodes extra_attrs = {} for node in context.application.cache.nodes: for key, value in node.extra.iteritems(): other_value = extra_attrs.get(key) if other_value is None: extra_attrs[key] = value elif isinstance(other_value, Undefined): continue elif other_value != value: extra_attrs[key] = Undefined() for key, value in extra_attrs.items(): if isinstance(value, Undefined): continue for node in context.application.cache.nodes: other_value = node.extra.get(key) if other_value != value: extra_attrs[key] = Undefined() break # B) present the extra attributes in a popup window with editing features extra_dialog = ExtraDialog() modified_extra_attrs, remove_keys = extra_dialog.run(extra_attrs) if len(modified_extra_attrs) > 0 or len(remove_keys) > 0: # C) the modified extra attributes are applied to the select objects for node in context.application.cache.nodes: new_value = node.extra.copy() new_value.update(modified_extra_attrs) for remove_key in remove_keys: new_value.pop(remove_key, None) primitive.SetProperty(node, "extra", new_value)
def do(self): cache = context.application.cache graph = create_molecular_graph(cache.nodes) parent = cache.node Frame = context.application.plugins.get_node("Frame") for group in graph.independent_vertices: atoms = [graph.molecule.atoms[i] for i in group] new_positions = self.calc_new_positions(group, atoms, graph, parent) if new_positions is None: # this happens for groups of atoms that are inherently periodic. continue frame = Frame(name=chemical_formula(atoms)[1]) primitive.Add(frame, parent, index=0) for node, atom in zip(group, atoms): primitive.Move(atom, frame) new_position = new_positions[node] translation = Translation( atom.get_parentframe_up_to(parent).inv * new_position) primitive.SetProperty(atom, "transformation", translation) for atom in atoms: # take a copy of the references since they are going to be # refreshed (changed and reverted) during the loop. for reference in list(atom.references): referent = reference.parent if referent.parent != frame: has_to_move = True for child in referent.children: if child.target.parent != frame: has_to_move = False break if has_to_move: primitive.Move(referent, frame)
def fn(): from molmod import UnitCell context.application.model.file_open("test/input/methane_box22_125.xyz") universe = context.application.model.universe context.application.action_manager.record_primitives = False unit_cell = UnitCell( numpy.identity(3, float) * 22 * angstrom, numpy.ones(3, bool)) primitive.SetProperty(universe, "cell", unit_cell) context.application.main.select_nodes([universe]) AutoConnectPhysical = context.application.plugins.get_action( "AutoConnectPhysical") assert AutoConnectPhysical.analyze_selection() AutoConnectPhysical() context.application.main.select_nodes([universe]) FrameMolecules = context.application.plugins.get_action( "FrameMolecules") assert FrameMolecules.analyze_selection() FrameMolecules() Bond = context.application.plugins.get_node("Bond") for frame in universe.children: for bond in frame.children: if isinstance(bond, Bond): bond.calc_vector_dimensions() assert bond.length < 2 * angstrom
def do(self): counter = 1 for node in context.application.cache.children: if isinstance(node, Atom): primitive.SetProperty( node, "name", periodic[node.number].symbol + str(counter)) counter += 1
def do(self): victim = context.application.cache.node Frame = context.application.plugins.get_node("Frame") frame = Frame(name="Frame of " + victim.name) primitive.Add(frame, victim.parent, index=victim.get_index()) primitive.Transform(frame, victim.transformation) primitive.Move(victim, frame) primitive.SetProperty(victim, "transformation", victim.Transformation())
def do(self): universe = context.application.cache.node # first make sure the cell is right handed if numpy.linalg.det( universe.cell.matrix) < 0 and universe.cell.active.sum() == 3: new_matrix = universe.cell.matrix.copy() temp = new_matrix[:, 0].copy() new_matrix[:, 0] = new_matrix[:, 1] new_matrix[:, 1] = temp new_cell = UnitCell(new_matrix, universe.cell.active) primitive.SetProperty(universe, "cell", new_cell) # then rotate the unit cell box to the normalized frame: rotation = universe.cell.alignment_a for child in context.application.cache.transformed_children: primitive.Transform(child, rotation) new_cell = UnitCell(numpy.dot(rotation.r, universe.cell.matrix), universe.cell.active) primitive.SetProperty(universe, "cell", new_cell)
def finish(self): if self.changed: self.parameters.transformation = self.old_transformation.inv * self.victim.transformation primitive.SetProperty(self.victim, "transformation", self.old_transformation, done=True) self.victim.invalidate_transformation_list( ) # make sure that bonds and connectors are updated after transformation InteractiveWithMemory.finish(self)
def apply_normal(self): model, iter = self.tree_selection.get_selected() parent = self.frame2 if parent.parent is not None: parent = parent.parent transformation = self.frame1.get_frame_relative_to(parent) if self.cb_inverse.get_active() and len(model.get_value(iter, 3)[3]) > 0: transformation = model.get_value(iter, 3)[1].inv * transformation else: transformation = model.get_value(iter, 3)[1] * transformation primitive.SetProperty(self.frame2, "transformation", transformation)
def do(self): universe = context.application.model.universe for child in universe.children: if isinstance(child, GLTransformationMixin) and isinstance( child.transformation, Translation): cell_index = universe.cell.to_fractional( child.transformation.t) cell_index = numpy.floor(cell_index) if cell_index.any(): t = child.transformation.t - universe.cell.to_cartesian( cell_index) new_transformation = child.transformation.copy_with(t=t) primitive.SetProperty(child, "transformation", new_transformation)
def do(self): vectors = context.application.cache.nodes universe = context.application.model.root[0] new_cell = universe.cell try: for vector in vectors: new_cell = new_cell.add_cell_vector( vector.shortest_vector_relative_to(universe)) except ValueError: if len(vectors) == 1: raise UserError( "Failed to add the selected vector as cell vector since it would make the unit cell singular." ) else: raise UserError( "Failed to add the selected vectors as cell vectors since they would make the unit cell singular." ) primitive.SetProperty(universe, "cell", new_cell)
def do(self): for vector in context.application.cache.nodes: primitive.SetProperty(vector, "targets", vector.get_targets()[::-1])
def do(self): # the indices (n,m) that define the tube, see e.g. the wikipedia page # about nanotubes for the interpretation of these indices: # http://en.wikipedia.org/wiki/Carbon_nanotube n = self.parameters.n m = self.parameters.m periodic_tube = isinstance(self.parameters.tube_length, Undefined) universe = context.application.model.universe def define_flat(): "Reads and converts the unit cell vectors from the current model." # some parts of the algorithm have been arranged sub functions like # these, to reduce the number of local variables in self.do. This # should also clarify the code. active, inactive = universe.cell.active_inactive lengths, angles = universe.cell.parameters a = lengths[active[0]] b = lengths[active[1]] theta = angles[inactive[0]] return (numpy.array([a, 0], float), numpy.array([b * numpy.cos(theta), b * numpy.sin(theta)], float)) flat_a, flat_b = define_flat() def create_pattern(): "Read the atom positions and transform them to the flat coordinates" active, inactive = universe.cell.active_inactive a = universe.cell.matrix[:, active[0]] b = universe.cell.matrix[:, active[1]] c = numpy.cross(a, b) tmp_cell = UnitCell(numpy.array([a, b, c]).transpose()) rotation = tmp_cell.alignment_a return [(atom.number, rotation * atom.get_absolute_frame().t) for atom in iter_atoms([universe])] pattern = create_pattern() def define_big_periodic(): "Based on (n,m) calculate the size of the periodic sheet (that will be folded into a tube)." big_a = n * flat_a - m * flat_b norm_a = numpy.linalg.norm(big_a) radius = norm_a / (2 * numpy.pi) big_x = big_a / norm_a big_y = numpy.array([-big_x[1], big_x[0]], float) big_b = None stack_vector = flat_b - flat_a * numpy.dot( big_x, flat_b) / numpy.dot(big_x, flat_a) stack_length = numpy.linalg.norm(stack_vector) nominator = numpy.linalg.norm(stack_vector - flat_b) denominator = numpy.linalg.norm(flat_a) fraction = nominator / denominator stack_size = 1 while True: repeat = fraction * stack_size if stack_length * stack_size > self.parameters.max_length: break if abs(repeat - round(repeat) ) * denominator < self.parameters.max_error: big_b = stack_vector * stack_size break stack_size += 1 if big_b is None: raise UserError( "Could not create a periodic tube shorter than the given maximum length." ) rotation = numpy.array([big_x, big_y], float) return big_a, big_b, rotation, stack_vector, stack_size, radius def define_big_not_periodic(): "Based on (n,m) calculate the size of the non-periodic sheet (that will be folded into a tube)." big_a = n * flat_a - m * flat_b norm_a = numpy.linalg.norm(big_a) radius = norm_a / (2 * numpy.pi) big_x = big_a / norm_a big_y = numpy.array([-big_x[1], big_x[0]], float) stack_vector = flat_b - flat_a * numpy.dot( big_x, flat_b) / numpy.dot(big_x, flat_a) stack_length = numpy.linalg.norm(stack_vector) stack_size = int(self.parameters.tube_length / stack_length) big_b = stack_vector * stack_size rotation = numpy.array([big_x, big_y], float) return big_a, big_b, rotation, stack_vector, stack_size, radius if periodic_tube: big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_periodic( ) else: big_a, big_b, rotation, stack_vector, stack_size, radius = define_big_not_periodic( ) def iter_translations(): "Yields the indices of the periodic images that are part of the tube." to_fractional = numpy.linalg.inv( numpy.array([big_a, big_b]).transpose()) col_len = int( numpy.linalg.norm(big_a + m * stack_vector) / numpy.linalg.norm(flat_a)) + 4 shift = numpy.dot(stack_vector - flat_b, flat_a) / numpy.linalg.norm(flat_a)**2 for row in xrange(-m - 1, stack_size + 1): col_start = int(numpy.floor(row * shift)) - 1 for col in xrange(col_start, col_start + col_len): p = col * flat_a + row * flat_b i = numpy.dot(to_fractional, p) if (i >= 0).all() and (i < 1 - 1e-15).all(): yield p #yield p, (i >= 0).all() and (i < 1).all() def iter_pattern(): for number, coordinate in pattern: yield number, coordinate.copy() # first delete everything the universe: while len(universe.children) > 0: primitive.Delete(universe.children[0]) # add the new atoms Atom = context.application.plugins.get_node("Atom") if self.parameters.flat: rot_a = numpy.dot(rotation, big_a) rot_b = numpy.dot(rotation, big_b) big_matrix = numpy.array([ [rot_a[0], rot_b[0], 0], [rot_a[1], rot_b[1], 0], [0, 0, 10 * angstrom], ], float) big_cell = UnitCell( big_matrix, numpy.array([True, periodic_tube, False], bool)) primitive.SetProperty(universe, "cell", big_cell) for p in iter_translations(): for number, coordinate in iter_pattern(): coordinate[:2] += p coordinate[:2] = numpy.dot(rotation, coordinate[:2]) translation = Translation(coordinate) primitive.Add( Atom(number=number, transformation=translation), universe) else: tube_length = numpy.linalg.norm(big_b) big_matrix = numpy.diag([radius * 2, radius * 2, tube_length]) big_cell = UnitCell( big_matrix, numpy.array([False, False, periodic_tube], bool)) primitive.SetProperty(universe, "cell", big_cell) for p in iter_translations(): for number, coordinate in iter_pattern(): coordinate[:2] += p coordinate[:2] = numpy.dot(rotation, coordinate[:2]) translation = Translation( numpy.array([ (radius + coordinate[2]) * numpy.cos(coordinate[0] / radius), (radius + coordinate[2]) * numpy.sin(coordinate[0] / radius), coordinate[1], ])) primitive.Add( Atom(number=number, transformation=translation), universe)
def do(self): cache = context.application.cache parent = cache.parent involved_frames = cache.spring_problem.frames springs = cache.spring_problem.springs max_step = [] old_transformations = [(frame, frame.transformation) for frame in involved_frames if frame is not None] variable_indices = dict((frame, index) for index, frame in enumerate( frame for frame in involved_frames if frame is not None)) cost_function = iterative.expr.Root(1, 10, True) for frame in involved_frames: if frame is None: pass elif self.parameters.allow_rotation and isinstance( frame.transformation, Complete): variable = iterative.var.Frame( frame.transformation.r, frame.transformation.t, ) cost_function.register_state_variable(variable) constraint = iterative.expr.Orthonormality(1e-10) constraint.register_input_variable(variable) max_step.extend([ 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 1.0, 1.0, 1.0 ]) elif isinstance(frame.transformation, Translation): variable = iterative.var.Translation( frame.transformation.r, frame.transformation.t, ) cost_function.register_state_variable(variable) max_step.extend([1.0, 1.0, 1.0]) else: raise UserError( "The involved frames shoud be at least capable of being translated." ) for spring, frames in springs.iteritems(): spring_term = iterative.expr.Spring(spring.rest_length) for target, frame in frames.iteritems(): if frame is None: spring_term.register_input_variable( iterative.expressions.NoFrame(), target.get_frame_up_to(parent).t) else: spring_term.register_input_variable( cost_function.state_variables[variable_indices[frame]], target.get_frame_up_to(frame).t) max_step = numpy.array(max_step, float) minimize = iterative.alg.DefaultMinimize( cost_function, max_step, max_step * 1e-8, ) result = self.report_dialog.run( minimize, involved_frames, self.parameters.update_interval, self.parameters.update_steps, len(springs), ) if result != gtk.RESPONSE_OK: for frame, transformation in old_transformations: frame.transformation = transformation frame.invalidate_transformation_list() raise CancelException for frame, transformation in old_transformations: primitive.SetProperty( frame, "transformation", transformation, done=True, )
def do(self): # create the repetitions vector repetitions = [] if hasattr(self.parameters, "repetitions_a"): repetitions.append(self.parameters.repetitions_a) else: repetitions.append(1) if hasattr(self.parameters, "repetitions_b"): repetitions.append(self.parameters.repetitions_b) else: repetitions.append(1) if hasattr(self.parameters, "repetitions_c"): repetitions.append(self.parameters.repetitions_c) else: repetitions.append(1) repetitions = numpy.array(repetitions, int) # serialize the positioned children universe = context.application.model.universe positioned = [ node for node in universe.children if (isinstance(node, GLTransformationMixin) and isinstance(node.transformation, Translation)) ] if len(positioned) == 0: return serialized = StringIO.StringIO() dump_to_file(serialized, positioned) # create the replica's # replicate the positioned objects new_children = {} for cell_index in iter_all_positions(repetitions): cell_index = numpy.array(cell_index) cell_hash = tuple(cell_index) serialized.seek(0) nodes = load_from_file(serialized) new_children[cell_hash] = nodes for node in nodes: t = node.transformation.t + numpy.dot(universe.cell.matrix, cell_index) new_transformation = node.transformation.copy_with(t=t) node.set_transformation(new_transformation) # forget about serialized stuff serialized.close() del serialized new_connectors = [] # replicate the objects that connect these positioned objects for cell_index in iter_all_positions(repetitions): cell_index = numpy.array(cell_index) cell_hash = tuple(cell_index) for connector in universe.children: # Only applicable to ReferentMixin with only SpatialReference # children if not isinstance(connector, ReferentMixin): continue skip = False for reference in connector.children: if not isinstance(reference, SpatialReference): skip = True break if skip: continue # first locate the new first target for this cell_index first_target_orig = connector.children[0].target first_target_index = positioned.index(first_target_orig) first_target = new_children[cell_hash][first_target_index] assert first_target is not None new_targets = [first_target] for reference in connector.children[1:]: # then find the other new targets, taking into account # periodicity other_target_orig = reference.target shortest_vector = universe.shortest_vector( (other_target_orig.transformation.t - first_target_orig.transformation.t)) translation = first_target.transformation.t + shortest_vector other_target_pos = translation other_cell_index = numpy.floor( universe.cell.to_fractional(other_target_pos)).astype( int) other_cell_index %= repetitions other_cell_hash = tuple(other_cell_index) other_target_index = positioned.index(other_target_orig) other_cell_children = new_children.get(other_cell_hash) assert other_cell_children is not None other_target = other_cell_children[other_target_index] assert other_target is not None new_targets.append(other_target) state = connector.__getstate__() state["targets"] = new_targets new_connectors.append(connector.__class__(**state)) # remove the existing nodes while len(universe.children) > 0: primitive.Delete(universe.children[0]) del positioned # multiply the cell matrix and reset the number of repetitions new_matrix = universe.cell * repetitions primitive.SetProperty(universe, "cell", new_matrix) primitive.SetProperty(universe, "repetitions", numpy.array([1, 1, 1], int)) # add the new nodes for nodes in new_children.itervalues(): for node in nodes: primitive.Add(node, universe) for connector in new_connectors: primitive.Add(connector, universe)
def extend_to_cluster(axis, interval): if (interval is None) or isinstance(interval, Undefined): return assert universe.cell.active[axis] interval.sort() index_min = int(numpy.floor(interval[0])) index_max = int(numpy.ceil(interval[1])) old_points = [ node for node in universe.children if (isinstance(node, GLTransformationMixin) and isinstance(node.transformation, Translation)) ] if len(old_points) == 0: return old_connections = [ node for node in universe.children if (isinstance(node, ReferentMixin) and reduce( (lambda x, y: x and y), (isinstance(child, SpatialReference) for child in node.children), True, )) ] # replication of the points new_points = {} for old_point in old_points: # determine the wrapped position old_pos = old_point.transformation.t.copy() old_frac = universe.cell.to_fractional(old_pos) old_index = numpy.floor(old_frac).astype(int) old_pos -= universe.cell.to_cartesian(old_index) old_frac -= old_index del old_index # make copies for cell_index in xrange(index_min, index_max): position = old_pos + universe.cell.matrix[:, axis] * cell_index if (old_frac[axis] + cell_index < interval[0]) or ( old_frac[axis] + cell_index > interval[1]): continue state = old_point.__getstate__() state["transformation"] = state[ "transformation"].copy_with(t=position) new_point = old_point.__class__(**state) new_points[(old_point, cell_index)] = new_point new_connections = [] # replication of the connections for cell_index in xrange(index_min - 1, index_max + 1): for connection in old_connections: old_target0 = connection.children[0].target new_target0 = new_points.get((old_target0, cell_index)) if new_target0 is None: continue new_targets = [new_target0] for reference in connection.children[1:]: abort = True old_target1 = reference.target for offset in 0, 1, -1: new_target1 = new_points.get( (old_target1, cell_index + offset)) if new_target1 is not None: delta = new_target0.transformation.t - new_target1.transformation.t if vector_acceptable( delta, universe.cell.matrix[:, axis]): new_targets.append(new_target1) abort = False break if abort: break if abort: del new_targets continue state = connection.__getstate__() state["targets"] = new_targets new_connections.append(connection.__class__(**state)) # remove the existing points and connections for node in old_connections: primitive.Delete(node) del old_connections for node in old_points: primitive.Delete(node) del old_points # remove the periodicity new_active = universe.cell.active.copy() new_active[axis] = False new_cell = universe.cell.copy_with(active=new_active) primitive.SetProperty(universe, "cell", new_cell) # add the new nodes for node in new_points.itervalues(): primitive.Add(node, universe) for connection in new_connections: primitive.Add(connection, universe)
def do(self): for node in context.application.cache.transformed_nodes: primitive.SetProperty(node, "transformation", node.Transformation.identity())
def do(self): class Record(object): def __init__(self, name, quaternion): self.name = name self.quaternion = quaternion self.cost_function = 0.0 rounded_quaternions = [] cache = context.application.cache if len(cache.nodes) == 1: victim = cache.last master = None factor, selected_quaternion = rotation_matrix_to_quaternion( victim.transformation.r) elif len(cache.nodes) == 2: master = cache.last victim = cache.next_to_last factor, selected_quaternion = rotation_matrix_to_quaternion( victim.get_frame_relative_to(master).r) step = 15 for axis_name, axis in self.axes.iteritems(): for angle_index in xrange(1, 360 / step): angle = angle_index * step name = "%s (%s)" % (axis_name, angle) rad = angle * numpy.pi / 360 quaternion = numpy.concatenate( ([numpy.cos(rad)], numpy.sin(rad) * axis), 1) rounded_quaternions.append(Record(name, quaternion)) new_quaternions = [ Record("Identity", numpy.array([1.0, 0.0, 0.0, 0.0])) ] for record1 in rounded_quaternions: for record2 in rounded_quaternions: if record1.name[0] != record2.name[0]: new_quaternions.append( Record( "%s after %s" % (record1.name, record2.name), quaternion_product(record1.quaternion, record2.quaternion))) def filter_out_high_cost(records): for record in records: #print selected_quaternion, record.quaternion cosine = numpy.dot(selected_quaternion, record.quaternion) if cosine > 1: cosine = 1 elif cosine < -1: cosine = -1 cost_function = int(numpy.arccos(cosine) * 180.0 / numpy.pi) if cost_function < 10: record.cost_function = cost_function else: record.quaternion = None return filter(lambda record: record.quaternion is not None, records) new_quaternions = filter_out_high_cost(new_quaternions) for index1, record1 in enumerate(new_quaternions): if record1.quaternion is not None: for record2 in new_quaternions[:index1]: if record2.quaternion is not None: if 1 - numpy.dot(record1.quaternion, record2.quaternion) < 1e-3: record2.quaternion = None for record2 in rounded_quaternions: if 1 - numpy.dot(record1.quaternion, record2.quaternion) < 1e-3: record1.quaternion = None break new_quaternions = filter(lambda record: record.quaternion is not None, new_quaternions) rounded_quaternions = filter_out_high_cost(rounded_quaternions) rounded_quaternions.extend(new_quaternions) if len(rounded_quaternions) == 0: raise UserError("No similar rounded rotations found.") rounded_quaternions.sort(key=(lambda x: x.cost_function)) self.select_quaternion.main_field.records = rounded_quaternions user_record = Record("", rounded_quaternions[0].quaternion) if self.select_quaternion.run(user_record) != gtk.RESPONSE_OK: raise CancelException if user_record.quaternion is not None: if len(cache.nodes) == 1: r = factor * quaternion_to_rotation_matrix( user_record.quaternion) new_transformation = victim.transformation.copy_with(r=r) primitive.SetProperty(victim, "transformation", new_transformation) elif len(cache.nodes) == 2: r = numpy.dot( master.get_frame_relative_to(victim).r, factor * quaternion_to_rotation_matrix(user_record.quaternion), ) old_transformation = victim.transformation.copy_with(r=r) primitive.SetProperty(victim, "transformation", old_transformation, done=True)