From cd212c056b7c7949c6cf155636214aa2a902110a Mon Sep 17 00:00:00 2001 From: yokochi47 Date: Fri, 6 Dec 2024 18:25:00 +0900 Subject: [PATCH] Append _Spectral_dim and _Spectral_dim_transfer loops --- wwpdb/utils/nmr/NmrDpUtility.py | 2 +- wwpdb/utils/nmr/mr/ParserListenerUtil.py | 114 +++++++++++++++++++-- wwpdb/utils/nmr/pk/BasePKParserListener.py | 43 +++++++- 3 files changed, 146 insertions(+), 13 deletions(-) diff --git a/wwpdb/utils/nmr/NmrDpUtility.py b/wwpdb/utils/nmr/NmrDpUtility.py index 80b084e0..d94779ae 100644 --- a/wwpdb/utils/nmr/NmrDpUtility.py +++ b/wwpdb/utils/nmr/NmrDpUtility.py @@ -32240,7 +32240,7 @@ def __mergeAnyPkAsIs(self): sf = master_entry.get_saveframe_by_name(sf_framecode) text_data = get_first_sf_tag(sf, 'Text_data') - if any(loop for loop in sf.loops if loop.category in ('_Peak_raw_format', '_Peak'))\ + if any(loop for loop in sf.loops if loop.category in ('_Peak_row_format', '_Peak'))\ or text_data not in emptyValue: list_id += 1 diff --git a/wwpdb/utils/nmr/mr/ParserListenerUtil.py b/wwpdb/utils/nmr/mr/ParserListenerUtil.py index 2e64738f..b34d9d24 100644 --- a/wwpdb/utils/nmr/mr/ParserListenerUtil.py +++ b/wwpdb/utils/nmr/mr/ParserListenerUtil.py @@ -2020,13 +2020,23 @@ {'name': 'Entry_ID', 'type': 'str', 'mandatory': True} ]) -NMR_STAR_AUX_LP_CATEGORIES = {'dist_restraint': ['_Gen_dist_constraint_software_param'] +NMR_STAR_AUX_LP_CATEGORIES = {'dist_restraint': ['_Gen_dist_constraint_software_param' + ], + 'spectral_peak': ['_Spectral_dim', 'Spectral_dim_transfer' + ] } NMR_STAR_AUX_LP_KEY_ITEMS = {'dist_restraint': {'_Gen_dist_constraint_software_param': [ - {'name': 'Software_ID', 'type': 'int', 'mandatory': True}, - {'name': 'Type', 'type': 'str', 'mandatory': True}] - } + {'name': 'Software_ID', 'type': 'int'}, + {'name': 'Type', 'type': 'str'}] + }, + 'spectral_peak': {'_Spectral_dim': [ + {'name': 'ID', 'type': 'positive-int', 'auto-increment': True} + ], + '_Spectral_dim_transfer': [ + {'name': 'Spectral_dim_ID_1', 'type': 'positive-int'}, + {'name': 'Spectral_dim_ID_2', 'type': 'positive-int'}] + } } NMR_STAR_AUX_LP_DATA_ITEMS = {'dist_restraint': {'_Gen_dist_constraint_software_param': [ @@ -2035,7 +2045,39 @@ {'name': 'Gen_dist_constraint_list_ID', 'type': 'pointer-index', 'mandatory': True, 'default': '1', 'default-from': 'parent'}, {'name': 'Entry_ID', 'type': 'str', 'mandatory': True}] - } + }, + 'spectral_peak': {'_Spectral_dim': [ + {'name': 'Atom_type', 'type': 'enum', 'mandatory': True, + 'enum': set(ISOTOPE_NUMBERS_OF_NMR_OBS_NUCS.keys()), + 'enforce-enum': True}, + {'name': 'Atom_isotope_number', 'type': 'enum-int', 'mandatory': True, + 'enum': set(ALLOWED_ISOTOPE_NUMBERS), + 'enforce-enum': True}, + {'name': 'Axis_code', 'type': 'str'}, + {'name': 'Spectrometer_frequency', 'type': 'positive-float', 'mandatory': False, + 'enforce-non-zero': True}, + {'name': 'Spectral_region', 'type': 'str', 'mandatory': True}, + {'name': 'Sweep_width', 'type': 'positive-float', 'mandatory': False, + 'enforce-non-zero': True}, + {'name': 'Sweep_width_units', 'type': 'enum', 'mandatory': True, + 'enum': ('ppm', 'Hz'), + 'enforce-enum': True}, + {'name': 'Value_first_point', 'type': 'float', 'mandatory': False}, + {'name': 'Absolute_peak_positions', 'type': 'bool', 'mandatory': False}, + {'name': 'Acquisition', 'type': 'bool', 'mandatory': False}, + {'name': 'Center_frequency_offset', 'type': 'float', 'mandatory': False}, + {'name': 'Spectral_peak_list_ID', 'type': 'pointer-index', 'mandatory': True, + 'default': '1', 'default-from': 'parent'}, + {'name': 'Entry_ID', 'type': 'str', 'mandatory': True}], + 'Spectral_dim_transfer': [ + {'name': 'Type', 'type': 'enum', 'mandatory': True, + 'enum': ('onebond', 'jcoupling', 'jmultibond', 'relayed', 'relayed-alternate', 'through-space'), + 'enforce-enum': True}, + {'name': 'Indirect', 'type': 'bool', 'mandatory': False}, + {'name': 'Spectral_peak_list_ID', 'type': 'pointer-index', 'mandatory': True, + 'default': '1', 'default-from': 'parent'}, + {'name': 'Entry_ID', 'type': 'str', 'mandatory': True}] + } } CARTN_DATA_ITEMS = [{'name': 'Cartn_x', 'type': 'float', 'alt_name': 'x'}, @@ -2075,15 +2117,15 @@ 'atom_type': None, 'atom_isotope_number': None, 'spectral_region': None, - 'magnetization_linkage_id': None, + # 'magnetization_linkage_id': None, not required for _Peak_row_format loop 'sweep_width': None, 'sweep_width_unit': None, 'value_first_point': None, 'absolute_peak_positions': None, 'acquisition': None, 'center_frequency_offset': None, - 'encoding_code': None, - 'encoded_reduced_dimension_id': None + # 'encoding_code': None, not required for _Peak_row_format loop + # 'encoded_reduced_dimension_id': None not required for _Peak_row_format loop } @@ -8056,6 +8098,62 @@ def getPkRow(pkSubtype: str, id: int, indexId: int, return row +def getSpectralDimRow(id: int, listId: int, entryId: str, meta: dict) -> List[Any]: + """ Return row data for a _Spectral_dim loop. + @return: data array + """ + + content_subtype = 'spectral_peak' + lp_category = '_Spectral_dim' + + key_size = len(NMR_STAR_AUX_LP_KEY_ITEMS[content_subtype][lp_category]) + data_items = NMR_STAR_AUX_LP_DATA_ITEMS[content_subtype][lp_category] + + row = [None] * (key_size + len(data_items)) + + row[0] = id + + for idx, data_item in enumerate(data_items, start=key_size): + data_name = data_item['name'].lower() + if data_name in meta: + row[idx] = meta[data_name] + + row[-2] = listId + row[-1] = entryId + + return row + + +def getSpectralDimTransferRow(listId: int, entryId: str, meta: dict) -> List[Any]: + """ Return row data for a _Spectral_dim_transfer loop. + @return: data array + """ + + content_subtype = 'spectral_peak' + lp_category = '_Spectral_dim_transfer' + + key_items = NMR_STAR_AUX_LP_KEY_ITEMS[content_subtype][lp_category] + data_items = NMR_STAR_AUX_LP_DATA_ITEMS[content_subtype][lp_category] + + key_size = len(key_items) + + row = [None] * (key_size + len(data_items)) + + for idx, key_item in enumerate(key_items): + key_name = key_item['name'].lower() + row[idx] = meta[key_name] + + for idx, data_item in enumerate(data_items, start=key_size): + data_name = data_item['name'].lower() + if data_name in meta: + row[idx] = meta[data_name] + + row[-2] = listId + row[-1] = entryId + + return row + + def getMaxEffDigits(vals: List[str]) -> int: """ Return maximum effective precision of float strings. """ diff --git a/wwpdb/utils/nmr/pk/BasePKParserListener.py b/wwpdb/utils/nmr/pk/BasePKParserListener.py index fc17a864..c92d3a7a 100644 --- a/wwpdb/utils/nmr/pk/BasePKParserListener.py +++ b/wwpdb/utils/nmr/pk/BasePKParserListener.py @@ -32,6 +32,9 @@ decListIdCounter, getSaveframe, getPkLoop, + getAuxLoops, + getSpectralDimRow, + getSpectralDimTransferRow, getMaxEffDigits, roundString, ISOTOPE_NUMBERS_OF_NMR_OBS_NUCS, @@ -91,6 +94,9 @@ decListIdCounter, getSaveframe, getPkLoop, + getAuxLoops, + getSpectralDimRow, + getSpectralDimTransferRow, getMaxEffDigits, roundString, ISOTOPE_NUMBERS_OF_NMR_OBS_NUCS, @@ -423,7 +429,7 @@ def enter(self): def exit(self, spectrum_names: Optional[dict] = None): - self.fillSpectralDimTransfer(spectrum_names) + self.fillPkAuxLoops(spectrum_names) try: @@ -760,7 +766,7 @@ def fillAtomTypeInCase(self, _dim_id: int, atom_type: str) -> bool: return True return False - def fillSpectralDimTransfer(self, spectrum_names: Optional[dict]): + def fillPkAuxLoops(self, spectrum_names: Optional[dict]): if len(self.spectral_dim) > 0: for d, v in self.spectral_dim.items(): for _id, _v in v.items(): @@ -1140,7 +1146,7 @@ def fillSpectralDimTransfer(self, spectrum_names: Optional[dict]): if 'yes' in (_dict1['acquisition'], _dict2['acquisition']): transfer = {'spectral_dim_id_1': min([_dim_id1, _dim_id2]), 'spectral_dim_id_2': max([_dim_id1, _dim_id2]), - 'type': 'through-space?', + 'type': 'through-space', # optimistic inferencing? 'indirect': 'yes'} cur_spectral_dim_transfer.append(transfer) @@ -1156,7 +1162,7 @@ def fillSpectralDimTransfer(self, spectrum_names: Optional[dict]): if 'yes' in (_dict1['acquisition'], _dict2['acquisition']): transfer = {'spectral_dim_id_1': min([_dim_id1, _dim_id2]), 'spectral_dim_id_2': max([_dim_id1, _dim_id2]), - 'type': 'through-space?', + 'type': 'through-space', # optimistic inferencing? 'indirect': 'yes'} cur_spectral_dim_transfer.append(transfer) @@ -1173,6 +1179,35 @@ def fillSpectralDimTransfer(self, spectrum_names: Optional[dict]): for transfer in cur_spectral_dim_transfer: print(transfer) + if self.createSfDict__: + self.cur_subtype = f'peak{d}d' + self.cur_list_id = _id + + sf = self.getSf() + + list_id = sf['list_id'] + sf['aux_loops'] = getAuxLoops('spectral_peak') + + aux_lp = next((aux_lp for aux_lp in sf['aux_loops'] if aux_lp.category == '_Spectral_dim'), None) + + if aux_lp is None: + continue + + for _dim_id, _dict in cur_spectral_dim.items(): + aux_lp.add_data(getSpectralDimRow(_dim_id, list_id, self.entryId, _dict)) + + sf['saveframe'].add_loop(aux_lp) + + aux_lp = next((aux_lp for aux_lp in sf['aux_loops'] if aux_lp.category == '_Spectral_dim_transfer'), None) + + if aux_lp is None: + continue + + for _dict in cur_spectral_dim_transfer: + aux_lp.add_data(getSpectralDimTransferRow(list_id, self.entryId, _dict)) + + sf['saveframe'].add_loop(aux_lp) + def validatePeak2D(self, index: int, pos_1: float, pos_2: float, pos_unc_1: Optional[float], pos_unc_2: Optional[float], lw_1: Optional[float], lw_2: Optional[float],