Skip to content

Support the new ECOD distribution format - #1141

Open
aalhossary wants to merge 2 commits into
biojava:masterfrom
aalhossary:aa/ecod-new-format
Open

Support the new ECOD distribution format#1141
aalhossary wants to merge 2 commits into
biojava:masterfrom
aalhossary:aa/ecod-new-format

Conversation

@aalhossary

Copy link
Copy Markdown
Member

Fixes #1139.

ECOD redesigned its distribution at v294.1. Neither the version comment nor the column layout is recognised any more, so EcodInstallationTest.testVersion fails and — less visibly — anyone calling EcodFactory.getEcodDatabase() today gets an empty domain list with no exception thrown.

The version comment

Release Header line
up to develop292 #ECOD version develop291
v294.1 onwards # Version: v295

parsedVersion stayed null and getVersion() fell back to the string that was requested, which for latest is the literal "latest" — the value the test asserts against. One pattern now matches both forms, so the historical releases keep working; a regex that only accepted the new form would silently break every pinned develop* version.

The columns

Format Columns Column header row
v1.4 / v1.5 (develop124, develop204) 15 #uid …
v1.6 (develop291) 16 — f_id renamed t_id, unp_acc inserted at 9 #uid …
v294.1 23 uid … — no longer commented out
v295 25 — adds ligand_comp_ids, ligand_pdbnum uid …

Rather than add a fourth positional special case, files that declare a column header — every release since develop101 — are now read by column name. That covers all four layouts at once and will not need revisiting the next time a column moves. Files older than develop101 have no header and keep the existing positional path, unchanged.

Everything else that moved with the columns:

  • manual_rep holds True/False rather than MANUAL_REP/AUTO_NONREP;
  • assembly_id is declared but empty on all 2,945,500 rows, meaning what NOT_DOMAIN_ASSEMBLY used to mean;
  • the ligand list moved to ligand_comp_ids;
  • ligand_pdbnum, the last column, is empty on 2,399,569 rows, so split("\t") was dropping it and making those rows look a column short. Trailing empty fields are now kept;
  • f_name is empty rather than F_UNCLASSIFIED for unclassified domains — deliberately left as it is, see below;
  • 1,573,776 rows (53%) describe domains found in AlphaFold models, with ids like P44140_F1_nD2 and an empty pdb column. EcodDomain is keyed by PdbId and cannot represent them, so they are counted and reported at INFO rather than each logged as an error.

Two failure modes that hid this are also closed: parsing nothing at all is now logged as an error instead of quietly returning an empty list, and the per-line NumberFormatException warning is capped like the three warnings beside it, rather than printing a stack trace per row.

getVersion() no longer parses the whole file

It reads the header. Parsing the current release in full to answer "which version?" costs 1,186 MB of heap and 9.8 s — and the test JVM is given -Xmx1500M by the root pom. The download is unchanged; only the parse is skipped. This is a small behaviour change, in that getVersion() no longer has the side effect of loading every domain, which the 7.3.0 target allows.

Measured

File domains before domains after
ecod.develop124.domains.txt 468,680 468,680
ecod.develop204.domains.txt 592,427 592,427
ecod.develop291.domains.txt 0 1,083,021
ecod.latest.domains.txt (v295) 0 1,371,723 + 1,573,776 model rows reported

The first two are the counts EcodInstallationTest already asserts, so the old path is provably untouched.

Tests

EcodParserTest is new and entirely offline. EcodParser already accepts a Reader, so fixtures taken verbatim from the real files pin all five layouts, both version comment forms, a row ending in an empty column, an AlphaFold-derived row and a malformed row. 15 tests, no network, well under a second:

mvn test -pl biojava-structure -Dtest=EcodParserTest

That is the part I would most like kept. The distribution is 657 MB, so the only test that ever touched the current release was testVersion, asserting on one string; everything else pins develop204. That is exactly why a wholesale format change surfaced as a single one-line assertion failure, months after it happened.

testVersion now also parses the first few thousand lines of the local file — enough to notice a column change without building three million domains.

mvn test -pl biojava-integrationtest -Dtest=EcodInstallationTest

9 tests, 1 skipped (testAllVersions, already @Ignored for being slow), green in 124 s.

Note on CI

Branched off master, so its PR Build will still show the CATH failure until #1133 merges. That is #1138, not something new here.

Three judgement calls I would rather not make alone

