Skip to content
Snippets Groups Projects
Commit e2a7ca6d authored by David Sehnal's avatar David Sehnal
Browse files

wip refactoring custom props

parent f028ad05
No related branches found
No related tags found
No related merge requests found
...@@ -36,10 +36,50 @@ export namespace StructureQualityReport { ...@@ -36,10 +36,50 @@ export namespace StructureQualityReport {
{ {
name: 'pdbe_structure_quality_report_issues', name: 'pdbe_structure_quality_report_issues',
instance(ctx) { instance(ctx) {
const prop = get(ctx.firstModel);
if (!prop) return CifWriter.Category.Empty;
let groupCtx: ReportExportContext;
if (ctx.cache.pdbe_structure_quality_report_issues) groupCtx = ctx.cache.pdbe_structure_quality_report_issues;
else {
const exportCtx = prop.data!.getExportContext(ctx.structures[0]);
groupCtx = createExportContext(exportCtx);
ctx.cache.pdbe_structure_quality_report_issues = groupCtx;
}
return { return {
fields: _structure_quality_report_issues_fields, fields: _structure_quality_report_issues_fields,
source: ctx.structures.map(s => IndexedCustomProperty.getCifDataSource(s, StructureQualityReport.getIssueMap(s.model), ctx.cache)) source: [{ data: groupCtx, rowCount: groupCtx.elements.length }]
}; }
// return {
// fields: _structure_quality_report_issues_fields,
// source: ctx.structures.map(s => IndexedCustomProperty.getCifDataSource(s, StructureQualityReport.getIssueMap(s.model), ctx.cache))
// };
}
}, {
name: 'pdbe_structure_quality_report_issue_types',
instance(ctx) {
const prop = get(ctx.firstModel);
if (!prop) return CifWriter.Category.Empty;
let groupCtx: ReportExportContext;
if (ctx.cache.pdbe_structure_quality_report_issues) groupCtx = ctx.cache.pdbe_structure_quality_report_issues;
else {
const exportCtx = prop.data!.getExportContext(ctx.structures[0]);
groupCtx = createExportContext(exportCtx);
ctx.cache.pdbe_structure_quality_report_issues = groupCtx;
}
return {
fields: _structure_quality_report_issue_types_fields,
source: [{ data: groupCtx, rowCount: groupCtx.rows.length }]
}
// return {
// fields: _structure_quality_report_issues_fields,
// source: ctx.structures.map(s => IndexedCustomProperty.getCifDataSource(s, StructureQualityReport.getIssueMap(s.model), ctx.cache))
// };
} }
}] }]
}, },
...@@ -58,13 +98,20 @@ export namespace StructureQualityReport { ...@@ -58,13 +98,20 @@ export namespace StructureQualityReport {
id: Column.Schema.int, id: Column.Schema.int,
...mmCIF_residueId_schema, ...mmCIF_residueId_schema,
pdbx_PDB_model_num: Column.Schema.int, pdbx_PDB_model_num: Column.Schema.int,
issues: Column.Schema.List(',', x => x) issue_group_id: Column.Schema.int
},
pdbe_structure_quality_report_issue_types: {
group_id: Column.Schema.int,
issue_type: Column.Schema.str
} }
} }
function getCifData(model: Model) { function getCifData(model: Model) {
if (model.sourceData.kind !== 'mmCIF') throw new Error('Data format must be mmCIF.'); if (model.sourceData.kind !== 'mmCIF') throw new Error('Data format must be mmCIF.');
return toTable(Schema.pdbe_structure_quality_report_issues, model.sourceData.frame.categories.pdbe_structure_quality_report_issues); return {
residues: toTable(Schema.pdbe_structure_quality_report_issues, model.sourceData.frame.categories.pdbe_structure_quality_report_issues),
groups: toTable(Schema.pdbe_structure_quality_report_issue_types, model.sourceData.frame.categories.pdbe_structure_quality_report_issue_types),
}
} }
export async function attachFromCifOrApi(model: Model, params: { export async function attachFromCifOrApi(model: Model, params: {
...@@ -77,7 +124,7 @@ export namespace StructureQualityReport { ...@@ -77,7 +124,7 @@ export namespace StructureQualityReport {
let info = PropertyWrapper.tryGetInfoFromCif('pdbe_structure_quality_report', model); let info = PropertyWrapper.tryGetInfoFromCif('pdbe_structure_quality_report', model);
if (info) { if (info) {
const data = getCifData(model); const data = getCifData(model);
issueMap = createIssueMapFromCif(model, data); issueMap = createIssueMapFromCif(model, data.residues, data.groups);
} else if (params.PDBe_apiSourceJson) { } else if (params.PDBe_apiSourceJson) {
const data = await params.PDBe_apiSourceJson(model); const data = await params.PDBe_apiSourceJson(model);
if (!data) return false; if (!data) return false;
...@@ -112,12 +159,39 @@ export namespace StructureQualityReport { ...@@ -112,12 +159,39 @@ export namespace StructureQualityReport {
} }
type ExportCtx = IndexedCustomProperty.ExportCtx<string[]> type ExportCtx = IndexedCustomProperty.ExportCtx<string[]>
const _structure_quality_report_issues_fields: CifField<number, ExportCtx>[] = CifWriter.fields() const _structure_quality_report_issues_fields: CifField<number, ReportExportContext>[] = CifWriter.fields<number, ReportExportContext>()
.index('id') .index('id')
.many(residueIdFields((i, d) => d.elements[i])) .many(residueIdFields((i, d) => d.elements[i], { includeModelNum: true }))
.int('pdbx_PDB_model_num', (i, d) => P.unit.model_num(d.elements[i])) .int('group_id', (i, d) => d.groupId[i])
.str('issues', (i, d) => d.property(i).join(',')) .getFields();
.getFields()
interface ReportExportContext extends ExportCtx {
groupId: number[],
rows: [number, string][]
}
const _structure_quality_report_issue_types_fields: CifField<number, ReportExportContext>[] = CifWriter.fields<number, ReportExportContext>()
.int('group_id', (i, d) => d.rows[i][0])
.str('issue_type', (i, d) => d.rows[i][1])
.getFields();
function createExportContext(ctx: ExportCtx): ReportExportContext {
const groupMap = new Map<string, number>();
const groupId: number[] = [];
const rows: ReportExportContext['rows'] = [];
for (let i = 0; i < ctx.elements.length; i++) {
const issues = ctx.property(i);
const key = issues.join(',');
if (!groupMap.has(key)) {
const idx = groupMap.size + 1;
groupMap.set(key, idx);
for (const issue of issues) {
rows.push([idx, issue]);
}
}
groupId[i] = groupMap.get(key)!;
}
return { ...ctx, groupId, rows };
}
function createIssueMapFromJson(modelData: Model, data: any): StructureQualityReport.IssueMap | undefined { function createIssueMapFromJson(modelData: Model, data: any): StructureQualityReport.IssueMap | undefined {
const ret = new Map<ResidueIndex, string[]>(); const ret = new Map<ResidueIndex, string[]>();
...@@ -143,15 +217,36 @@ function createIssueMapFromJson(modelData: Model, data: any): StructureQualityRe ...@@ -143,15 +217,36 @@ function createIssueMapFromJson(modelData: Model, data: any): StructureQualityRe
return IndexedCustomProperty.fromResidueMap(ret); return IndexedCustomProperty.fromResidueMap(ret);
} }
function createIssueMapFromCif(modelData: Model, data: Table<typeof StructureQualityReport.Schema.pdbe_structure_quality_report_issues>): StructureQualityReport.IssueMap | undefined { function createIssueMapFromCif(modelData: Model,
residueData: Table<typeof StructureQualityReport.Schema.pdbe_structure_quality_report_issues>,
groupData: Table<typeof StructureQualityReport.Schema.pdbe_structure_quality_report_issue_types>): StructureQualityReport.IssueMap | undefined {
const ret = new Map<ResidueIndex, string[]>(); const ret = new Map<ResidueIndex, string[]>();
const { label_entity_id, label_asym_id, auth_seq_id, pdbx_PDB_ins_code, issues, pdbx_PDB_model_num, _rowCount } = data; const { label_entity_id, label_asym_id, auth_seq_id, pdbx_PDB_ins_code, issue_group_id, pdbx_PDB_model_num, _rowCount } = residueData;
const groups = parseIssueTypes(groupData);
for (let i = 0; i < _rowCount; i++) { for (let i = 0; i < _rowCount; i++) {
if (pdbx_PDB_model_num.value(i) !== modelData.modelNum) continue; if (pdbx_PDB_model_num.value(i) !== modelData.modelNum) continue;
const idx = modelData.atomicHierarchy.index.findResidue(label_entity_id.value(i), label_asym_id.value(i), auth_seq_id.value(i), pdbx_PDB_ins_code.value(i)); const idx = modelData.atomicHierarchy.index.findResidue(label_entity_id.value(i), label_asym_id.value(i), auth_seq_id.value(i), pdbx_PDB_ins_code.value(i));
ret.set(idx, issues.value(i)); ret.set(idx, groups.get(issue_group_id.value(i))!);
} }
return IndexedCustomProperty.fromResidueMap(ret); return IndexedCustomProperty.fromResidueMap(ret);
}
function parseIssueTypes(groupData: Table<typeof StructureQualityReport.Schema.pdbe_structure_quality_report_issue_types>): Map<number, string[]> {
const ret = new Map<number, string[]>();
const { group_id, issue_type } = groupData;
for (let i = 0; i < groupData._rowCount; i++) {
let group: string[];
const id = group_id.value(i);
if (ret.has(id)) group = ret.get(id)!;
else {
group = [];
ret.set(id, group);
}
group.push(issue_type.value(i));
}
return ret;
} }
\ No newline at end of file
...@@ -74,9 +74,21 @@ function mappedProp<K, D>(loc: (key: K, data: D) => StructureElement, prop: (e: ...@@ -74,9 +74,21 @@ function mappedProp<K, D>(loc: (key: K, data: D) => StructureElement, prop: (e:
return (k: K, d: D) => prop(loc(k, d)); return (k: K, d: D) => prop(loc(k, d));
} }
export function residueIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: { prefix?: string, postfix?: string }): CifField<K, D>[] { function addModelNum<K, D>(fields: CifWriter.Field.Builder<K, D>, getLocation: (key: K, data: D) => StructureElement, options?: IdFieldsOptions) {
if (options && options.includeModelNum) {
fields.int('pdbx_PDB_model_num', mappedProp(getLocation, P.unit.model_num));
}
}
export interface IdFieldsOptions {
prefix?: string,
postfix?: string,
includeModelNum?: boolean
}
export function residueIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: IdFieldsOptions): CifField<K, D>[] {
const prefix = options && options.prefix, postfix = options && options.postfix; const prefix = options && options.prefix, postfix = options && options.postfix;
return CifWriter.fields<K, D>() const ret = CifWriter.fields<K, D>()
.str(prepostfixed(prefix, postfix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id)) .str(prepostfixed(prefix, postfix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id))
.int(prepostfixed(prefix, postfix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), { .int(prepostfixed(prefix, postfix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), {
encoder: E.deltaRLE, encoder: E.deltaRLE,
...@@ -93,29 +105,35 @@ export function residueIdFields<K, D>(getLocation: (key: K, data: D) => Structur ...@@ -93,29 +105,35 @@ export function residueIdFields<K, D>(getLocation: (key: K, data: D) => Structur
.str(prepostfixed(prefix, postfix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id)) .str(prepostfixed(prefix, postfix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id))
.int(prepostfixed(prefix, postfix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE }) .int(prepostfixed(prefix, postfix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE })
.str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) .str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id));
.getFields();
addModelNum(ret, getLocation, options);
return ret.getFields();
} }
export function chainIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: { prefix?: string, postfix?: string }): CifField<K, D>[] { export function chainIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: IdFieldsOptions): CifField<K, D>[] {
const prefix = options && options.prefix, postfix = options && options.postfix; const prefix = options && options.prefix, postfix = options && options.postfix;
return CifField.build<K, D>() const ret = CifField.build<K, D>()
.str(prepostfixed(prefix, postfix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id)) .str(prepostfixed(prefix, postfix, `label_asym_id`), mappedProp(getLocation, P.chain.label_asym_id))
.str(prepostfixed(prefix, postfix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)) .str(prepostfixed(prefix, postfix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id))
.str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) .str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id))
.getFields();
addModelNum(ret, getLocation, options);
return ret.getFields();
} }
export function entityIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: { prefix?: string, postfix?: string }): CifField<K, D>[] { export function entityIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: IdFieldsOptions): CifField<K, D>[] {
const prefix = options && options.prefix, postfix = options && options.postfix; const prefix = options && options.prefix, postfix = options && options.postfix;
return CifField.build<K, D>() const ret = CifField.build<K, D>()
.str(prepostfixed(prefix, postfix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id)) .str(prepostfixed(prefix, postfix, `label_entity_id`), mappedProp(getLocation, P.chain.label_entity_id))
.getFields();
addModelNum(ret, getLocation, options);
return ret.getFields();
} }
export function atomIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: { prefix?: string, postfix?: string }): CifField<K, D>[] { export function atomIdFields<K, D>(getLocation: (key: K, data: D) => StructureElement, options?: IdFieldsOptions): CifField<K, D>[] {
const prefix = options && options.prefix, postfix = options && options.postfix; const prefix = options && options.prefix, postfix = options && options.postfix;
return CifWriter.fields<K, D>() const ret = CifWriter.fields<K, D>()
.str(prepostfixed(prefix, postfix, `label_atom_id`), mappedProp(getLocation, P.atom.label_atom_id)) .str(prepostfixed(prefix, postfix, `label_atom_id`), mappedProp(getLocation, P.atom.label_atom_id))
.str(prepostfixed(prefix, postfix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id)) .str(prepostfixed(prefix, postfix, `label_comp_id`), mappedProp(getLocation, P.residue.label_comp_id))
.int(prepostfixed(prefix, postfix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), { .int(prepostfixed(prefix, postfix, `label_seq_id`), mappedProp(getLocation, P.residue.label_seq_id), {
...@@ -135,6 +153,8 @@ export function atomIdFields<K, D>(getLocation: (key: K, data: D) => StructureEl ...@@ -135,6 +153,8 @@ export function atomIdFields<K, D>(getLocation: (key: K, data: D) => StructureEl
.str(prepostfixed(prefix, postfix, `auth_atom_id`), mappedProp(getLocation, P.atom.auth_atom_id)) .str(prepostfixed(prefix, postfix, `auth_atom_id`), mappedProp(getLocation, P.atom.auth_atom_id))
.str(prepostfixed(prefix, postfix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id)) .str(prepostfixed(prefix, postfix, `auth_comp_id`), mappedProp(getLocation, P.residue.auth_comp_id))
.int(prepostfixed(prefix, postfix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE }) .int(prepostfixed(prefix, postfix, `auth_seq_id`), mappedProp(getLocation, P.residue.auth_seq_id), { encoder: E.deltaRLE })
.str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id)) .str(prepostfixed(prefix, postfix, `auth_asym_id`), mappedProp(getLocation, P.chain.auth_asym_id));
.getFields();
addModelNum(ret, getLocation, options);
return ret.getFields();
} }
\ No newline at end of file
...@@ -43,26 +43,26 @@ async function run() { ...@@ -43,26 +43,26 @@ async function run() {
try { try {
// const testFile = '1crn.cif' // const testFile = '1crn.cif'
const testFile = '1cbs_updated.cif' const testFile = '1cbs_updated.cif'
const request = createJob({
entryId: path.join(examplesPath, testFile),
queryName: 'full',
queryParams: { }
});
// const request = createJob({ // const request = createJob({
// entryId: path.join(examplesPath, testFile), // entryId: path.join(examplesPath, testFile),
// queryName: 'atoms', // queryName: 'full',
// queryParams: { // queryParams: { }
// atom_site: { label_comp_id: 'ALA' }
// }
// }); // });
// const request = createJob({ // const request = createJob({
// entryId: path.join(examplesPath, testFile), // entryId: path.join(examplesPath, testFile),
// queryName: 'residueInteraction', // queryName: 'atoms',
// queryParams: { // queryParams: {
// atom_site: { label_comp_id: 'REA' }, // atom_site: { label_comp_id: 'ALA' }
// radius: 5
// } // }
// }); // });
const request = createJob({
entryId: path.join(examplesPath, testFile),
queryName: 'residueInteraction',
queryParams: {
atom_site: { label_comp_id: 'REA' },
radius: 5
}
});
const encoder = await resolveJob(request); const encoder = await resolveJob(request);
const writer = wrapFile(path.join(outPath, testFile)); const writer = wrapFile(path.join(outPath, testFile));
encoder.writeTo(writer); encoder.writeTo(writer);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment