/// <summary> /// Calculate 'reference' codons /// </summary> /// <param name="numCodons"></param> /// <returns></returns> protected string CodonsRef(int numCodons) { ISequence cds = Transcript.RetrieveCodingSequence(); string codon = ""; int start = CodonStartNumber * CODON_SIZE; int more = numCodons * CODON_SIZE; int end = start + more; int len = (int)cds.Count; if (start >= len) { start = len; } if (end >= len) { end = len; } // Capitalize codon = SequenceExtensions.ConvertToString(cds.GetSubSequence(start, more)); // Codon not multiple of three? Add missing bases as 'N' if (codon.Length % 3 == 1) { codon += "NN"; } else if (codon.Length % 3 == 2) { codon += "N"; } return(codon); }
/// <summary> /// Calculate base number in a cds where 'pos' is /// </summary> /// <param name="pos"></param> /// <returns></returns> protected long CdsBaseNumber(long pos) { long cdsbn = Transcript.BaseNumberCds(pos, true); // Does not intersect the transcript? if (cdsbn < 0) { // 'pos' before transcript start if (pos <= Transcript.CdsOneBasedStart) { if (Transcript.IsStrandPlus()) { return(0); } return(Transcript.RetrieveCodingSequence().Count); } // 'pos' is after CDS end if (Transcript.IsStrandPlus()) { return(Transcript.RetrieveCodingSequence().Count); } return(0); } return(cdsbn); }
/// <summary> /// Add an effect /// </summary> /// <param name="marker"></param> /// <param name="effectType"></param> /// <param name="effectImpact"></param> /// <param name="codonsOld"></param> /// <param name="codonsNew"></param> /// <param name="codonNum"></param> /// <param name="codonIndex"></param> /// <param name="allowReplace"></param> /// <returns></returns> private VariantEffect Effect(Interval marker, EffectType effectType, EffectImpact effectImpact, string codonsOld, string codonsNew, int codonNum, int codonIndex, bool allowReplace) { // Create and add variant affect long cDnaPos = Transcript.BaseNumber2MRnaPos(Variant.OneBasedStart); VariantEffect varEff = new VariantEffect(Variant, marker, effectType, effectImpact, codonsOld, codonsNew, codonNum, codonIndex, cDnaPos); VariantEffects.AddEffect(varEff); // Are there any additional effects? Sometimes a new effect arises from setting codons (e.g. FRAME_SHIFT disrupts a STOP codon) EffectType addEffType = AdditionalEffect(codonsOld, codonsNew, codonNum, codonIndex); if (addEffType != EffectType.NONE && addEffType != effectType) { if (allowReplace && addEffType.CompareTo(effectType) < 0) { // Replace main effect (using default impact) varEff.SetEffect(addEffType); } else { // Add effect to list (using default impact) varEff.AddEffect(addEffType); } } return(varEff); }
public override bool CreateVariantEffect(Variant variant, VariantEffects variantEffects) { if (!Intersects(variant)) { return(false); } Transcript tr = (Transcript)Parent; bool coding = tr.IsProteinCoding(); // Different analysis for coding or non-coding bool exonAnnotated = false; if (!coding || variant.isInterval() || !variant.isVariant()) { // Non-coding or non-variant? Just annotate as 'exon' variantEffects.AddEffect(variant, this, EffectType.EXON, ""); exonAnnotated = true; } else if (tr.IsCds(variant)) { // Is it a coding transcript and the variant is within the CDS? // => We need codon analysis CodonChange codonChange = CodonChange.Factory(variant, tr, variantEffects); codonChange.ChangeCodon(); exonAnnotated = true; } // Any splice site effect to add? //for (SpliceSite ss : spliceSites) // if (ss.intersects(variant)) ss.variantEffect(variant, variantEffects); return(exonAnnotated); }
/// <summary> /// Analyze insertions in this transcript. Add changeEffect to 'changeEffect' /// </summary> /// <param name="exon"></param> /// <returns></returns> protected override bool ChangeCodon(Exon exon) { string netChange = Variant.NetChange(Transcript.IsStrandMinus()); CodonsReference = CodonsRef(); CodonsAlternate = CodonsAlt(); EffectType effType; if (netChange.Length % CODON_SIZE != 0) { /** * Length not multiple of CODON_SIZE => FRAME_SHIFT * E.g. : * Original: AAA CCC GGG AAA CCC GGG AAA CCC GGG * Insert 'TT' pos 0: TTA AAC CCG GGA AAC CCG GGA AAC CCG GG * Insert 'TT' pos 1: ATT AAC CCG GGA AAC CCG GGA AAC CCG GG * Insert 'TT' pos 2: AAT TAC CCG GGA AAC CCG GGA AAC CCG GG */ effType = EffectType.FRAME_SHIFT; } else if (CodonStartIndex == 0) { /** * Length multiple of CODON_SIZE and insertion happens at codon boundary => CODON_INSERTION * E.g. : * Original: AAA CCC GGG AAA CCC GGG AAA CCC GGG * Insert 'TTT' pos 0: TTT AAA CCC GGG AAA CCC GGG AAA CCC GGG */ effType = EffectType.CODON_INSERTION; } else { /** * Length multiple of CODON_SIZE and insertion does not happen at codon boundary => CODON_CHANGE_PLUS_CODON_INSERTION * E.g. : * Original: AAA CCC GGG AAA CCC GGG AAA CCC GGG * Insert 'TTT' pos 1: ATT TAA CCC GGG AAA CCC GGG AAA CCC GGG * Insert 'TTT' pos 2: AAT TTA CCC GGG AAA CCC GGG AAA CCC GGG */ if (CodonsAlternate.ToUpper(CultureInfo.InvariantCulture).StartsWith(CodonsReference.ToUpper(CultureInfo.InvariantCulture))) { /** * May be the inserted base are equal to the old ones. * E.g. * Original: AAA CCC GGG AAA CCC GGG AAA CCC GGG * Insert 'AAA' pos 1: AAA AAA CCC GGG AAA CCC GGG AAA CCC GGG */ effType = EffectType.CODON_INSERTION; } else { effType = EffectType.CODON_CHANGE_PLUS_CODON_INSERTION; } } Effect(exon, effType, false); return(true); }
public override bool CreateVariantEffect(Variant variant, VariantEffects variantEffects) { // Has the whole UTR been deleted? if (variant.Includes(this) && variant.VarType == Variant.VariantType.DEL) { variantEffects.AddEffect(variant, this, EffectType.UTR_5_DELETED, ""); // A UTR was removed entirely return(true); } // Add distance Transcript tr = (Transcript)FindParent(typeof(Transcript)); long distance = utrDistance(variant, tr); VariantEffect variantEffect = new VariantEffect(variant); variantEffect.Set(this, IntervalType, EffectTypeMethods.EffectDictionary[IntervalType], distance >= 0 ? distance + " bases from TSS" : ""); variantEffect.Distance = distance; variantEffects.AddEffect(variantEffect); // Start gained? string gained = startGained(variant); if (gained != "") { variantEffects.AddEffect(variant, this, EffectType.START_GAINED, gained); } return(true); }
/// <summary> /// Apply variants to a transcript /// </summary> /// <param name="t"></param> /// <returns></returns> public static List <Transcript> ApplyVariantsCombinitorially(Transcript t) { // Clear out annotations from non-combinitoric add/annotate method t.VariantAnnotations.Clear(); t.ProteinSequenceVariations.Clear(); List <Transcript> newTranscripts = new List <Transcript> { new Transcript(t) }; int heterozygousNonsynonymousCount = 0; List <Variant> transcriptVariants = t.Variants.OrderByDescending(v => v.OneBasedStart).ToList(); // reversed, so that the coordinates of each successive variant is not changed foreach (Variant v in transcriptVariants) { List <Transcript> newOnes = new List <Transcript>(); foreach (var nt in newTranscripts) { var newerOnes = nt.ApplyVariantCombinitorics(v, out var effects); // expands only when there is a heterozygous nonsynonymous variation bool heterozygousNonsynonymous = v.GenotypeType == GenotypeType.HETEROZYGOUS && effects.Effects.Any(eff => eff.IsNonsynonymous()); if (heterozygousNonsynonymous) { heterozygousNonsynonymousCount++; } if (heterozygousNonsynonymousCount > 5 && heterozygousNonsynonymous) { Transcript.combinatoricFailures.Add("Heterozygous nonsynonymous variant: transcript:" + v.ToString() + " wasn't included in transcript: " + t.ID + " or protein: " + t.ProteinID); break; // avoid large combinitoric problems for now (heterozygous, nonsynonymous count > 5), but still stick in the homozygous variation } newOnes.AddRange(newerOnes); } newTranscripts = newOnes; } return(newTranscripts); }
/// <summary> /// Get the simplest string describing the effect (this is mostly used for testcases) /// </summary> /// <param name="shortFormat"></param> /// <returns></returns> public string ToStringSimple(bool shortFormat) { string transcriptId = ""; Transcript tr = GetTranscript(); if (tr != null) { transcriptId = tr.ID; } string exonId = ""; Exon exon = GetExon(); //if (exon != null) exonId = exon.getId(); string eff = Effect(shortFormat, true, true, false, false); if (eff != "") { return(eff); } if (exonId != "") { return(exonId); } if (transcriptId != "") { return(transcriptId); } return("NO EFFECT"); }
/// <summary> /// Can we add an effectType to the previous variatnEffect? /// </summary> /// <param name="variant"></param> /// <param name="marker"></param> /// <returns>true if transcript IDs and variant's genotypes match (i.e. we can add effectType)</returns> private bool CanAddType(Variant variant, Interval marker) { VariantEffect veff = Get(); if (veff == null || veff.Variant == null) { return(false); } // Do genotypes match? var gt = veff.Variant.Genotype; var vgt = variant.Genotype; if (((vgt != null) ^ (gt != null)) || // One null and one non-null? ((vgt != null) && (gt != null) && !variant.Genotype.Equals(variant.Genotype)) // Both non-null, but different? ) { return(false); } // Do transcripts match? Transcript trMarker = (Transcript)marker.FindParent(typeof(Transcript)); Transcript tr = veff.GetTranscript(); if (tr == null || trMarker == null) { return(false); } return(tr.ID == trMarker.ID); }
/// <summary> /// Create a specific codon change for a variant /// </summary> /// <param name="variant"></param> /// <param name="transcript"></param> /// <param name="variantEffects"></param> /// <returns></returns> public static CodonChange Factory(Variant variant, Transcript transcript, VariantEffects variantEffects) { switch (variant.VarType) { case Variant.VariantType.SNV: return(new CodonChangeSnv(variant, transcript, variantEffects)); case Variant.VariantType.INS: return(new CodonChangeIns(variant, transcript, variantEffects)); case Variant.VariantType.DEL: return(new CodonChangeDel(variant, transcript, variantEffects)); case Variant.VariantType.MNV: return(new CodonChangeMnv(variant, transcript, variantEffects)); //case Variant.VariantType.MIXED: // return new CodonChangeMixed(variant, transcript, variantEffects); case Variant.VariantType.DUP: return(new CodonChangeDup(variant, transcript, variantEffects)); case Variant.VariantType.INV: return(new CodonChangeInv(variant, transcript, variantEffects)); case Variant.VariantType.INTERVAL: return(new CodonChangeInterval(variant, transcript, variantEffects)); default: throw new ArgumentException("Unimplemented factory for variant type '" + variant.VarType + "', variant: " + variant); } }
/// <summary> /// Calculate codons by applying the variant and calculating the differences in CDS sequences. /// This is a slow method, makes sense only for complex variants /// </summary> protected void CodonsRefAlt() { Transcript trNew = Transcript.ApplyVariant(Variant) as Transcript; cdsAlt = SequenceExtensions.ConvertToString(trNew.RetrieveCodingSequence()); cdsRef = SequenceExtensions.ConvertToString(Transcript.RetrieveCodingSequence()); cdsDiff(); // Calculate differences: CDS }
/// <summary> /// CDS length (negative if there is none) /// </summary> /// <returns></returns> public long GetCdsLength() { Transcript tr = GetTranscript(); return(tr != null && tr.IsProteinCoding() ? tr.RetrieveCodingSequence().Count : -1); }
/// <summary> /// Sets relevant regions for a transcript /// </summary> /// <param name="transcript"></param> public static void SetRegions(Transcript transcript) { transcript.Introns = transcript.CreateIntrons(); transcript.UTRs = transcript.CreateUTRs(); var updown = transcript.CreateUpDown(transcript.Gene.Chromosome); transcript.Upstream = updown.OfType <Upstream>().FirstOrDefault(); transcript.Downstream = updown.OfType <Downstream>().FirstOrDefault(); }
/// <summary> /// Copy this transcript /// </summary> /// <param name="transcript"></param> public Transcript(Transcript transcript) : this(transcript.ID, transcript.Gene, transcript.Source, transcript.Strand, transcript.OneBasedStart, transcript.OneBasedEnd, transcript.ProteinID, transcript.FeatureMetadata) { VariantAnnotations = new List <string>(transcript.VariantAnnotations); ProteinSequenceVariations = new HashSet <SequenceVariation>(transcript.ProteinSequenceVariations); Exons = new List <Exon>(transcript.Exons.Select(x => new Exon(this, x.Sequence, x.Source, x.OneBasedStart, x.OneBasedEnd, x.ChromosomeID, x.Strand, x.FeatureMetadata))); CodingDomainSequences = new List <CDS>(transcript.CodingDomainSequences.Select(cds => new CDS(this, cds.ChromosomeID, cds.Source, cds.Strand, cds.OneBasedStart, cds.OneBasedEnd, cds.StartFrame))); SetRegions(this); }
private long cdsBaseNumber(long pos, bool usePrevBaseIntron) { if (pos < cdsStart) { return(Transcript.IsStrandPlus() ? 0 : Transcript.RetrieveCodingSequence().Count - 1); } if (pos > cdsEnd) { return(Transcript.IsStrandPlus() ? Transcript.RetrieveCodingSequence().Count - 1 : 0); } return(Transcript.BaseNumberCds(pos, usePrevBaseIntron)); }
private long utrDistance(Variant variant, Transcript tr) { long cdsEnd = tr.CdsOneBasedEnd; if (cdsEnd < 0) { return(-1); } if (IsStrandPlus()) { return(variant.OneBasedStart - cdsEnd); } return(cdsEnd - variant.OneBasedEnd); }
/// <summary> /// We may have to calculate 'netCdsChange', which is the effect on the CDS. /// Note: A deletion or a MNP might affect several exons /// </summary> /// <returns></returns> protected override string NetCdsChange() { if (Variant.Length() > 1) { StringBuilder sb = new StringBuilder(); foreach (Exon exon in Transcript.ExonsSortedStrand) { string seq = Variant.NetChange(exon); sb.Append(exon.IsStrandPlus() ? seq : SequenceExtensions.ConvertToString(new Sequence(Alphabets.AmbiguousDNA, seq).GetReverseComplementedSequence())); } return(sb.ToString()); } return(Variant.NetChange(Transcript.IsStrandPlus())); }
/// <summary> /// Get new (modified) codons /// </summary> /// <returns></returns> protected override string CodonsAlt() { // Inserts BEFORE base: // - In positive strand that is BEFORE pos // - In negative strand, that is AFTER pos int idx = CodonStartIndex + (Transcript.IsStrandMinus() ? 1 : 0); // Insertion: Concatenate... string prefix = CodonsReference.Length >= idx?CodonsReference.Substring(0, idx) : CodonsReference; // First part of the codon string netChange = Variant.NetChange(Transcript.IsStrandMinus()); // Insertion string suffix = CodonsReference.Length >= idx?CodonsReference.Substring(idx) : ""; // last part of the codon // New codon string codonsNew = prefix + netChange + suffix; return(codonsNew); }
/// <summary> /// Get original codons in CDS /// </summary> /// <returns></returns> protected override string CodonsRef() { int numCodons = 1; // Get CDS ISequence cdsStr = Transcript.RetrieveCodingSequence(); long cdsLen = cdsStr.Count; // Calculate minBase (first codon base in the CDS) int minBase = CodonStartNumber * CODON_SIZE; if (minBase < 0) { minBase = 0; } // Calculate maxBase (last codon base in the CDS) long maxBase = CodonStartNumber * CODON_SIZE + numCodons * CODON_SIZE; if (maxBase > cdsLen) { maxBase = cdsLen; } // Sanity checks if (cdsLen == 0 || // Empty CDS => Cannot get codon (e.g. one or more exons are missing their sequences (cdsLen <= minBase) // Codon past CDS sequence => Cannot get codon ) { return(""); } // Create codon sequence char[] codonChars = SequenceExtensions.ConvertToString(cdsStr).Substring(minBase, CODON_SIZE).ToLower(CultureInfo.InvariantCulture).ToCharArray(); // Capitatlize changed base if (CodonStartIndex < codonChars.Length) { codonChars[CodonStartIndex] = char.ToUpper(codonChars[CodonStartIndex]); } string codon = new String(codonChars); return(codon); }
/// <summary> /// Set marker. Add some warnings if the marker relates to incomplete transcripts /// </summary> /// <param name="marker"></param> public void SetMarker(Interval marker) { Marker = marker; Transcript transcript = GetTranscript(); if (transcript != null) { // Transcript level errors or warnings AddErrorWarningInfo(transcript.sanityCheck(Variant)); // Exon level errors or warnings Exon exon = GetExon(); if (exon != null) { AddErrorWarningInfo(exon.SanityCheck(Variant)); } } }
/// <summary> /// We may have to calculate 'netCdsChange', which is the effect on the CDS. /// Note: A deletion or a MNP might affect several exons /// </summary> /// <returns></returns> protected virtual string NetCdsChange() { if (!RequireNetCdsChange) { return(""); } if (Variant.Length() > 1) { StringBuilder sb = new StringBuilder(); foreach (Exon exon in Transcript.ExonsSortedStrand) { sb.Append(Variant.NetChange(exon)); } return(sb.ToString()); } return(Variant.NetChange(Transcript.IsStrandMinus())); }
/// <summary> /// Get new (modified) codons /// </summary> /// <returns></returns> protected override string CodonsAlt() { // Was there a problem getting 'codonsOld'? => We cannot do anything if (CodonsReference == "") { return(""); } char[] codonChars = CodonsReference.ToLower(CultureInfo.InvariantCulture).ToCharArray(); char snpBase = Variant.NetChange(Transcript.IsStrandMinus())[0]; if (CodonStartIndex < codonChars.Length) { codonChars[CodonStartIndex] = char.ToUpper(snpBase); } string codonsNew = new string(codonChars); return(codonsNew); }
public List <UTR5Prime> get5primeUtrs() { if (UTRs == null) { Transcript tr = (Transcript)FindParent(typeof(Transcript)); // Get UTRs and sort them UTRs = tr.UTRs.OfType <UTR5Prime>().ToList(); if (IsStrandPlus()) { UTRs = UTRs.OrderBy(u => u.OneBasedStart).ToList(); // Sort by start position } else { UTRs = UTRs.OrderByDescending(u => u.OneBasedEnd).ToList(); // Sort by end position (reversed) } } return(UTRs); }
/// <summary> /// Add variants to relevant genomic regions and annotate them if on transcripts /// </summary> /// <param name="variants"></param> public void AddVariantAnnotations(List <Variant> variants) { Parallel.ForEach(variants.OrderByDescending(v => v.OneBasedStart).ToList(), v => { if (GenomeForest.Forest.TryGetValue(Chromosome.GetFriendlyChromosomeName(v.ChromosomeID), out var intervalTree)) { foreach (Interval i in intervalTree.Stab(v.OneBasedStart)) { lock (i) { i.Variants.Add(v); Transcript t = i as Transcript; if (t != null) { t.AnnotateWithVariant(v); } } } } }); PreviouslyAddedVariants = variants; }
/// <summary> /// Get original codons in CDS /// </summary> /// <returns></returns> protected override string CodonsRef() { if (NetCodingSequenceChange == "") { return(""); } long min = Variant.OneBasedStart; long max = Variant.OneBasedEnd; long cdsBaseMin = CdsBaseNumber(min); long cdsBaseMax = CdsBaseNumber(max); // Swap? if (Transcript.IsStrandMinus()) { long swap = cdsBaseMin; cdsBaseMin = cdsBaseMax; cdsBaseMax = swap; } if (cdsBaseMax < cdsBaseMin) { throw new ArgumentOutOfRangeException("This should never happen!\n\tcdsBaseMin: " + cdsBaseMin + "\n\tcdsBaseMax: " + cdsBaseMax + "\n\tmin: " + min + "\n\tmax: " + max + "\n\tSeqChange: " + Variant + "\n\ttranscript: " + Transcript + "\n\tCDS.len: " + Transcript.RetrieveCodingSequence().Count); } long maxCodon = cdsBaseMax / CODON_SIZE; long minCodon = cdsBaseMin / CODON_SIZE; long oldCodonCdsStart = (CODON_SIZE * minCodon); long oldCodonCdsEnd = (CODON_SIZE * (maxCodon + 1)) - 1; string codons = oldCodonCdsEnd >= Transcript.RetrieveCodingSequence().Count ? SequenceExtensions.ConvertToString(Transcript.RetrieveCodingSequence()).Substring((int)oldCodonCdsStart) : SequenceExtensions.ConvertToString(Transcript.RetrieveCodingSequence().GetSubSequence(oldCodonCdsStart, (maxCodon - minCodon + 1) * CODON_SIZE)); return(codons); }
public override bool CreateVariantEffect(Variant variant, VariantEffects variantEffects) { if (!Intersects(variant)) { return(false); } if (variant.Includes(this) && variant.VarType == Variant.VariantType.DEL) { variantEffects.AddEffectType(variant, this, EffectType.UTR_3_DELETED); // A UTR was removed entirely return(true); } Transcript tr = (Transcript)FindParent(typeof(Transcript)); long distance = utrDistance(variant, tr); VariantEffect variantEffect = new VariantEffect(variant); variantEffect.Set(this, EffectType.UTR_3_PRIME, EffectTypeMethods.EffectDictionary[EffectType.UTR_3_PRIME], distance >= 0 ? distance + " bases from CDS" : ""); variantEffect.Distance = distance; variantEffects.AddEffect(variantEffect); return(true); }
/// <summary> /// Reads gene model features into data structures contained within this library /// </summary> /// <param name="geneModelFile"></param> public void ReadGeneFeatures(string geneModelFile) { foreach (ISequence chromFeatures in SimplerParse(geneModelFile)) { Chromosome chrom = Genome.Chromosomes.FirstOrDefault(x => x.FriendlyName == chromFeatures.ID); if (chrom == null) { continue; } chromFeatures.Metadata.TryGetValue("features", out object f); List <MetadataListItem <List <string> > > features = f as List <MetadataListItem <List <string> > >; for (int i = 0; i < features.Count; i++) { MetadataListItem <List <string> > feature = features[i]; long.TryParse(feature.SubItems["start"][0], out long start); long.TryParse(feature.SubItems["end"][0], out long end); var attributes = SplitAttributes(feature.FreeText); if (feature.FreeText.Contains('=')) { ProcessGff3Feature(feature, start, end, chrom, attributes); } else { ProcessGtfFeature(feature, start, end, chrom, attributes); } } } if (currentTranscript != null) { Transcript.SetRegions(currentTranscript); currentTranscript.FrameCorrection(); } CreateIntergenicRegions(); // possibly check transcript sanity here with Parallel.ForEach(Genes.SelectMany(g => g.Transcripts).ToList(), t => t.SanityCheck()); GenomeForest.Build(); }
public CodonChangeSnv(Variant variant, Transcript transcript, VariantEffects variantEffects) : base(variant, transcript, variantEffects) { ReturnNow = true; // A SNP can only affect one exon }
protected CodonChangeStructural(Variant variant, Transcript transcript, VariantEffects variantEffects) : base(variant, transcript, variantEffects) { coding = transcript.IsProteinCoding(); // || Config.get().isTreatAllAsProteinCoding(); CountAffectedExons(); }
/// <summary> /// Calculate codons old / codons new /// </summary> protected void codonOldNew() { if (!Transcript.Intersects(Variant)) { return; } // CDS coordinates cdsStart = Transcript.IsStrandPlus() ? Transcript.CdsOneBasedStart : Transcript.CdsOneBasedEnd; cdsEnd = Transcript.IsStrandPlus() ? Transcript.CdsOneBasedEnd : Transcript.CdsOneBasedStart; // Does it intersect CDS? if (cdsStart > Variant.OneBasedEnd) { return; } if (cdsEnd < Variant.OneBasedStart) { return; } // Base number relative to CDS start long scStart, scEnd; if (Transcript.IsStrandPlus()) { scStart = cdsBaseNumber(Variant.OneBasedStart, false); scEnd = cdsBaseNumber(Variant.OneBasedEnd, true); } else { scEnd = cdsBaseNumber(Variant.OneBasedStart, true); scStart = cdsBaseNumber(Variant.OneBasedEnd, false); } // Update coordinates CodonStartNumber = (int)(scStart / CODON_SIZE); CodonStartIndex = (int)(scStart % CODON_SIZE); // MNP overlap in coding part long scLen = scEnd - scStart; if (scLen < 0) { return; } // Round to codon position long scStart3 = round3(scStart, false); long scEnd3 = round3(scEnd, true); long scLen3 = scEnd3 - scStart3; if (scEnd3 == scStart3) { scEnd3 += 3; } // At least one codon // Append 'N' string padN = ""; long diff = scEnd3 - (Transcript.RetrieveCodingSequence().Count - 1); if (diff > 0) { scEnd3 = Transcript.RetrieveCodingSequence().Count - 1; // Pad with 'N' switch (diff) { case 1: padN = "N"; break; case 2: padN = "NN"; break; default: throw new ArgumentOutOfRangeException("Sanity check failed. Number of 'N' pading is :" + diff + ". This should not happen!"); } } // Get old codon (reference) CodonsReference = SequenceExtensions.ConvertToString(Transcript.RetrieveCodingSequence().GetSubSequence(scStart3, scLen3)); // Get new codon (change) string prepend = CodonsReference.Substring(0, (int)(scStart - scStart3)); string append = scEnd3 > scEnd?CodonsReference.Substring(CodonsReference.Length - (int)(scEnd3 - scEnd)) : ""; CodonsAlternate = prepend + NetCdsChange() + append; // Pad codons with 'N' if required CodonsReference += padN; CodonsAlternate += padN; //--- // Can we simplify codons? //--- if ((CodonsReference != null) && (CodonsAlternate != null)) { while ((CodonsReference.Length >= 3) && (CodonsAlternate.Length >= 3)) { // First codon string cold = CodonsReference.Substring(0, 3); string cnew = CodonsAlternate.Substring(0, 3); // Are codons equal? => Simplify if (cold.Equals(cnew, StringComparison.InvariantCultureIgnoreCase)) { CodonsReference = CodonsReference.Substring(3); CodonsAlternate = CodonsAlternate.Substring(3); CodonStartNumber++; } else { break; } } } }