def exchange_single_base(residue, new_name, model=None, new_number=None):
    """*exchange_single_base(residue, new_name, model=None, new_number=None)*
    
Exchanges standard RNA bases in a residue.
This can be used to modify residues already in a model,
or to exchange and copy them in one step, if an RnaModel is given.
It is also possible to modify the template this way!

The residue number does not change by default, but a new one can be given.

:Arguments:
    * Residues from a Template or RnaModel
    * Abbreviation of the new base ('A', 'G', 'C' or 'U')
    * RnaModel object (optional)
    * New residue number in the model (optional)
    """
    residue = validate_resi(residue)
    new_name = validate_alphabet(new_name)
    if model: model = validate_model(model)
    if new_number: new_number = validate_resnum(new_number)

    if model:
        model.copy_residue(residue, new_number)
        number = new_number or residue.identifier
        modifications.exchange_base(model[number], new_name)
    else:
        modifications.exchange_base(residue, new_name)
def exchange_some_bases(residue_list, new_names, model=None, new_numbers=None):
    """*exchange_some_bases(residue_list, new_names, model=None, new_numbers=None)*

Exchanges standard RNA bases in a set of residues.
This can be used to modify residues already in a model,
or to exchange and copy them in one step, if a RNAModel is given.
It is also possible to modify the template this way!

The residue numbers are not changed by default, but a list of
new one can be given.

:Arguments:
    * Residues from a Template or RnaModel
    * List of names of the new bases ('A', 'G', 'C' or 'U')
    * RnaModel object (optional)
    * New residue number in the model
    """
    residue_list = validate_resi_list(residue_list)
    new_names = validate_alphabet_list(new_names, len(residue_list))
    if model: model = validate_model(model)
    if new_numbers:
        new_numbers = validate_resnum_list(new_numbers, len(residue_list))

    if model:
        model.exchange_list_of_bases(residue_list, new_names, new_numbers)
    else:
        for resi, newname in zip(residue_list, new_names):
            modifications.exchange_base(resi, newname)
def shrink_helix(model, anchor5_id, anchor3_id, anchor5_upper_id,
                 anchor3_upper_id):
    """*shrink_helix(model,  anchor5_id,  anchor3_id,  anchor5_upper_id,  anchor3_upper_id)*

Makes helix shorter - cuts out a helix fragment between given residues from the model.

:Arguments:
    * Template or RnaModel
    * anchor5 - residue id on the 5' side belonging to the first base pair that will remain
    * anchor3 - residue id on the 3' side belonging to the first base pair that will remain
    * anchor5_upper - residue id on the 5' side belonging to the pair that will end up next to the first.
    * anchor3_upper - residue id on the 3' side belonging to the pair that will end up next to the first.
    """
    model = validate_model(model)
    anchor5_id = validate_resnum(anchor5_id)
    anchor3_id = validate_resnum(anchor3_id)
    anchor5_upper_id = validate_resnum(anchor5_upper_id)
    anchor3_upper_id = validate_resnum(anchor3_upper_id)

    hbuilder = HelixBuilder()
    helix = hbuilder.build_helix(Sequence('AA_UU'))
    fr = ModernaFragment2D(helix, anchor5=model[anchor5_id], \
                           anchor3=model[anchor3_id], \
                           anchor5_upper=model[anchor5_upper_id], \
                           anchor3_upper=model[anchor3_upper_id], \
                           frag5_upper = helix['2'], frag3_upper = helix['401'], \
                           model=model)
    model.insert_fragment(fr)
def add_modification(residue,
                     modification_name,
                     model=None,
                     residue_number=None):
    """*add_modification(residue, modification_name, model=None, residue_number=None)*

Adds a modification to a single residue. An RNAModel can be given optionally. If this is given, the modified residue is subsequently copied to it.

Note that deoxynucleotides count as modified bases as well.

:Arguments:
    * residue from a Template or RNAModel object
    * modification name (abbreviated as e.g. 'm6Am', 'm1G', 'm3U', 'mnm5s2U')
    * model (optional; if this is given, the residue is copied)
    * residue position in model (optional; by default the residue number is kept)
    """
    residue = validate_resi(residue)
    modification_name = validate_alphabet(modification_name)
    if model: model = validate_model(model)
    if residue_number: validate_resnum(residue_number)

    if model != None:
        model.add_one_modification_copy(residue, modification_name,
                                        residue_number)
    else:
        modifications.add_modification(residue, modification_name)
