288c7b7d7573211134a3d2fdced0911324b9de70 max Fri Oct 18 04:13:03 2024 -0700 adding primer3 exon amp mode support to primer3 links, refs #34657 diff --git src/hg/cgilib/hgSeq.c src/hg/cgilib/hgSeq.c index f0b6f9a..0922fe8 100644 --- src/hg/cgilib/hgSeq.c +++ src/hg/cgilib/hgSeq.c @@ -7,30 +7,33 @@ #include "dnautil.h" #include "dnaseq.h" #include "dystring.h" #include "cart.h" #include "cheapcgi.h" #include "hdb.h" #include "web.h" #include "rmskOut.h" #include "fa.h" #include "genePred.h" #include "bed.h" #include "hgSeq.h" #include "trackHub.h" #include "hubConnect.h" +// primer3 can design primers around exons like exonprimer, but needs some flanking +// sequence around the transcript for the first and the last primer +const int PRIMER3EXTEND = 200; int hgSeqChromSize(char *db, char *chromName) /* get chrom size if there's a database out there, * otherwise just return 0 */ { int thisSize = 0; if (hDbExists(db)) thisSize = hChromSize(db, chromName); return thisSize; } void hgSeqFeatureRegionOptions(struct cart *cart, boolean canDoUTR, boolean canDoIntrons) /* Print out HTML FORM entries for feature region options. */ { @@ -258,45 +261,48 @@ static struct dyString *genPrimer3Exons(int rCount, unsigned *rStarts, unsigned *rSizes, boolean *exonFlags, int seqStart) /* generate string with exon positions on transcript sequence, format <relExonStart>-<relExonEnd,... e.g. "10-20,30-40," and return. * Result must be freed.*/ { struct dyString* exonStr = dyStringNew(1024); for (int i=0; i < rCount; i++) { int start = rStarts[i] - seqStart; int size = rSizes[i]; if (exonFlags[i]) dyStringPrintf(exonStr, "%d-%d,", start, size); } return exonStr; } -static void printPrimerForm(char *seq, char *exons, char *db, char strand, char *returnUrl) { +static void printPrimerForm(char *seq, char *exons, char *db, char strand, char *returnUrl, int primer3Extend) { /* print the form to send arguments to primer3 and click the submit button */ puts("<form id='primer3Form' method='POST' action='https://dev.primer3plus.com/primer3plus/api/v1/upload'>\n"); printf("<input type='hidden' name='SEQUENCE_TEMPLATE' value='%s'>\n", seq); printf("<input type='hidden' name='P3P_GB_EXONS' value='%s'>\n", exons); printf("<input type='hidden' name='P3P_GB_DB' value='%s'>\n", db); printf("<input type='hidden' name='P3P_GB_ORIENTATION' value='%c'>\n", strand); printf("<input type='hidden' name='P3P_GB_RETURN_PATH' value='%s'>\n", returnUrl); char *chrom = cgiString("c"); char *winLeft = cgiString("l"); char *winRight = cgiString("r"); - printf("<input type='hidden' name='P3P_GB_POSITION' value='%s:%s-%s'>\n", chrom, winLeft, winRight); + int chromStart = atoi(winLeft) - primer3Extend; + int chromEnd = atoi(winRight) + primer3Extend; + + printf("<input type='hidden' name='P3P_GB_POSITION' value='%s:%d-%d'>\n", chrom, chromStart, chromEnd); puts("<input style='display:none' type='submit' value='Submit'>"); puts("</form>"); jsInline("document.getElementById(\"primer3Form\").submit();\n"); } static void hgSeqConcatRegionsDb(char *db, char *chrom, int chromSize, char strand, char *name, int rCount, unsigned *rStarts, unsigned *rSizes, boolean *exonFlags, boolean *cdsFlags, boolean toPrimer3) /* Concatenate and print out dna for a series of regions. * * If toPrimer3 is true, will send them to primer3, overriding most arguments to allow exon-exon primers..*/ { // Note: this code use to generate different sequence ids if the global // database in hdb was different than the db parameter. This functionality // has been removed since the global database was removed and it didn't @@ -425,31 +431,31 @@ } memcpy(cSeq->dna+offset, rSeq->dna+start, size); offset += size; } assert(offset == cSeq->size); cSeq->dna[offset] = 0; freeDnaSeq(&rSeq); if (isRc && !toPrimer3) reverseComplement(cSeq->dna, cSeq->size); if (toPrimer3) { struct dyString* primer3Exons = genPrimer3Exons(rCount, rStarts, rSizes, exonFlags, seqStart); - printPrimerForm(cSeq->dna, primer3Exons->string, db, strand, hgAbsUrlCgi("hgTracks")); + printPrimerForm(cSeq->dna, primer3Exons->string, db, strand, hgAbsUrlCgi("hgTracks"), PRIMER3EXTEND); dyStringFree(&primer3Exons); } else { safef(recName, sizeof(recName), "%s_%s range=%s:%d-%d 5'pad=%d 3'pad=%d " "strand=%c repeatMasking=%s", hubConnectSkipHubPrefix(db), hubConnectSkipHubPrefix(name), chrom, seqStart+1, seqEnd, padding5, padding3, (isRc ? '-' : '+'), (maskRep ? repMasking : "none")); faWriteNext(stdout, recName, cSeq->dna, cSeq->size); freeDnaSeq(&cSeq); @@ -574,38 +580,38 @@ boolean promoter = cgiBoolean("hgSeq.promoter"); boolean intron = cgiBoolean("hgSeq.intron"); boolean utrExon5 = cgiBoolean("hgSeq.utrExon5"); boolean cdsExon = cgiBoolean("hgSeq.cdsExon"); boolean utrExon3 = cgiBoolean("hgSeq.utrExon3"); boolean downstream = cgiBoolean("hgSeq.downstream"); int promoterSize = cgiOptionalInt("hgSeq.promoterSize", 0); int downstreamSize = cgiOptionalInt("hgSeq.downstreamSize", 0); char *granularity = cgiOptionalString("hgSeq.granularity"); boolean toPrimer3 = cgiBoolean("primer3"); if (toPrimer3) { - promoter = FALSE; + promoter = TRUE; utrExon5 = TRUE; intron = TRUE; cdsExon = TRUE; utrExon3 = TRUE; - downstream = FALSE; - downstreamSize = 0; - promoterSize = 0; + downstream = TRUE; + downstreamSize = PRIMER3EXTEND; + promoterSize = PRIMER3EXTEND; granularity = "gene"; } boolean utrIntron3 = utrExon3 && intron; boolean utrIntron5 = utrExon5 && intron; boolean cdsIntron = cdsExon && intron; boolean concatRegions = granularity && sameString("gene", granularity); boolean concatAdjacent = (cgiBooleanDefined("hgSeq.splitCDSUTR") && (! cgiBoolean("hgSeq.splitCDSUTR"))); if (toPrimer3) concatAdjacent = TRUE; boolean isCDS, doIntron;