@sbliven — you wrote this parser and know the format history far better than I do. If you have the time, I would value your eyes on it, particularly on:

  1. unp_acc is read and discarded. develop291 carries a UniProt accession that EcodDomain has nowhere to put. Adding a field means touching equals/hashCode/toString/Comparable, so I left it out — but it is real data we are dropping.
  2. An empty f_name is left empty rather than translated to F_UNCLASSIFIED. They used to be equivalent; now f_id classifies to a fourth level (1.1.1.3) while the name is blank, so I do not think they are the same thing any more. If you disagree it is a one-line change.
  3. An empty assembly_id is mapped onto the old NOT_DOMAIN_ASSEMBLY semantics (assemblyId = uid). It is empty on every row of v294+, so assembly information is simply gone from the distribution; this keeps getAssemblyId() returning what callers expect rather than null.

Also deliberately out of scope, and worth a follow-up issue rather than growing this PR: valid_structure, ligand_binding, ligand_pdbnum, range_count and the five *_manual flags are new columns with no home in EcodDomain, and the AlphaFold half of the distribution needs a model that is not keyed by PdbId.

Unrelated but useful

ECOD now publishes ecod.latest.md5 in coreutils format alongside the distribution. That is a real hashURL for FileDownloadUtils.createValidationFiles(url, file, hashURL, Hash.MD5) — the path #1133 repairs and which, before it, could never write a hash file at all. Not wired up here; noting it so it is not lost.

ECOD redesigned its distribution at v294.1 and neither the version comment
nor the column layout is recognised any more.

The version comment changed from "#ECOD version develop291" to
"# Version: v295", so parsedVersion stayed null and getVersion() fell back
to the string that was requested. The columns changed from 15 (or 16 in
develop291, which inserts unp_acc) to 23 and then 25, so every data line in
the current release is rejected and getAllDomains() quietly returns an
empty list.

Files that declare a column header - every release since develop101 - are
now read by column name rather than by position, which covers all four
layouts at once and will not need revisiting the next time a column moves.
Older files keep the positional path unchanged. Along with the columns:

- manual_rep now holds True/False rather than MANUAL_REP/AUTO_NONREP
- assembly_id is empty on every row, meaning what NOT_DOMAIN_ASSEMBLY meant
- the ligand list moved to ligand_comp_ids
- the last column is empty on four rows in five, so trailing empty fields
  are kept rather than discarded by split()
- 53% of rows now describe domains found in AlphaFold models, which have no
  PDB entry and so cannot be an EcodDomain; they are counted and reported
  rather than logged as errors

Parsing nothing at all is now reported as an error instead of returning an
empty list silently, and the per-line NumberFormatException warning is
capped like the others rather than printing a stack trace per row.

getVersion() reads only the file header. Parsing the current 657 MB release
in full to answer that question costs over a gigabyte of heap, which does
not fit comfortably in the 1500 MB the test JVM is given.
The distribution is 657 MB, so the only test that touched the current
release was testVersion, which asserts on one string. Every other test pins
develop204. That is why a wholesale format change surfaced as a single
one-line assertion failure, eight months after it happened.

EcodParserTest reads fixtures taken verbatim from the real files - 13, 15,
16, 23 and 25 columns, both version comment forms, a row ending in an empty
column, an AlphaFold-derived row, and a malformed row - through the Reader
constructor. Fifteen tests, no network, well under a second.

testVersion additionally parses the first few thousand lines of the local
file. That is enough to notice a column change without building the three
million domains the whole file now holds.
@aalhossary

Copy link
Copy Markdown
Member Author

CI result on this branch, as expected: five jobs fail, all on CathDomainTest alone. ECOD no longer appears anywhere (run 31985806634).

[ERROR] Tests run: 164, Failures: 0, Errors: 1, Skipped: 10
[ERROR]   CathDomainTest.test:40 NullPointer

EcodInstallationTest passes on every job:

[INFO] Running org.biojava.nbio.structure.test.ecod.EcodInstallationTest
latest version of ECOD is v295
[WARNING] Tests run: 9, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 164.1 s

That is the last remaining failure in the module, it is #1138, and #1133 fixes it — so with #1133 and this merged, PR Build should be green with the integration tests still running, for the first time since 2025-12-14.

The ERROR-level ECOD line visible in the biojava-structure log is deliberate: EcodParserTest.unparseableLinesAreSkippedNotFatal feeds the parser a malformed row on purpose, to check that one bad line does not take the good ones with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ECOD changed its distribution format: neither the version header nor the column layout is recognised

1 participant