def copy_identical_residues(template,
                            alignment,
                            model,
                            strict=True,
                            modifications=True):
    """*copy_identical_residues(template, alignment, model, strict=True, modifications=True)*

Copies all bases identical identical in the alignment
from the template structure to a model. The residue numbers
do not change.

:Arguments:
    * Template object
    * Alignment object
    * RnaModel object
    * strict=1 complains and stops on any problem encountered (default); strict=0 goes on if single residues fail to be copied
    * modifications=0 does not copy modified bases; modifications=1 is default.
    """
    template = validate_template(template)
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    if template: model.template = template
    if alignment:
        model.alignment = alignment
        model.recipe = RecipeMaker(alignment).recipe
    model.copy_all_residues(strict=strict, modifications=modifications)
def match_alignment_with_model(alignment, model):
    """*match_alignment_with_model(alignment, model)*

Checks, if the sequence of a model structure is equal to the first sequence in the alignment. 
Writes an according message and returns True or False.

Both sequences also count as equal if one has modified nucleotides, and 
the other the corresponding unmodified nucleotides in the same position, 
or if one of the sequences contains the wildcard symbol '.'. 
Thus, the sequence "AGU" is equal to both "A7Y" and "A.U".
    
:Arguments:
    * Alignment object
    * RnaModel object
    """
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    log.write_message('\nChecking whether alignment matches with model.')
    am = AlignmentMatcher(alignment)
    seq = model.get_sequence()
    result = am.is_target_identical(seq)
    if not result:
        log.write_message("alignment and model match.\n")
    else:
        log.write_message(
            "ALIGNMENT AND MODEL SEQUENCES DO NOT MATCH YET !!!\n")
    return result
def remove_all_modifications(model):
    """*remove_all_modifications(model)*

Removes all base modifications from a given model. The nucleotides are
transformed into standard bases from which the modifications originated.
     
:Arguments:
    * RnaModel object
    """
    model = validate_model(model)
    model.remove_all_modifications()
def delete_residue(residue_number, model):
    """*delete_residue(residue_number, model)*
    
Removes a residue from a RNAModel object.
   
:Arguments:
    * residue identifier e.g. '1', '6', '6A'
    * RnaModel object
    """
    model = validate_model(model)
    residue_number = validate_resnum(residue_number)

    model.remove_residue(residue_number)
def insert_fragment(model, fragment):
    """*insert_fragment(model, fragment)*

Inserts a fragment object into the model. 
The model should be the same object, from which the 
two anchor residues were defined when the fragment was created. 
(See also documentation of the create_fragment/find_fragment functions.)

:Arguments:
    * RnaModel object
    * ModernaFragment or LirHit object
    """
    model = validate_model(model)
    fragment = validate_fragment(fragment)

    if type(fragment) == LirHit: model.insert_lir_candidate(fragment)
    else: model.insert_fragment(fragment)
def apply_indel(model, res5_number, res3_number, sequence):
    """*apply_indel(model, res5_number, res3_number, sequence)*

Finds the best fitting fragment between two residues, and inserts it into the model. 
The procedure automatically retrieves the 20 best fitting candidates from the fragment database, 
checks whether they produce any clashes upon insertion, and inserts the best scoring candidate.

:Arguments:
    * RNAmodel object
    * number of the residue on the 5' end of the fragment
    * number of the residue on the 3' end of the fragment
    * sequence of the fragment (not including the two residues specified above).
    """
    model = validate_model(model)
    res5_number = validate_resnum(res5_number)
    res3_number = validate_resnum(res3_number)
    sequence = validate_seq(sequence)

    model.insert_best_fragment(res5_number, res3_number, sequence)
def apply_missing_ends(alignment, model):
    """*apply_missing_ends(alignment,  model)*
    
Attaches an extended fragment of structure at both
the 5' and 3' ends of the target, where there is no corresponding
part in the template.

:Arguments:
    * Alignment object
    * model
    """
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    if alignment:
        model.alignment = alignment
        model.recipe = RecipeMaker(alignment).recipe
    model.add_missing_5p()
    model.add_missing_3p()
def insert_two_strand_fragment(model, anchor5_id, anchor3_id, anchor5_upper_id, anchor3_upper_id, \
                 frag_anchor5_id,  frag_anchor3_id, frag_anchor5_upper_id, frag_anchor3_upper_id,  fragment_file,  chain_name='A'):
    """*insert_2D_fragment(model, anchor5_id, anchor3_id, anchor5_upper_id, anchor3_upper_id, \
                 frag_anchor5_id,  frag_anchor3_id, frag_anchor5_upper_id, frag_anchor3_upper_id,  fragment_file,  chain_name='A')*

Inserts a given 2D fragment between two pairs of indicated residues.
Requires to indicate connecting residues from both model (4) and fragment (4).

:Arguments:
    * model - RNAModel object
    * anchor5_id - anchor residue in the model on the 5' side of the fragment.
    * anchor3_id - anchor residue in the model on the 3' side of the fragment.
    * anchor5_upper_id - anchor residue in the model on the 5' side of the middle part of the fragment.
    * anchor3_upper_id - anchor residue in the model on the 3' side of the middle part of the fragment.
    * frag_anchor5_id - anchor residue in the fragment on the 5' side of the fragment.
    * frag_anchor3_id - anchor residue in the fragment on the 3' side of the fragment.
    * frag_anchor5_upper_id - anchor residue in the fragment on the 5' side of the middle part of the fragment.
    * frag_anchor3_upper_id - anchor residue in the fragment on the 3' side of the middle part of the fragment.
    * fragment_file - name of the fragment PDB file
    * chain_name - chain ID (default: 'A')
    """
    model = validate_model(model)
    anchor5_id = validate_resnum(anchor5_id)
    anchor3_id = validate_resnum(anchor3_id)
    anchor5_upper_id = validate_resnum(anchor5_upper_id)
    anchor3_upper_id = validate_resnum(anchor3_upper_id)
    frag_anchor5_id = validate_resnum(frag_anchor5_id)
    frag_anchor3_id = validate_resnum(frag_anchor3_id)
    frag_anchor5_upper_id = validate_resnum(frag_anchor5_upper_id)
    frag_anchor3_upper_id = validate_resnum(frag_anchor3_upper_id)
    fragment_file = validate_filename(fragment_file)

    struc = ModernaStructure(data_type='file',
                             data=fragment_file,
                             chain_name=chain_name)
    mf = ModernaFragment2D(struc, \
                anchor5=model[anchor5_id], anchor3=model[anchor3_id], \
                anchor5_upper=model[anchor5_upper_id], \
                anchor3_upper=model[anchor3_upper_id], \
                frag5_upper=struc[frag_anchor5_upper_id], \
                frag3_upper=struc[frag_anchor3_upper_id], \
                model=model)
    model.insert_fragment(mf)
def add_pair_to_base(model, anchor_id, new_id=None, new_sequence=None):
    """*add_pair_to_base(model,  anchor_id,  new_id=None,  new_sequence=None)*

Adds Watson-Crick paired second strand to single nucleotide.

:Arguments:
    * RNAModel object
    * Identifier of residue to which a new base pair will be added
    * New identifier for second strand
    * New sequence for second strand
    """
    model = validate_model(model)
    anchor_id = validate_resnum(anchor_id)
    if new_id: new_id = validate_resnum(new_id)
    if new_sequence: new_sequence = validate_seq(new_sequence)

    fr = ModernaFragmentStrand(anchor=model[anchor_id],
                               identifier=new_id,
                               new_sequence=new_sequence)
    model.insert_fragment(fr)
def add_all_modifications(template, alignment, model):
    """*add_all_modifications(template, alignment, model)*

Adds all modifications that occur in the target sequence, and are
not present in the template.
    
:Arguments:
    * Template object
    * Alignment object
    * RnaModel object
    """
    template = validate_template(template)
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    if template: model.template = template
    if alignment:
        model.alignment = alignment
        model.recipe = RecipeMaker(alignment).recipe
    model.add_all_modifications_copy()
