eeac40956b3dd6611f58aeb847ff5c404d3ce883
angie
  Fri Dec 1 09:05:41 2023 -0800
Support trees whose reference/root is not from a db or hub, but rather a custom .2bit file.
This means that the selected pathogen may or may not also be a db/hub, so the selection interacts with the db cart variable but does not always match it.
Also, in phyloPlace.c, update RSV metadata column headers (RGCC lineages replace Ramaekers 2020 clades).

diff --git src/hg/hgPhyloPlace/hgPhyloPlace.c src/hg/hgPhyloPlace/hgPhyloPlace.c
index 4dc7bca..ec9739c 100644
--- src/hg/hgPhyloPlace/hgPhyloPlace.c
+++ src/hg/hgPhyloPlace/hgPhyloPlace.c
@@ -67,105 +67,114 @@
 else if (isNotEmpty(fileBinaryCoords))
     {
     fprintf(stderr, "%s=%s fileBinaryCoords=%s\n", cartVar, fileName, fileBinaryCoords);
     char *binInfo = cloneString(fileBinaryCoords);
     char *words[2];
     char *mem;
     unsigned long size;
     chopByWhite(binInfo, words, ArraySize(words));
     mem = (char *)sqlUnsignedLong(words[0]);
     size = sqlUnsignedLong(words[1]);
     lf = lineFileDecompressMem(TRUE, mem, size);
     }
 return lf;
 }
 
-static char *labelForDb(char *db)
-/* The assembly hub name is just the accession; make a special label for hMPXV.  Otherwise just
- * return hGenome(db). */
+static char *labelForDb(char *db, boolean addDescription)
+/* If config defines a user-friendly name then return that; otherwise return hGenome(db).
+ * If addDescription is set and config defines a description then tack that on. */
 {
 char *label = phyloPlaceDbSetting(db, "name");
 if (isEmpty(label))
     label = hGenome(db);
+if (addDescription)
+    {
+    char *desc = phyloPlaceDbSetting(db, "description");
+    if (isNotEmpty(desc))
+        {
+        struct dyString *dy = dyStringCreate("%s %s", label, desc);
+        label = dyStringCannibalize(&dy);
+        }
+    }
 return label;
 }
 
 static int labelCmp(const void *va, const void *vb)
 /* Compare two slPairs on their string values -- but treat SARS-CoV-2 as more important. */
 {
 const struct slPair *a = *((struct slPair **)va);
 const struct slPair *b = *((struct slPair **)vb);
 if (sameString((char *)(a->val), "SARS-CoV-2"))
     return -1;
 else if (sameString((char *)(b->val), "SARS-CoV-2"))
     return 1;
 return strcmp((char *)(a->val), (char *)(b->val));
 }
 
 
 static struct slName *sortByLabel(struct slName *dbList)
 /* Return a newly allocated version of dbList, sorted by labelForDb value -- but favor SARS-CoV-2. */
 {
 struct slPair *dbLabelList = NULL;
 struct slName *sln;
 for (sln = dbList;  sln != NULL;  sln = sln->next)
-    slPairAdd(&dbLabelList, sln->name, cloneString(labelForDb(sln->name)));
+    slPairAdd(&dbLabelList, sln->name, cloneString(labelForDb(sln->name, TRUE)));
 slSort(&dbLabelList, labelCmp);
 struct slName *newList = NULL;
 struct slPair *slp;
 for (slp = dbLabelList;  slp != NULL;  slp = slp->next)
     slAddHead(&newList, slNameNew(slp->name));
 slReverse(&newList);
 slPairFreeValsAndList(&dbLabelList);
 return newList;
 }
 
 static void selectDb(char **pDb, char **pLabel)
 /* Search for assembly config.ra files in hgPhyloPlaceData.  If there is more than one
  * supported assembly, then make a menu / select input for supported  assemblies;
  * reload the page on change. */
 {
 struct slName *supportedDbs = sortByLabel(phyloPlaceDbList(cart));
 if (supportedDbs == NULL)
     errAbort("Sorry, this server is not configured to perform phylogenetic placement.");
 if (!slNameInList(supportedDbs, *pDb))
     {
     *pDb = cloneString(supportedDbs->name);
     }
-*pLabel = labelForDb(*pDb);
+*pLabel = labelForDb(*pDb, FALSE);
+char *selectVar = "hpp_ref";
 int supportedDbCount = slCount(supportedDbs);
 if (supportedDbCount > 1)
     {
     char *labels[supportedDbCount];
     char *values[supportedDbCount];
     struct slName *sDb;
     int i;
     for (sDb = supportedDbs, i = 0;  i < supportedDbCount;  sDb = sDb->next, i++)
         {
         values[i] = sDb->name;
-        labels[i] = labelForDb(values[i]);
+        labels[i] = labelForDb(values[i], TRUE);
         }
-    char *selectVar = "db";
     struct dyString *dy = jsOnChangeStart();
     jsDropDownCarryOver(dy, selectVar);
     char *js = jsOnChangeEnd(&dy);
     puts("<p>Choose your pathogen: ");
     cgiMakeDropListFull(selectVar, labels, values, supportedDbCount, *pDb, "change", js);
     puts("</p>");
     }
 else
-    cgiMakeHiddenVar("db", *pDb);
+    cgiMakeHiddenVar(selectVar, *pDb);
 slNameFreeList(&supportedDbs);
 }
 
 static void newPageStartStuff()
 {
 // Copied these from hgGtexTrackSettings.c which says "// NOTE: This will likely go to web.c".
 puts("<link rel='stylesheet' href='../style/gb.css'>");
 puts("<link rel='stylesheet' href='../style/hgGtexTrackSettings.css'>");
 
 //#*** TODO: move this out to a CSS (hardcoding for now because we're doing a standalone push
 //#*** independent of the release cycle).
 puts("<style>\n"
 "#warnBox {\n"
 "    border: 3px ridge DarkRed;\n"
 "    width:640px;\n"
@@ -441,98 +450,110 @@
      );
 puts("</div>");
 puts("</div>");
 puts("</form>");
 }
 
 static void mainPage(char *db)
 {
 // Start web page with new-style header
 webStartGbNoBanner(cart, db, "UShER: Upload");
 jsInit();
 jsIncludeFile("jquery.js", NULL);
 jsIncludeFile("ajax.js", NULL);
 newPageStartStuff();
 
-// Hidden form for reloading page when db select is changed
-static char *saveVars[] = { "db" };
+// Hidden form for reloading page when hpp_ref select is changed
+static char *saveVars[] = { "hpp_ref" };
 jsCreateHiddenForm(cart, cgiScriptName(), saveVars, ArraySize(saveVars));
 
 puts("<div class='row'>"
      "  <div class='row gbSectionBannerLarge'>\n"
      "    <div class='col-md-11'>UShER: Ultrafast Sample placement on Existing tRee</div>\n"
      "    <div class='col-md-1'></div>\n"
      "  </div>\n"
      "</div>\n"
      "<div class='row'>\n");
 if (hgPhyloPlaceEnabled())
     {
     inputForm(db);
     }
 else
     {
     puts("  <div class='gbControl col-md-12'>");
     puts("  Sorry, this server is not configured to perform phylogenetic placement.");
     puts("  </div>");
     }
 puts("</div>\n");
 
 newPageEndStuff();
 }
 
