def _parse_special_cases(self, cmd, args, arguments, i, li): if cmd in ('TITL', 'REM'): args = args.strip() if args: arg_tuple = (args, ) else: arg_tuple = () return (cmd, arg_tuple) if cmd == 'SYMM': if args is None: raise shelx_error("illegal argument '%s'", i, args) return (cmd, (self.symm_space.sub('', args).upper(), )) if cmd == 'EQIV': m = self._eqiv_pat.search(args) if m is None: raise shelx_error("illegal argument '%s'", i, args) try: idx = int(m.group(1)) except ValueError: raise shelx_error("illegal argument '%s'", i, m.group(1)) return (cmd, (idx, self.symm_space.sub('', m.group(2)).upper())) if cmd == 'SFAC': sfac_args = [] for e in arguments: try: sfac_args.append(float(e)) except ValueError: sfac_args.append(e) return (cmd, tuple(sfac_args)) return None
def _parse_special_cases(self, cmd, args, arguments, i, li): if cmd in ("TITL", "REM"): args = args.strip() if args: arg_tuple = (args,) else: arg_tuple = () return (cmd, arg_tuple) if cmd == "SYMM": if args is None: raise shelx_error("illegal argument '%s'", i, args) return (cmd, (self.symm_space.sub("", args).upper(),)) if cmd == "EQIV": m = self._eqiv_pat.search(args) if m is None: raise shelx_error("illegal argument '%s'", i, args) try: idx = int(m.group(1)) except ValueError: raise shelx_error("illegal argument '%s'", i, m.group(1)) return (cmd, (idx, self.symm_space.sub("", m.group(2)).upper())) if cmd == "SFAC": sfac_args = [] for e in arguments: try: sfac_args.append(float(e)) except ValueError: sfac_args.append(e) return (cmd, tuple(sfac_args)) return None
def filtered_commands(self): active_afix = False for command, line in self.command_stream: cmd, args = command[0], command[-1] if cmd in ('AFIX', 'HKLF'): if cmd == 'AFIX' and not args: raise shelx_error("too few arguments", line) if active_afix: if n_afixed != n_expected_afixed: raise shelx_error("wrong number of afixed atoms", line) self.builder.end_geometrical_constraint() active_afix = False n_afixed = 0 if cmd == 'HKLF': yield command, line continue mn = args[0] if mn == 0: continue m,n = divmod(mn, 10) d, sof, u = (None,)*3 params = args[1:] if not params: pass elif len(params) == 1: d = params[0] elif len(params) == 3: d, sof = params[0:] elif len(params) == 4: d, sof, u = params[0:] else: raise shelx_error("too many arguments", line) info = self.constraints.get(m) if info is not None: constraint_name, pivot_relative_pos = info constraint_type = self.builder.make_geometrical_constraint_type( constraint_name) self.builder.start_geometrical_constraint( type_=constraint_type, bond_length=d, rotating=n in (7, 8), stretching=n in (4, 8), pivot_relative_pos=pivot_relative_pos) n_expected_afixed = constraint_type.n_constrained_sites active_afix = True n_afixed = 0 elif cmd == '__ATOM__': if active_afix: if sof is not None: args[4] = sof if u is not None and len(args) == 6: args[-1] = u n_afixed += 1 yield command, line else: yield command, line
def lex_scatterer(self, args, scatterer_index): name = args[0] n = int(args[1]) n_vars = len(args) - 2 if n_vars == 5 or (not self.strictly_shelxl and n_vars == 6): values, behaviours = self.decode_variables(args[2:7], u_iso_idx=n_vars - 1) u = values[4] isotropic = True elif n_vars == 10: unit_cell = self.builder.crystal_symmetry.unit_cell() values, behaviours = self.decode_variables( args[2:-3] + (args[-1], args[-2], args[-3]), u_iso_idx=None) u = adptbx.u_cif_as_u_star(unit_cell, values[-6:]) isotropic = False else: raise shelx_error("wrong number of parameters for scatterer", self.line) site = values[0:3] occ = values[3] scattering_type = eltbx.xray_scattering.get_standard_label( self.label_for_sfac[n], # works thank to (a) above exact=True) scatterer = xray.scatterer(label=name, site=site, occupancy=occ, u=u, scattering_type=scattering_type) if (not isotropic or not isinstance(behaviours[-1], tuple) or behaviours[-1][0] != constant_times_u_eq): self.scatterer_to_bind_u_eq_to = (scatterer, scatterer_index) return scatterer, behaviours
def _parse_general_case(self, cmd, cmd_residue, arguments, i, li): toks = [] for j, arg in enumerate(arguments): try: toks.append(float(arg)) except ValueError: if cmd == 'RESI': toks.append(arg) else: m = self._atom_name_pat.match(arg) if m is None: raise shelx_error("illegal argument '%s'", i, arg) name, symmetry, resnum, plus_minus = m.group( 'name', 'symmetry', 'resnum', 'plusminus') if name is not None: if resnum is not None: resnum = int(resnum) if symmetry is not None: symmetry = int(symmetry) toks.append( tokens.atomname_token(name=name, symmetry=symmetry, residue_number=resnum, plus_minus=plus_minus)) continue element, resnum = m.group('element', 'resnum') if element is not None: toks.append( tokens.element_token(element=element, residue_number=resnum)) continue if m.group('range') == '>': toks.append((tokens.forward_range_tok, )) elif m.group('range') == '<': toks.append((tokens.backward_range_tok, )) if cmd_residue: return (cmd, cmd_residue, tuple(toks)) else: if cmd not in self.shelx_commands: if cmd[0] == 'Q': toks = (int(cmd[1:]), ) + tuple(toks) cmd = '__Q_PEAK__' else: toks = (cmd, ) + tuple(toks) cmd = '__ATOM__' else: toks = tuple(toks) return (cmd, toks)
def _parse_general_case(self, cmd, cmd_residue, arguments, i, li): toks = [] for j, arg in enumerate(arguments): try: toks.append(float(arg)) except ValueError: if cmd == "RESI": toks.append(arg) else: m = self._atom_name_pat.match(arg) if m is None: raise shelx_error("illegal argument '%s'", i, arg) name, symmetry, resnum, plus_minus = m.group("name", "symmetry", "resnum", "plusminus") if name is not None: if resnum is not None: resnum = int(resnum) if symmetry is not None: symmetry = int(symmetry) toks.append( tokens.atomname_token( name=name, symmetry=symmetry, residue_number=resnum, plus_minus=plus_minus ) ) continue element, resnum = m.group("element", "resnum") if element is not None: toks.append(tokens.element_token(element=element, residue_number=resnum)) continue if m.group("range") == ">": toks.append((tokens.forward_range_tok,)) elif m.group("range") == "<": toks.append((tokens.backward_range_tok,)) if cmd_residue: return (cmd, cmd_residue, tuple(toks)) else: if cmd not in self.shelx_commands: if cmd[0] == "Q": toks = (int(cmd[1:]),) + tuple(toks) cmd = "__Q_PEAK__" else: toks = (cmd,) + tuple(toks) cmd = "__ATOM__" else: toks = tuple(toks) return (cmd, toks)
def process_possible_constrained_occupancy(self, scatterer_index, scatterer, occupancy_behaviour): if self.builder_does_occupancy_pair_affine_constraint: try: kind, coeff, free_var_idx = occupancy_behaviour except (TypeError, ValueError): pass else: if not self.free_variable: raise shelx_error("An instruction FVAR needs to appear before " "this point in the file,", self.line) coeff /= scatterer.weight_without_occupancy() r_coeff = scitbx.math.continued_fraction.from_real( coeff, eps=1e-5).as_rational() coeff = round(r_coeff.numerator()/r_coeff.denominator(), ndigits=5) if kind == constant_times_independent_scalar_parameter: self.occupancies_depending_on_free_variable.setdefault( free_var_idx, []).append((coeff, 0, scatterer_index)) elif kind == constant_times_independent_scalar_parameter_minus_1: self.occupancies_depending_on_free_variable.setdefault( free_var_idx, []).append((coeff, -1, scatterer_index))
def lex_scatterer(self, args, scatterer_index): name = args[0] n = int(args[1]) n_vars = len(args) - 2 if n_vars == 5 or (not self.strictly_shelxl and n_vars == 6): values, behaviours = self.decode_variables( args[2:7], u_iso_idx=n_vars-1) u = values[4] isotropic = True elif n_vars == 10: unit_cell = self.builder.crystal_symmetry.unit_cell() values, behaviours = self.decode_variables( args[2:-3] + (args[-1], args[-2], args[-3]), u_iso_idx=None) u = adptbx.u_cif_as_u_star(unit_cell, values[-6:]) isotropic = False else: raise shelx_error("wrong number of parameters for scatterer", self.line) site = values[0:3] occ = values[3] scattering_type = eltbx.xray_scattering.get_standard_label( self.label_for_sfac[n], # works thank to (a) above exact=True) scatterer = xray.scatterer( label = name, site = site, occupancy = occ, u = u, scattering_type = scattering_type) if (not isotropic or not isinstance(behaviours[-1], tuple) or behaviours[-1][0] != constant_times_u_eq): self.scatterer_to_bind_u_eq_to = (scatterer, scatterer_index) return scatterer, behaviours
def filtered_commands(self): from scitbx.math import continued_fraction temperature = 20 for command, line in self.command_stream: cmd, args = command[0], command[-1] n_args = len(args) if cmd == 'OMIT': if n_args == 3 and isinstance(args[0], float): self.instructions.setdefault('omit_hkl', []) self.instructions['omit_hkl'].append([int(i) for i in args]) elif n_args == 2 and isinstance(args[0], float): self.instructions['omit'] = { 's': args[0], 'two_theta': args[1]} else: yield command, line elif cmd == 'SHEL': if args: shel = {'lowres': args[0]} if n_args > 1: shel['highres'] = args[1] elif cmd == 'MERG': if args: self.instructions['merg'] = args[0] elif cmd == 'TEMP': if len(args) > 1: raise shelx_error("TEMP takes at most 1 argument") if args: temperature = args[0] self.instructions['temp'] = temperature self.builder.temperature_in_celsius = temperature elif cmd == 'WGHT': if n_args > 6: raise shelx_error("Too many argument for %s" % cmd, line) default_weighting_scheme = { 'a': 0.1, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 1/3 } weighting_scheme = dict([ (key, (arg is not None and arg) or default_weighting_scheme[key]) for key, arg in itertools.izip_longest('abcdef', args) ]) self.instructions['wght'] = weighting_scheme self.builder.make_shelx_weighting_scheme(**weighting_scheme) elif cmd == 'HKLF': # only ONE HKLF instruction allowed assert 'hklf' not in self.instructions hklf = {'s': 1, 'matrix': sgtbx.rot_mx()} hklf['n'] = args[0] if n_args > 1: hklf['s'] = args[1] if n_args > 2: assert n_args > 10 mx = [ continued_fraction.from_real(e, eps=1e-3).as_rational() for e in args[2:11] ] den = reduce(rational.lcm, [ r.denominator() for r in mx ]) nums = [ r.numerator()*(den//r.denominator()) for r in mx ] hklf['matrix'] = sgtbx.rot_mx(nums, den) if n_args > 11: hklf['wt'] = args[11] if n_args == 13: hklf['m'] = args[12] self.instructions['hklf'] = hklf assert not self.builder or ('wt' not in hklf and 'm' not in hklf) self.builder.create_shelx_reflection_data_source( format=hklf['n'], indices_transform=hklf['matrix'], data_scale=hklf['s']) if 'basf' in self.instructions and hklf['n'] == 5: self.builder.make_non_merohedral_twinning_with_transformed_hkl( fractions=self.instructions['basf']) elif cmd == 'TWIN': # only ONE twin instruction allowed assert 'twin' not in self.instructions twin = {} if n_args > 0: assert n_args >= 9 twin['matrix'] = sgtbx.rt_mx( sgtbx.rot_mx([int(i) for i in args[0:9]])) if n_args > 9: twin['n'] = args[9] self.instructions['twin'] = twin if 'basf' in self.instructions: self.issue_merohedral_twinning() elif cmd == 'BASF': self.instructions['basf'] = args if 'twin' in self.instructions: self.issue_merohedral_twinning() elif cmd == 'EXTI': if len(args) == 1: self.instructions['exti'] = args[0] else: yield command, line else: # All token have been read without errors or early bailout assert 'hklf' in self.instructions, "Missing HKLF instruction"
def filtered_commands(self): self.label_for_sfac = None overall_scale = None scatterer_index = 0 conformer_index = 0 sym_excl_index = 0 part_sof = None current_residue = (None, None) line_of_scatterer_named = {} in_the_midst_of_atom_list = False idx_assigned_by_builder_to_free_var_idx = {} builder = self.builder if self.builder_does_occupancy_pair_affine_constraint: self.occupancies_depending_on_free_variable = {} for command, line in self.command_stream: self.line = line cmd, args = command[0], command[-1] if cmd == 'SFAC': builder.make_structure() if len(args) == 15 and isinstance(args[1], float): raise NotImplementedError( '''SFAC label a1 b1 a2 b2 a3 b3 a4 b4 c f' f" mu r wt''') self.label_for_sfac = ('*',) + args # (a) working around # ShelXL 1-based indexing elif cmd == 'FVAR': if overall_scale is None: overall_scale = args[0] self.free_variable = args # (b) ShelXL indexes into the whole array else: # ShelXL allows for more than one FVAR instruction self.free_variable = self.free_variable + args elif cmd == 'PART': part_sof = None conformer_index = 0 sym_excl_index = 0 part_number = 0 if args: part_number = int(args[0]) if len(args) == 2: part_sof = self.decode_one_variable(args[1]) if part_number > 0: conformer_index = part_number elif part_number < 0: sym_excl_index = abs(part_number) elif cmd == "RESI": current_residue = args self.builder.add_residue(*current_residue) elif cmd == '__ATOM__': if not in_the_midst_of_atom_list: if self.label_for_sfac is None: raise shelx_error("An instruction SFAC needs to appear before " "this point in the file,", self.line) in_the_midst_of_atom_list = True scatterer, behaviour_of_variable = self.lex_scatterer( args, scatterer_index) residue_number, residue_class = current_residue name = scatterer.label.upper() line_1 = line_of_scatterer_named.get((residue_number, name)) if line_1 is not None: raise shelx_error("Residue #%i has two scatterers named %s, " "(with perhaps a difference in letter case)" "defined at lines %i and %i" % (residue_number, name, line, line_1), line=None) line_of_scatterer_named[(residue_number, name)] = line if (conformer_index or sym_excl_index) and part_sof: scatterer.occupancy, behaviour_of_variable[3] = part_sof builder.add_scatterer(scatterer, behaviour_of_variable, occupancy_includes_symmetry_factor=True, conformer_index=conformer_index, sym_excl_index=sym_excl_index, residue_number=residue_number, residue_class=residue_class) # As the builder accepted the scatterer, we assume that it called # scatterer.apply_symmetry so that scatterer.multiplicity and dependents # are correctly set. Hence our fetching the scatterer from the builder # instead of using the pre-existing local variable. scatterer = builder.structure.scatterers()[-1] self.process_possible_constrained_occupancy(scatterer_index, scatterer, behaviour_of_variable[3]) self.process_possible_u_iso_constraints(scatterer_index, behaviour_of_variable[4]) scatterer_index += 1 elif cmd == '__Q_PEAK__': assert not self.strictly_shelxl,\ "Q-peaks amidst atoms in strict ShelXL model" builder.add_electron_density_peak(site = args[2:5], height = args[-1]) else: yield command, line self.process_occupancies_depending_on_free_variable()
def raise_parameter_error(): raise shelx_error( "scatterer parameter #%d '%s'", line, i_cv+1, coded_variable)
def __iter__(self): """ Yields the commands in self.file as tuples: - either (cmd, args) where args is a tuple, e.g. ('CELL', (0.71073, 1, 2, 3, 90, 90, 90)) - or (cmd, (residue_class, residue_number), args) for those commands which can be suffixed by a residue, e.g. ('HFIX', (parser.residue_number_tok, 1), (23, )) Notes: - For atoms, cmd is '__ATOM__' and the name is the first argument - For so-called Q-peaks, cmd is '__Q_PEAK__' and the number is the first argument - In args, floating point items are reported as is whereas any string comes as (type, value) where type is one of the class constants defined just above this method (actually, for the residue_number_tok, the value is an integer stored as a float). - The atomic refinable variables are not decoded: this is the job of a parser, not of a lexer. """ continued = False for i, li in enumerate(self.file): if not li: continue if continued: m = self._continuation_pat.search(li) if m is None: raise shelx_error("illegal continuation line error", i) cont_args, continued = m.groups() arguments.extend(cont_args.split()) else: m = self._cmd_pat.search(li) if m is None: if li[0].isspace(): continue else: m = self._include_filename_pat.search(li) if m is not None: cmd, filename = m.group(1, 2) yield (cmd, filename), i continue raise shelx_error("illegal command or atom name error", i) cmd = m.group(1) or m.group(6) if cmd: cmd = cmd.upper() cmd_residue = None else: (cmd, cmd_residue_class, cmd_residue_number) = m.group(3, 4, 5) cmd = cmd.upper() if cmd_residue_class: cmd_residue = (tokens.residue_class_tok, cmd_residue_class.upper()) elif cmd_residue_number: cmd_residue = (tokens.residue_number_tok, int(cmd_residue_number)) else: cmd_residue = (tokens.all_residues_tok, ) args = m.group(2) or m.group(7) or "" continued = m.group(8) arguments = args.split() if not continued: result = self._parse_special_cases(cmd, args, arguments, i, li) if result is None: result = self._parse_general_case(cmd, cmd_residue, arguments, i, li) yield result, i if cmd == 'HKLF': break
def __iter__(self): """ Yields the commands in self.file as tuples: - either (cmd, args) where args is a tuple, e.g. ('CELL', (0.71073, 1, 2, 3, 90, 90, 90)) - or (cmd, (residue_class, residue_number), args) for those commands which can be suffixed by a residue, e.g. ('HFIX', (parser.residue_number_tok, 1), (23, )) Notes: - For atoms, cmd is '__ATOM__' and the name is the first argument - For so-called Q-peaks, cmd is '__Q_PEAK__' and the number is the first argument - In args, floating point items are reported as is whereas any string comes as (type, value) where type is one of the class constants defined just above this method (actually, for the residue_number_tok, the value is an integer stored as a float). - The atomic refinable variables are not decoded: this is the job of a parser, not of a lexer. """ continued = False for i, li in enumerate(self.file): if not li: continue if continued: m = self._continuation_pat.search(li) if m is None: raise shelx_error("illegal continuation line error", i) cont_args, continued = m.groups() arguments.extend(cont_args.split()) else: m = self._cmd_pat.search(li) if m is None: if li[0].isspace(): continue else: m = self._include_filename_pat.search(li) if m is not None: cmd, filename = m.group(1, 2) yield (cmd, filename), i continue raise shelx_error("illegal command or atom name error", i) cmd = m.group(1) or m.group(6) if cmd: cmd = cmd.upper() cmd_residue = None else: (cmd, cmd_residue_class, cmd_residue_number) = m.group(3, 4, 5) cmd = cmd.upper() if cmd_residue_class: cmd_residue = (tokens.residue_class_tok, cmd_residue_class.upper()) elif cmd_residue_number: cmd_residue = (tokens.residue_number_tok, int(cmd_residue_number)) else: cmd_residue = (tokens.all_residues_tok,) args = m.group(2) or m.group(7) or "" continued = m.group(8) arguments = args.split() if not continued: result = self._parse_special_cases(cmd, args, arguments, i, li) if result is None: result = self._parse_general_case(cmd, cmd_residue, arguments, i, li) yield result, i if cmd == "HKLF": break
def parse_restraints(self): for cmd, restraints in sorted(self.cached_restraints.items()): for line, args in restraints.iteritems(): cmd_residue = args[0] if cmd_residue is None: residues = [None] else: tok = cmd_residue[0] if tok == tokens.residue_number_tok: residues = [cmd_residue[1]] elif tok == tokens.residue_class_tok: residues = self.builder.residue_numbers_having_class[cmd_residue[1]] elif tok == tokens.all_residues_tok: residues = self.builder.residue_class_of_residue_number.keys() args = args[1] floats = [] atoms = [] elements = [] # it seems that shelxl will accept the restraints and target value/sigma # in any order - we will interpret any floating point values as # target value (if applicable), sigma, in that order. Any other # arguments given are atoms for arg in args: try: floats.append(float(arg)) except TypeError, e: if isinstance(arg, tokens.atomname_token): atoms.append(arg) elif isinstance(arg, tokens.element_token): elements.append(arg) for residue_number in residues: try: i_seqs = self.i_seqs_from_atoms(atoms, residue_number) if i_seqs is None: continue restraint_type = self.restraint_types.get(cmd) if cmd in ('DFIX','DANG'): assert len(floats) in (1, 2) distance_ideal = floats[0] if len(floats) == 2: sigma = floats[1] else: if cmd == 'DFIX': sigma = 0.02 else: sigma = 0.04 assert len(atoms) > 1 weight = 1/(sigma**2) assert len(atoms) % 2 == 0 for i in range(len(atoms)//2): atom_pair = atoms[i*2:(i+1)*2] i_seq_pair = i_seqs[i*2:(i+1)*2] sym_ops = [ self.symmetry_operations.get(atom.symmetry) for atom in atom_pair] self.builder.process_restraint(restraint_type, distance_ideal=distance_ideal, weight=weight, i_seqs=i_seq_pair, sym_ops=sym_ops) if cmd == 'SADI': assert len(floats) <= 1 if len(floats): sigma = floats[0] else: sigma = 0.02 i_seq_pairs = [] sym_ops = [] for i in range(len(atoms)//2): atom_pair = atoms[i*2:(i+1)*2] i_seq_pairs.append(i_seqs[i*2:(i+1)*2]) sym_ops.append( [self.symmetry_operations.get(atom.symmetry) for atom in atom_pair]) weights = [1/(sigma**2)]*len(i_seq_pairs) self.builder.process_restraint(restraint_type, weights=weights, i_seqs=i_seq_pairs, sym_ops=sym_ops) elif cmd == 'FLAT': assert len(floats) <= 1 if len(floats) == 1: sigma = floats[0] else: sigma = 0.1 assert len(atoms) > 3 sym_ops = [ self.symmetry_operations.get(atom.symmetry) for atom in atoms] weights = [1/(sigma**2)]*len(i_seqs) self.builder.process_restraint(restraint_type, weights=weights, i_seqs=i_seqs, sym_ops=sym_ops) elif cmd == 'CHIV': pass elif cmd in ('DELU', 'ISOR', 'SIMU'): assert len(floats) <= 3 s1 = s2 = dmax = None if len(floats) > 0: s1 = floats[0] if len(floats) > 1: s2 = floats[1] if len(floats) > 2: dmax = floats[2] if len(i_seqs) == 0: i_seqs = None if s1 is None: if cmd == 'SIMU': s1 = 0.04 elif cmd == 'DELU': s1 = 0.01 else: s1 = 0.1 if cmd == 'DELU': self.builder.process_restraint(restraint_type, sigma_12=s1, sigma_13=s2, i_seqs=i_seqs) else: self.builder.process_restraint(restraint_type, sigma=s1, sigma_terminal=s2, i_seqs=i_seqs) else: pass except (TypeError, AssertionError): raise shelx_error("Invalid %s instruction" %cmd, line)
def parse_restraints(self): for cmd, restraints in sorted(self.cached_restraints.items()): for line, args in restraints.iteritems(): cmd_residue = args[0] if cmd_residue is None: residues = [None] else: tok = cmd_residue[0] if tok == tokens.residue_number_tok: residues = [cmd_residue[1]] elif tok == tokens.residue_class_tok: residues = self.builder.residue_numbers_having_class[cmd_residue[1]] elif tok == tokens.all_residues_tok: residues = self.builder.residue_class_of_residue_number.keys() args = args[1] floats = [] atoms = [] elements = [] # it seems that shelxl will accept the restraints and target value/sigma # in any order - we will interpret any floating point values as # target value (if applicable), sigma, in that order. Any other # arguments given are atoms for arg in args: try: floats.append(float(arg)) except TypeError, e: if isinstance(arg, tokens.atomname_token): atoms.append(arg) elif isinstance(arg, tokens.element_token): elements.append(arg) for residue_number in residues: try: i_seqs = self.i_seqs_from_atoms(atoms, residue_number) if i_seqs is None: continue restraint_type = self.restraint_types.get(cmd) if cmd in ('DFIX','DANG'): assert len(floats) in (1, 2) distance_ideal = floats[0] if len(floats) == 2: sigma = floats[1] else: if cmd == 'DFIX': sigma = 0.02 else: sigma = 0.04 assert len(atoms) > 1 weight = 1/(sigma**2) assert len(atoms) % 2 == 0 for i in range(len(atoms)//2): atom_pair = atoms[i*2:(i+1)*2] i_seq_pair = i_seqs[i*2:(i+1)*2] sym_ops = [ self.symmetry_operations.get(atom.symmetry) for atom in atom_pair] self.builder.process_restraint(restraint_type, distance_ideal=distance_ideal, weight=weight, i_seqs=i_seq_pair, sym_ops=sym_ops) if cmd == 'SADI': assert len(floats) <= 1 if len(floats): sigma = floats[0] else: sigma = 0.02 i_seq_pairs = [] sym_ops = [] for i in range(len(atoms)//2): atom_pair = atoms[i*2:(i+1)*2] i_seq_pairs.append(i_seqs[i*2:(i+1)*2]) sym_ops.append( [self.symmetry_operations.get(atom.symmetry) for atom in atom_pair]) weights = [1/(sigma**2)]*len(i_seq_pairs) self.builder.process_restraint(restraint_type, weights=weights, i_seqs=i_seq_pairs, sym_ops=sym_ops) elif cmd == 'FLAT': assert len(floats) <= 1 if len(floats) == 1: sigma = floats[0] else: sigma = 0.1 assert len(atoms) > 3 sym_ops = [ self.symmetry_operations.get(atom.symmetry) for atom in atoms] weights = [1/(sigma**2)]*len(i_seqs) self.builder.process_restraint(restraint_type, weights=weights, i_seqs=i_seqs, sym_ops=sym_ops) elif cmd == 'CHIV': pass elif cmd in ('DELU', 'RIGU', 'ISOR', 'SIMU'): assert len(floats) <= 3 s1 = s2 = dmax = None if len(floats) > 0: s1 = floats[0] if len(floats) > 1: s2 = floats[1] if len(floats) > 2: dmax = floats[2] if len(i_seqs) == 0: i_seqs = None if s1 is None: if cmd == 'SIMU': s1 = 0.04 elif cmd == 'DELU': s1 = 0.01 elif cmd == 'RIGU': s1 = 0.004 else: s1 = 0.1 if cmd in ('DELU', 'RIGU'): self.builder.process_restraint(restraint_type, sigma_12=s1, sigma_13=s2, i_seqs=i_seqs) else: self.builder.process_restraint(restraint_type, sigma=s1, sigma_terminal=s2, i_seqs=i_seqs) else: pass except (TypeError, AssertionError): raise shelx_error("Invalid %s instruction" %cmd, line)