Skip to content

Commit 3ca8fad

Browse files
committed
Change lipid-inter numeratino as in sasa and extract some common parts
1 parent 052189a commit 3ca8fad

3 files changed

Lines changed: 116 additions & 73 deletions

File tree

‎src/routes/knowledge/lipid-inter/index.js‎

Lines changed: 70 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ const handler = require('../../../utils/generic-handler');
55
const getDatabase = require('../../../database');
66
// Standard HTTP response status codes
77
const { NOT_FOUND, INTERNAL_SERVER_ERROR } = require('../../../utils/status-codes');
8+
const { PROTEIN_RESIDUE_NAME_LETTERS } = require('../../../utils/constants');
89
const { getHost } = require('../../../utils/auxiliar-functions');
10+
const { buildKnowledgeResponse, formatKnowledgeDate } = require('../shared');
911

1012
// Set the name of the current analysis
1113
const ANALYSIS_NAME = 'lipid-inter';
@@ -66,25 +68,7 @@ router.route('/').get( handler({ async retriever(request) {
6668
poreFacingFractions = channelsData.data?.pore_residues?.pore_facing || [];
6769
}
6870
}
69-
// Set the sites list according to MemProtMD schema
70-
const sites = [
71-
{
72-
site_id: 1,
73-
label: "membrane lipid acyl-tail interacting residue",
74-
},
75-
{
76-
site_id: 2,
77-
label: "membrane lipid head-group interacting residue",
78-
},
79-
{
80-
site_id: 3,
81-
label: "solvent interacting residue",
82-
},
83-
{
84-
site_id: 4,
85-
label: "pore-facing residue",
86-
},
87-
];
71+
8872

8973
// Helper function to classify confidence based on interaction fraction
9074
const classifyConfidence = (value) => {
@@ -124,8 +108,14 @@ router.route('/').get( handler({ async retriever(request) {
124108
// To do so we must anotate data in PDB reference PDB chains and residues
125109
// Get chain data according to the FunPDBe schema
126110
const pdbChains = [];
127-
// Iterate over the different PDB chains
128-
for (const [chainLetter, uniprotId] of Object.entries(pdbReference.chain_uniprots)) {
111+
// Iterate over the different UniProt ids
112+
// Note that we may have more tha one chain in the PDB belonging to the same UniProt
113+
// Note that we may have more tha one chain in the simulation to the same UniProt
114+
// There are many possible scenarios and there is no simple rule to match chains always
115+
// For this reason, for every different UniProt id, we will use only the first chain
116+
// We will path values from the first system chain with numeration of the first PDB chain
117+
const uniprotIds = new Set(Object.values(pdbReference.chain_uniprots));
118+
for (const uniprotId of uniprotIds) {
129119
// Find the reference index in the topology
130120
const referenceIndex = topologyData.references.indexOf(uniprotId);
131121
// It may happen that the reference is not found
@@ -134,18 +124,22 @@ router.route('/').get( handler({ async retriever(request) {
134124
// Get residue indices for residues which belong to this reference/chain
135125
const residueIndices = [];
136126
Object.entries(topologyData.residue_reference_indices).forEach(([residueIndex, residueReferenceIndex]) => {
137-
if (residueReferenceIndex === referenceIndex) residueIndices.push(parseInt(residueIndex));
127+
if (residueReferenceIndex === referenceIndex) residueIndices.push(residueIndex);
138128
});
139-
// Get residue data according to the FunPDBe schema
140-
const pdbResidues = [];
141-
142129
// Iterate residue indices
143-
residueIndices.forEach(residueIndex => {
144-
// Get the residue numeration according to the reference (uniprot and thus the PDB)
145-
const residueNumber = topologyData.residue_reference_numbers[residueIndex];
146-
// Get residue name
147-
const residueName = topologyData.residue_names[residueIndex];
148-
130+
for (const residueIndex of residueIndices) {
131+
// Get the residue numeration according to the reference (uniprot)
132+
const residueUniprotNumber = topologyData.residue_reference_numbers[residueIndex];
133+
// Now use the uniprot 2 pdb map to get the equivalent PDB values
134+
const uniprotKey = `${uniprotId}_${residueUniprotNumber}`;
135+
const pdbEquivalent = pdbReference.uni2pdb[uniprotKey];
136+
if (!pdbEquivalent) continue;
137+
// If there is no PDB equivalent then this residue is not present in the PDB
138+
// We will return no data for this specific residue
139+
const [chainLetter, residueLabel, residueType] = pdbEquivalent;
140+
// Get the amino acid single letter code
141+
const residueLetter = PROTEIN_RESIDUE_NAME_LETTERS[residueType] || 'X';
142+
149143
// Get max contact probability for tail and head across all lipid types
150144
const tailInteraction = tailByResidue[residueIndex] || 0;
151145
const headInteraction = headByResidue[residueIndex] || 0;
@@ -173,12 +167,16 @@ router.route('/').get( handler({ async retriever(request) {
173167
}
174168
];
175169

170+
// Get the list of residues which belong to the current chain
171+
let pdbResidues = pdbChains[chainLetter];
172+
if (pdbResidues === undefined)
173+
pdbChains[chainLetter] = pdbResidues = [];
176174
// Add current PDB residue to the list
177175
pdbResidues.push({
178-
pdb_res_label: residueNumber.toString(),
179-
aa_type: residueName,
176+
pdb_res_label: residueLabel,
177+
aa_type: residueType,
180178
additional_residue_annotations: {
181-
MDDB_lipid_data: {
179+
mddb_lipid_data: {
182180
'group=Tail': tailInteraction,
183181
'group=Head': headInteraction,
184182
'group=Solvent': solventInteraction,
@@ -187,15 +185,15 @@ router.route('/').get( handler({ async retriever(request) {
187185
},
188186
site_data: site_data
189187
});
190-
})
191-
// Add the current PDB chain to the list
192-
pdbChains.push({
193-
chain_label: chainLetter,
194-
residues: pdbResidues
195-
})
188+
}
196189
}
190+
// Convert the pdbChains object to an array
191+
const finalPdbChains = Object.entries(pdbChains).map(([chainLabel, residues]) => ({
192+
chain_label: chainLabel,
193+
residues: residues
194+
}));
197195
// If no PDB chains were found then something is wrong
198-
if (pdbChains.length === 0) return {
196+
if (finalPdbChains.length === 0) return {
199197
headerError: INTERNAL_SERVER_ERROR,
200198
error: 'Something went wrong when searching for PDB chains'
201199
}
@@ -206,22 +204,38 @@ router.route('/').get( handler({ async retriever(request) {
206204
// Add the cliente equivalent project URL as it has been suggested
207205
// HARDCODE: El host de la query no tiene por que ser el del cliente
208206
// HARDCODE: De hecho una API podría no tener cliente asociado o tener varios
209-
const url = `${protocol}://${host}/#/id/${project.accession}/`;
207+
const url = `${protocol}://${host}/#/id/${request.params.project}/`;
208+
// Set the date in the expected format
209+
const funschemaDate = formatKnowledgeDate(pdbReference.date);
210210
// Return the final response in the expected format
211-
return {
212-
data_resource: "MDDB",
213-
resource_version: "0.0",
214-
resource_entry_url: url,
215-
model_coordinates_url: `https://www.ebi.ac.uk/pdbe/entry/pdb/${pdbReference.id}`,
216-
release_date: pdbReference.date,
217-
pdb_id: pdbReference.id,
218-
chains: pdbChains,
219-
evidence_code_ontology: [{
220-
"eco_term": "molecular dynamics evidence used in automatic assertion",
221-
"eco_code": "ECO_0006373"
222-
}],
223-
sites: sites,
224-
};
211+
return buildKnowledgeResponse({
212+
resourceVersion: '0.0',
213+
resourceEntryUrl: url,
214+
modelCoordinatesUrl: `https://www.ebi.ac.uk/pdbe/entry/pdb/${pdbReference.id}`,
215+
releaseDate: funschemaDate,
216+
pdbId: pdbReference.id,
217+
sourceId: request.params.project,
218+
chains: finalPdbChains,
219+
// Set the sites list according to MemProtMD schema
220+
sites: [
221+
{
222+
site_id: 1,
223+
label: "membrane lipid acyl-tail interacting residue",
224+
},
225+
{
226+
site_id: 2,
227+
label: "membrane lipid head-group interacting residue",
228+
},
229+
{
230+
site_id: 3,
231+
label: "solvent interacting residue",
232+
},
233+
{
234+
site_id: 4,
235+
label: "pore-facing residue",
236+
},
237+
],
238+
});
225239
}}));
226240

227241
module.exports = router;

‎src/routes/knowledge/sasa/index.js‎

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const getDatabase = require('../../../database');
66
// Standard HTTP response status codes
77
const { NOT_FOUND, INTERNAL_SERVER_ERROR } = require('../../../utils/status-codes');
88
const { PROTEIN_RESIDUE_NAME_LETTERS, KNOWLEDGE_REFERENCE_KEYWORD } = require('../../../utils/constants');
9+
const { buildKnowledgeResponse, formatKnowledgeDate } = require('../shared');
910
const {
1011
caluclateMeanAndStandardDeviation,
1112
min, max, round2tenths, getHost
@@ -251,24 +252,16 @@ router.route('/').get( handler({ async retriever(request) {
251252
// HARDCODE: De hecho una API podría no tener cliente asociado o tener varios
252253
const url = isReference ? pdbUrl : `${protocol}://${host}/#/id/${request.params.project}/`;
253254
// Set the date in the expected format
254-
const date = new Date(referenceData.date);
255-
const funschemaDate = `${date.getMonth()}/${date.getDate()}/${date.getFullYear()}`;
255+
const funschemaDate = formatKnowledgeDate(referenceData.date);
256256
// Return the final response in the expected format
257-
return {
258-
data_resource: "MDDB",
259-
resource_version: "0.0",
260-
resource_entry_url: url,
261-
model_coordinates_url: pdbUrl,
262-
release_date: funschemaDate,
263-
pdb_id: referenceData.id,
264-
additional_entry_annotations: {
265-
source_id: request.params.project,
266-
},
257+
return buildKnowledgeResponse({
258+
resourceVersion: '0.0',
259+
resourceEntryUrl: url,
260+
modelCoordinatesUrl: pdbUrl,
261+
releaseDate: funschemaDate,
262+
pdbId: referenceData.id,
263+
sourceId: request.params.project,
267264
chains: pdbChains,
268-
evidence_code_ontology: [{
269-
"eco_term": "molecular dynamics evidence used in automatic assertion",
270-
"eco_code": "ECO_0006373",
271-
}],
272265
sites: [
273266
{
274267
site_id: 1,
@@ -295,7 +288,7 @@ router.route('/').get( handler({ async retriever(request) {
295288
additional_site_annotations: { percentage: "24-26" },
296289
},
297290
],
298-
};
291+
});
299292
}}));
300293

301294
module.exports = router;

‎src/routes/knowledge/shared.js‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const formatKnowledgeDate = (dateValue) => {
2+
const date = new Date(dateValue);
3+
return `${date.getMonth()}/${date.getDate()}/${date.getFullYear()}`;
4+
};
5+
6+
const buildKnowledgeResponse = ({
7+
resourceVersion,
8+
resourceEntryUrl,
9+
modelCoordinatesUrl,
10+
releaseDate,
11+
pdbId,
12+
sourceId,
13+
chains,
14+
sites,
15+
}) => ({
16+
data_resource: 'MDDB',
17+
resource_version: resourceVersion,
18+
resource_entry_url: resourceEntryUrl,
19+
model_coordinates_url: modelCoordinatesUrl,
20+
release_date: releaseDate,
21+
pdb_id: pdbId,
22+
additional_entry_annotations: {
23+
source_id: sourceId,
24+
},
25+
chains,
26+
evidence_code_ontology: [{
27+
eco_term: 'molecular dynamics evidence used in automatic assertion',
28+
eco_code: 'ECO_0006373',
29+
}],
30+
sites,
31+
});
32+
33+
module.exports = {
34+
buildKnowledgeResponse,
35+
formatKnowledgeDate,
36+
};

0 commit comments

Comments
 (0)