def remove_mismatching_modifications(template, alignment, model):
    """*remove_mismatching_modifications(template, alignment, model)*

Removes all nucleotide modifications that occur in the template, 
and are not present in the target sequence. 
The nucleotides are transformed into standard bases from which the modifications originated.
   
:Arguments:
    * Template object
    * Alignment object
    * RnaModel object
    """
    template = validate_template(template)
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    model.template = template
    model.alignment = alignment
    model.recipe = RecipeMaker(alignment).recipe
    model.remove_all_modifications_copy()
def exchange_mismatches(template, alignment, model):
    """*exchange_mismatches(template, alignment, model)*
    
Exchanges the bases for all standard base mismatches in an alignment.
This applies all exchanges of one standard base by another.
Modified bases are not changed (use the apply_alignment command for that).
 
:Arguments:
    * Template object
    * Alignment object
    * RnaModel object
    """
    template = validate_template(template)
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    if template: model.template = template
    if alignment:
        model.alignment = alignment
        model.recipe = RecipeMaker(alignment).recipe
    model.exchange_all_bases()
def copy_single_residue(residue, model, new_number=None, strict=True):
    """*copy_single_residue(residue, model, new_number=None, strict=True)*
    
Copies a single residue into the model.
The residue can be taken from a Template, or another RnaModel.

Residues are specified by their PDB residue number in quotes and square brackets, e.g. template['5'].
eventually accompanied by the insertion letter (abbreviated as number).
By default, the number of the residue is kept, but it can be given optionally. 

:Arguments:
    * Residue from a Template or RnaModel
    * RnaModel object
    * new residue number in the model (optional)
    * strict=1 complains when a residue with the given number exists already (default); strict=0 copies anyway
    """
    residue = validate_resi(residue)
    model = validate_model(model)
    if new_number: new_number = validate_resnum(new_number)

    model.copy_residue(residue, new_number, strict=strict)
def apply_alignment(template, alignment, model):
    """*apply_alignment(template, alignment, model)*

Applies all operations on single bases that are in an alignment:
Copying identical residues, exchanging mismatches, adding modifications,
and removing modifications. As a result, all these residues are copied
into a model (which may be empty).
For gaps in the alignment, nothing is done.

:Arguments:
    * Template object
    * Alignment object
    * RNAModel object
    """
    template = validate_template(template)
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    model.alignment = alignment
    model.recipe = RecipeMaker(alignment).recipe
    model.template = template
    model.apply_alignment()
def remove_modification(residue, model=None, new_number=None):
    """*remove_modification(residue, model=None, new_number=None)*
    
Removes base modifications from a single residue. The nucleotide is
transformed into the standard base from which the modification originated.
A RnaModel can be given optionally. If this is given, the
modified residue is subsequently copied to it.

Note that desoxynucleotides count as modified bases as well.
  
:Arguments:
    * residue from a Template or RnaModel object
    * RnaModel object (optional)
    * new residue number after copying (optional)
    """
    residue = validate_resi(residue)
    if model: model = validate_model(model)
    if new_number: new_number = validate_resnum(new_number)

    if model:
        model.remove_one_modification_copy(residue, new_number)
    else:
        modifications.remove_modification(residue)
def extend_helix(model, anchor5_id, anchor3_id, new_sequence=None):
    """*extend_helix(model, anchor5_id, anchor3_id, new_sequence=None)*

Makes a helix longer by adding A-type RNA Watson-Crick base pairs. 
A helix of any size may be added to the model.
A helix may be added at the end or inside an already existing helix.

:Arguments:
    * Template or RnaModel
    * Identifier of the residue on the 5' side to which helix will be added
    * Identifier of the residue on the 3' side to which helix will be added
    * Helix sequence as Sequence obiect e.g. Sequence('AAAA_UUUU')
    """
    model = validate_model(model)
    anchor5_id = validate_resnum(anchor5_id)
    anchor3_id = validate_resnum(anchor3_id)
    if new_sequence: new_sequence = validate_seq(new_sequence)

    hb = HelixFragmentBuilder()
    frag = hb.build_fragment(anchor5= model[anchor5_id], \
                    anchor3=model[anchor3_id], sequence=new_sequence, \
                    model=model)
    model.insert_fragment(frag)
