d0ed51d077718213c0b843a89fd6f36ac32f1804
braney
  Fri Sep 4 11:39:28 2026 -0700
quickLift: lift alignments, and let psl and bigPsl tracks into the hub

Every type quickLift handled so far is one set of coordinates on one genome, so
the lift is a call to remapBlockedBed.  An alignment carries coordinates on both
sides at once, with a block start on each, so moving the genome side means
splitting and trimming blocks while keeping the other side lined up with them.

quickLiftPsl does that with pieces that were already in the tree: pick the chain
with liftOverChainForRange, the same one the bed path picks, turn it into a
mapping alignment with chainToPsl plus pslSwap, then pslTransMap.  The mapping
alignment is kept per chain, since rebuilding it for every item costs nothing at
gene zoom and a great deal zoomed out.

Two things pslTransMap does had to be undone.  It recounts match and mismatch off
the blocks, which would read every lifted alignment as a perfect match and draw
every item at full shade, so quickLiftPslCounts puts the original counts back,
scaled by how much of the alignment survived.  And it leaves a protein alignment
in nucleotide space, which the base alignment view rejects, so
quickLiftPslBackToProtein returns the query side to protein units when the lift
did not split a codon.

quickLiftChainHash hands out the chains for a reference range for callers that
collected their items some other way.  validateOneTdb now accepts psl and bigPsl,
and bigPsl joins bigBed and bigWig in the bigDataUrl fill-in.

refs #38249

diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c
index ca08288f003..264bbb41fa4 100644
--- src/hg/lib/trackHub.c
+++ src/hg/lib/trackHub.c
@@ -1939,40 +1939,44 @@
 /* Make sure the tdb is a track type we grok.  badList may be NULL to validate
  * silently (no user-facing complaint about non-liftable types). */
 {
 // trackDb types are matched without regard to case since that's how the rest of the
 // browser reads them (some trackDb stanzas say "bigbed" rather than "bigBed").
 if (sameString("cytoBandIdeo", trackHubSkipHubName(tdb->track)) ||
     !( startsWithNoCase("bigBed", tdb->type) || \
        startsWithNoCase("bigWig", tdb->type) || \
        startsWithNoCase("bigDbSnp", tdb->type) || \
        startsWithNoCase("bigGenePred", tdb->type) || \
        startsWithNoCase("gvf", tdb->type) || \
        startsWithNoCase("genePred", tdb->type) || \
        startsWithNoCase("narrowPeak", tdb->type) || \
        startsWithNoCase("broadPeak", tdb->type) || \
        startsWithNoCase("bigLolly", tdb->type) || \
+       startsWithNoCase("bigPsl", tdb->type) || \
+       sameWord("psl", tdb->type) ||
+       startsWithNoCase("psl ", tdb->type) ||
        sameWord("bed", tdb->type) ||
        startsWithNoCase("bed ", tdb->type)))
     {
     if (badList != NULL)
         slAddHead(badList, tdb);
     return FALSE;
     }
 
 // make sure we have a bigDataUrl
 if (startsWithNoCase("bigBed", tdb->type) || \
+       startsWithNoCase("bigPsl", tdb->type) || \
        startsWithNoCase("bigWig", tdb->type))
     {
     char *fileName = cloneString(trackDbSetting(tdb, "bigDataUrl"));
 
     if (fileName == NULL)
         {
         struct sqlConnection *conn = hAllocConnTrack(db, tdb);
         fileName = bbiNameFromSettingOrTable(tdb, conn, tdb->table);
         hashAdd(tdb->settingsHash, "bigDataUrl", fileName);
         hFreeConn(&conn);
         }
     }
 
 return TRUE;
 }