def do(self): Atom = context.application.plugins.get_node("Atom") def iter_all_tetra(nodes): for node in nodes: if isinstance(node, Atom) and node.number > 12: yield node elif isinstance(node, ContainerMixin): for tetra in iter_all_tetra(node.children): yield tetra coordinated_tetra = [[] for i in xrange(5)] for tetra in iter_all_tetra( context.application.cache.nodes_without_children): coordination = 0 for bridging in tetra.iter_neighbors(): if bridging.number > 6: num_t = len([ t for t in bridging.iter_neighbors() if t.number > 12 ]) if num_t > 2: raise UserError("Invalid zeolite structure.") if num_t == 2: coordination += 1 if coordination > 4: raise UserError("Invalid zeolite structure.") coordinated_tetra[coordination].append(tetra) result_dialog = CoordinationDialog(coordinated_tetra) response = result_dialog.run() if response != gtk.RESPONSE_CLOSE: main = context.application.main main.select_nodes(coordinated_tetra[response])
def do(self): for key, val in self.parameters.__dict__.iteritems(): if isinstance(val, Expression): val.compile_as("<%s>" % key) val.variables = (key[7:11], ) parent = context.application.cache.common_parent if parent is None: parent = context.application.model.universe angles = [] graph = create_molecular_graph(context.application.cache.nodes) match_definition = BendingAnglePattern(criteria_sets=[ CriteriaSet( thing_criteria={ 0: IndexToAtoms(self.parameters.filter_atom1), 1: IndexToAtoms(self.parameters.filter_atom2), 2: IndexToAtoms(self.parameters.filter_atom3), }, relation_criteria={ 0: IndexToBonds(self.parameters.filter_bond12), 1: IndexToBonds(self.parameters.filter_bond23), }, ) ], ) try: atoms = graph.molecule.atoms match_generator = GraphSearch(match_definition) for match in match_generator(graph): point1 = atoms[match.forward[0]].get_absolute_frame().t point2 = atoms[match.forward[1]].get_absolute_frame().t point3 = atoms[match.forward[2]].get_absolute_frame().t delta1 = parent.shortest_vector(point2 - point1) delta2 = parent.shortest_vector(point2 - point3) if numpy.linalg.norm(delta1) > 1e-8 and \ numpy.linalg.norm(delta2) > 1e-8: angles.append(angle(delta1, delta2)) except: raise UserError( "An error occured while sampling the bending angles.", "If this is an error in one of the filter expressions,\n" + "one should see the expression mentioned below as <filter_...>.\n\n" ) comments = [ "atom 1 filter expression: %s" % self.parameters.filter_atom1.code, "bond 1-2 filter expression: %s" % self.parameters.filter_bond12.code, "atom 2 filter expression: %s" % self.parameters.filter_atom2.code, "bond 2-3 filter expression: %s" % self.parameters.filter_bond23.code, "atom 3 filter expression: %s" % self.parameters.filter_atom3.code, ] if len(angles) > 0: distribution_dialog = DistributionDialog() distribution_dialog.run(numpy.array(angles), "Angle", "Bending angle", comments) else: raise UserError("No bending angles match the given criteria.")
def read_mopac_output(self, filename, num_atoms): if not os.path.isfile(filename): raise UserError("Could not find Mopac output file.", "Expected location of output file: %s" % filename) f = open(filename, 'r') coordinates = numpy.zeros((num_atoms, 3), float) success = False for line in f: if line == " CARTESIAN COORDINATES \n": break for line in f: if line == " CARTESIAN COORDINATES \n": success = True break if success: for i in xrange(3): f.next() i = 0 for line in f: if i < num_atoms: words = line.split() coordinates[i, 0] = float(words[2]) coordinates[i, 1] = float(words[3]) coordinates[i, 2] = float(words[4]) i += 1 else: break else: raise UserError("Could not find optimal coordinates.", "Check the file %s for more details." % filename) f.close() return coordinates * angstrom
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 do(self): cache = context.application.cache parents = cache.nodes containers = cache.containers_with_children main = context.application.main def toggle_children(parent): for node in parent.children: match = self.parameters.expression(node) if match: main.toggle_selection(node, on=True) if ((self.parameters.recursive == self.SELECT_RECURSIVE_IF_MATCH) and match) or (self.parameters.recursive == self.SELECT_RECURSIVE): if isinstance(node, ParentMixin): toggle_children(node) for parent in parents: main.toggle_selection(parent, on=False) try: for container in containers: toggle_children(container) except Exception: main.tree_selection.unselect_all() for parent in parents: main.toggle_selection(parent, on=True) raise UserError("An exception occured while evaluating the filter expression.")
def get_parameters(node, point_type, geometry_index, filter_expression, radius_expression): template = "An exception occured in the %%s expression\nfor the %s points of geometry %i." % ( point_type, geometry_index + 1) try: is_type = filter_expression(node) except Exception: raise UserError(template % "filter") if is_type: try: radius = radius_expression(node) except Exception: raise UserError(template % "radius") geometry_nodes[geometry_index].append(node) return True, radius else: return False, None
def do(self): frame_ref = context.application.cache.nodes[0] graph_ref = create_molecular_graph([frame_ref]) try: match_generator = GraphSearch(EqualPattern(graph_ref)) except GraphError, e: raise UserError( "Could not setup a graph match definition to clone the order.")
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): parent = context.application.cache.node org_mol = create_molecule([parent], parent) org_coords = org_mol.coordinates if org_mol.size == 0: raise UserError( "Could not get molecule.", "Make sure that the selected frame contains a molecule.") if org_mol.size == 3: raise UserError("For the moment three atoms are not supported.") # Make temp directory work = tempfile.mkdtemp("_zeobuilder_mopac") # Create mopac input file self.write_mopac_input(org_mol, os.path.join(work, 'mopac')) # Run input file through mopac and capture output in file object retcode = os.system('cd %s; run_mopac7 mopac > mopac.stdout' % work) if retcode != 0: raise UserError( "Failed to run Mopac.", "Check that the run_mopac7 binary is in the path. The input file can be found here: %s." % work) opt_coords = self.read_mopac_output(os.path.join(work, 'mopac.OUT'), org_mol.size) # clean up def safe_remove(filename): filename = os.path.join(work, filename) if os.path.isfile(filename): os.remove(filename) safe_remove("mopac.dat") safe_remove("mopac.log") safe_remove("mopac.stdout") safe_remove("mopac.OUT") safe_remove("mopac.arc") os.rmdir(work) coords_to_zeobuilder(org_coords, opt_coords, org_mol.atoms, parent)
def iter_hits(self, selection_box): if not self.get_gl_drawable().gl_begin(self.get_gl_context()): return vb = context.application.vis_backend try: for selection in vb.draw(self.allocation.width, self.allocation.height, selection_box): yield vb.names.get(selection[2][-1]) except GLerror, e: self.get_gl_drawable().gl_end() if e.errno[0] == 1283: raise UserError("Too many objects in selection. Increase selection buffer size.") else: raise
class CloneOrder(Immediate): description = "Apply the order of the first selection to all the other." menu_info = MenuInfo("default/_Object:tools/_Molecular:rearrange", "_Clone order", order=(0, 4, 1, 5, 0, 3)) authors = [authors.toon_verstraelen] @staticmethod def analyze_selection(): if not Immediate.analyze_selection(): return False cache = context.application.cache if len(cache.nodes) < 2: return False Frame = context.application.plugins.get_node("Frame") for cls in cache.classes: if not issubclass(cls, Frame): return False return True def do(self): frame_ref = context.application.cache.nodes[0] graph_ref = create_molecular_graph([frame_ref]) try: match_generator = GraphSearch(EqualPattern(graph_ref)) except GraphError, e: raise UserError( "Could not setup a graph match definition to clone the order.") some_failed = False all_failed = True for frame_other in context.application.cache.nodes[1:]: graph_other = create_molecular_graph([frame_other]) try: match = match_generator(graph_other).next() all_failed = False except (StopIteration, GraphError): some_failed = True continue moves = [(index1, graph_other.molecule.atoms[index2]) for index1, index2 in match.forward.iteritems()] moves.sort() for new_index, atom2 in moves: primitive.Move(atom2, frame_other, new_index) if all_failed: raise UserError("None of the atom orders could be cloned.") elif some_failed: ok_error( "Some molecules/frames did not match the first frame, so they are not reordered." )
def erase_at(self, p, parent): for node in context.application.main.drawing_area.iter_hits( (p[0] - 2, p[1] - 2, p[0] + 2, p[1] + 2)): try: match = (node is not None and node != parent and node.is_indirect_child_of(parent) and node.model == context.application.model and (not self.cb_erase_filter.get_active() or self.erase_filter(node))) except Exception: raise UserError( "An exception occured while evaluating the erase filter expression." ) if match: primitive.Delete(node)
def do(self): # Get the molecular graph of the molecule in the selection parent = context.application.cache.node graph = create_molecular_graph([parent], parent) if graph.molecule.size == 0: raise UserError( "Could not get molecular graph.", "Make sure that the selected frame contains a molecule.") # Guessed and original geometry opt_coords = tune_geometry(graph, graph.molecule).coordinates org_coords = graph.molecule.coordinates coords_to_zeobuilder(org_coords, opt_coords, graph.molecule.atoms, parent, graph)
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): 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)