e70c7f68f61a3477631bd364c31f99c157528fc8 braney Fri Sep 4 12:48:02 2026 -0700 quickLift: lift chains, and let chain and bigChain tracks into the hub A chain is an alignment between the assembly the track came from and some other species, so lifting one composes two alignments and leaves the user with chains between the assembly on screen and that species. quickLiftChain does it by the same route the psl work uses: chainToPsl, then quickLiftPsl, then chainFromPsl, which is the inverse chainToPsl never had. It does not modify the chain handed to it. That matters more than it sounds: every chain loader leaves the header describing the whole chain while loading only the blocks in range, so the header has to be corrected for the conversion, but the callers still want the original. The details page reports it, and the track sorts on it, which is what puts a lifted chain in the same row as the native one. quickLiftSourceRanges hands back the ranges in the other assembly that the window maps to, for callers whose items cannot be had from a query quickLiftSql knows how to make. It works those ranges out by intersecting the window with each chain block rather than taking the whole block, which matters here because one block can be enormous: hg19 and hg38 run identical for 12.8Mb on chr7, and asking for all of it turned a 39 chain window into a 1892 chain one. quickLiftIsOwnChainTrack keeps quickLift's own chain track out of all this. That stanza carries quickLiftUrl and quickLiftDb like any lifted track and is loaded by bigChainLoadItems like any bigChain, but its data is already in reference coordinates. The giveaway is that its bigDataUrl is the quickLift chain file. validateOneTdb now accepts chain and bigChain. netAlign is still refused: a net is a hierarchy of gaps rather than a plain alignment and wants its own thought. refs #38249 diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c index 264bbb41fa4..d49d2f1cd2e 100644 --- src/hg/lib/trackHub.c +++ src/hg/lib/trackHub.c @@ -1940,43 +1940,47 @@ * 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) || \ + startsWithNoCase("bigChain", tdb->type) || \ + sameWord("chain", tdb->type) || + startsWithNoCase("chain ", 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("bigChain", 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; }