def copy_some_residues(residue_list, model, new_numbers=None, strict=True):
    """*copy_some_residues(residue_list, model, new_numbers=None, strict=True)*

Copies a set of residues into the model.
The residues can be taken from a Template, or another RnaModel.

Residues are specified by enumerating their numbers in the PDB files,
or specifying a range of numbers (by 'num1':'num2').
By default, the numbers of the residues are kept,
but they can be given optionally.
Note that all residue numbers in ModeRNA have to be quoted.

:Arguments:
    * List of residues from a Template or RnaModel
    * RnaModel object
    * List of new residue numbers in the model (optional)
    * strict=1 complains when a residue with the given number exists already (default); strict=0 copies anyway
    """
    residue_list = validate_resi_list(residue_list)
    model = validate_model(model)
    if new_numbers: new_numbers = validate_resnum_list(new_numbers)

    model.copy_list_of_residues(residue_list, new_numbers, strict=strict)
def apply_all_indels(alignment, model):
    """*apply_all_indels(alignment, model)*
    
Finds and inserts the best fragment candidate for each gap region in the alignment. 
This command can be used to fill in gaps automatically. 
The procedure automatically retrieves the 20 best fitting candidates 
from the fragment database, checks whether they produce any clashes upon insertion, 
and inserts the best scoring candidate.

It depends, however on
    * gaps being shorter than 17 bases.
    (if longer a database of fragments up to 100 nt is available)

:Arguments:
    * Alignment object
    * RnaModel object
    """
    alignment = validate_alignment(alignment)
    model = validate_model(model)

    if alignment:
        model.alignment = alignment
        model.recipe = RecipeMaker(alignment).recipe
    model.insert_all_fragments()
def fix_backbone(model, resi1_number=None, resi2_number=None):
    """*fix_backbone(structure)*

Fixes interrupted backbones between adjacent residues.

This function either examines the backbone of all nt in a structure (and repairs them if broken), 
or only does this for the two residues specified. For repairing, first only the phosphate and adjacent oxygens are remodeled. 
In case this fails, the FCCD Loop Closing Algorithm (Boomsma/Hamelryck 2005) is used for the entire O3'..C4' segment.
If the two residues are far from each other or oriented in a weird angle, the result will be awkward.
    
:Arguments:
    * RnaModel object
    * residue number on the 5' side of the broken backbone (optional).
    * residue number on the 3' side of the broken backbone (optional).
    """
    model = validate_model(model)
    if resi1_number: resi1_number = validate_resnum(resi1_number)
    if resi2_number: resi2_number = validate_resnum(resi2_number)

    if resi1_number and resi2_number:
        model.fix_backbone_between_resis(model[resi1_number],
                                         model[resi2_number])
    else:
        model.fix_backbone()
def find_fragment(model,
                  res5_number,
                  res3_number,
                  sequence,
                  number_of_candidates=NUMBER_OF_FRAGMENT_CANDIDATES,
                  secstruc=None):
    """*find_fragment(model, res5_number, res3_number, sequence, number_of_candidates=20, secstruc=None)*

Searches fragment candidate structures that fit between two given residues. 
Produces a list of fragments candidate objects. The fragment search sorts candidates 
according to the geometrical fit of their backbones.

As an optional argument, a secondary structure can be specified in dot-bracket format. 
This restricts the found fragment candidates to those having exactly the same Watson-Crick pairs.

:Arguments:
    * RnaModel object
    * number of the residue at the 5' end of the fragment
    * number of the residue at the 3' end of the fragment
    * sequence of the fragment to be inserted (not including the two residues above)
    * number of candidate fragments to be returned (default=20)
    * secondary structure of the fragment in dot-bracket format (optional).
    """
    model = validate_model(model)
    res5_number = validate_resnum(res5_number)
    res3_number = validate_resnum(res3_number)
    sequence = validate_seq(sequence)
    if secstruc: secstruc = validate_secstruc(secstruc)

    r5 = model[res5_number]
    r3 = model[res3_number]
    return model.find_fragment_candidates(r5,
                                          r3,
                                          sequence,
                                          number_of_candidates,
                                          secstruc=secstruc)