-static void resultsPage(char *db, struct lineFile *lf)
+static void resultsPage(char *db, char *refName, struct lineFile *lf)
 /* QC the user's uploaded sequence(s) or VCF; if input looks valid then run usher
  * and display results. */
 {
+// If refName is a real database or hub then set db to refName.
+if (hDbExists(refName))
+    db = refName;
+else
+    {
+    // Not a db -- see if it's a hub that is already connected:
+    struct trackHubGenome *hubGenome = trackHubGetGenomeUndecorated(db);
+    if (hubGenome != NULL)
+        db = refName;
+    // Otherwise we're counting on the config to specify a .2bit file and we won't make CTs.
+    }
 webStartGbNoBanner(cart, db, "UShER: Results");
 jsIncludeFile("jquery.js", NULL);
 jsIncludeFile("ajax.js", NULL);
 newPageStartStuff();
 
 if (issueBotWarning)
     {
     char *ip = getenv("REMOTE_ADDR");
     botDelayMessage(ip, botDelayMillis);
     }
 
 // Allow 10 minutes for big sets of sequences
 lazarusLives(15 * 60);
 
 puts("<div class='row'>"
      "  <div class='row gbSectionBannerLarge'>\n"
      "    <div class='col-md-11'>UShER: Ultrafast Sample placement on Existing tRee</div>\n"
      "    <div class='col-md-1'></div>\n"
      "  </div>\n"
      "</div>\n"
      "<div class='row'>\n");
 // Form submits subtree custom tracks to hgTracks
 printf("<form action='%s' name='resultsForm' method=%s>\n\n",
        hgTracksName(), cartUsualString(cart, "formMethod", "POST"));
 cartSaveSession(cart);
+cgiMakeHiddenVar("db", db);
 puts("  <div class='gbControl col-md-12'>");
 fflush(stdout);
 
 if (lf != NULL)
     {
     // Use trackLayout to get hgTracks parameters relevant to displaying trees:
     struct trackLayout tl;
     trackLayoutInit(&tl, cart);
     // Do our best to place the user's samples, make custom tracks if successful:
     char *phyloPlaceTree = cartOptionalString(cart, "phyloPlaceTree");
     int subtreeSize = cartUsualInt(cart, "subtreeSize", 50);
     boolean success = FALSE;
-    char *ctFile = phyloPlaceSamples(lf, db, phyloPlaceTree, measureTiming, subtreeSize,
+    char *ctFile = phyloPlaceSamples(lf, db, refName, phyloPlaceTree, measureTiming, subtreeSize,
                                      tl.fontHeight, &success);
     if (ctFile)
         {
         cgiMakeHiddenVar(CT_CUSTOM_TEXT_VAR, ctFile);
         if (tl.leftLabelWidthChars < 0 || tl.leftLabelWidthChars == leftLabelWidthDefaultChars)
             cgiMakeHiddenVar(leftLabelWidthVar, leftLabelWidthForLongNames);
         cgiMakeButton("submit", "view in Genome Browser");
         puts("  </div>");
         puts("</form>");
         }
     else if (! success)
         {
         puts("<p></p>");
         puts("  </div>");
         puts("</form>");
@@ -683,70 +704,74 @@
         errAbort("Usher server mode not configured for db=%s", db);
     }
 else
     errAbort("Bad request");
 popWarnHandler();
 popAbortHandler();
 }
 
 static void doMiddle(struct cart *theCart)
 /* Set up globals and make web page */
 {
 cart = theCart;
 char *db = NULL, *genome = NULL;
 // Get the current db from the cart
 getDbAndGenome(cart, &db, &genome, oldVars);
+// The currently selected pathogen reference sequence may or may not be a db/hub.
+char *refName = cartOptionalString(cart, "hpp_ref");
+if (isEmpty(refName))
+    refName = cloneString(db);
 
 int timeout = cartUsualInt(cart, "udcTimeout", 300);
 if (udcCacheTimeout() < timeout)
     udcSetCacheTimeout(timeout);
 knetUdcInstall();
 
 measureTiming = cartUsualBoolean(cart, "measureTiming", measureTiming);
 
 char *submitLabel = cgiOptionalString("submit");
 char *newExampleButton = cgiOptionalString("exampleButton");
 if ((submitLabel && sameString(submitLabel, "try example")) ||
     (newExampleButton && sameString(newExampleButton, "Upload Example File")))
     {
-    char *exampleFile = phyloPlaceDbSettingPath(db, "exampleFile");
+    char *exampleFile = phyloPlaceDbSettingPath(refName, "exampleFile");
     struct lineFile *lf = lineFileOpen(exampleFile, TRUE);
-    resultsPage(db, lf);
+    resultsPage(db, refName, lf);
     }
 else if (cgiOptionalString(remoteFileVar))
     {
     char *url = cgiString(remoteFileVar);
     struct lineFile *lf = netLineFileOpen(url);
-    resultsPage(db, lf);
+    resultsPage(db, refName, lf);
     }
 else if (isNotEmpty(trimSpaces(cgiOptionalString(pastedIdVar))))
     {
     char *pastedIds = cgiString(pastedIdVar);
     struct lineFile *lf = lineFileOnString("pasted names/IDs", TRUE, pastedIds);
-    resultsPage(db, lf);
+    resultsPage(db, refName, lf);
     }
 else if (cgiOptionalString(seqFileVar) || cgiOptionalString(seqFileVar "__filename"))
     {
     struct lineFile *lf = lineFileFromFileInput(cart, seqFileVar);
-    resultsPage(db, lf);
+    resultsPage(db, refName, lf);
     }
 else if (isNotEmpty(cgiOptionalString(serverCommandVar)))
     {
-    sendServerCommand(db);
+    sendServerCommand(refName);
     }
 else
-    mainPage(db);
+    mainPage(refName);
 }
 
 #define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
 
 static void addLdLibraryPath()
 /* usher requires a tbb lib that is not in the yum package tbb-devel, so for now
  * I'm adding the .so files to hgPhyloPlaceData.  Set environment variable LD_LIBRARY_PATH
  * to pick them up from there. */
 {
 char *oldValue = getenv(LD_LIBRARY_PATH);
 struct dyString *dy = dyStringNew(0);
 if (startsWith("/", PHYLOPLACE_DATA_DIR))
     dyStringAppend(dy, PHYLOPLACE_DATA_DIR);
 else
     {