diff --git a/modules/io/src/mol/mmcif_reader.cc b/modules/io/src/mol/mmcif_reader.cc index e550d96f83dfc160819f860055561534606b48fd..0fa4516c496479abf7d281540eb758a7b51e3de1 100644 --- a/modules/io/src/mol/mmcif_reader.cc +++ b/modules/io/src/mol/mmcif_reader.cc @@ -134,12 +134,13 @@ bool MMCifReader::OnBeginLoop(const StarLoopDesc& header) this->TryStoreIdx(CARTN_X, "Cartn_x", header); this->TryStoreIdx(CARTN_Y, "Cartn_y", header); this->TryStoreIdx(CARTN_Z, "Cartn_z", header); + // optional (but warning: mandatory for waters/ligands) + indices_[AUTH_SEQ_ID] = header.GetIndex("auth_seq_id"); + indices_[PDBX_PDB_INS_CODE] = header.GetIndex("pdbx_PDB_ins_code"); // optional indices_[OCCUPANCY] = header.GetIndex("occupancy"); indices_[B_ISO_OR_EQUIV] = header.GetIndex("B_iso_or_equiv"); indices_[GROUP_PDB] = header.GetIndex("group_PDB"); - indices_[AUTH_SEQ_ID] = header.GetIndex("auth_seq_id"); - indices_[PDBX_PDB_INS_CODE] = header.GetIndex("pdbx_PDB_ins_code"); indices_[PDBX_PDB_MODEL_NUM] = header.GetIndex("pdbx_PDB_model_num"); indices_[FORMAL_CHARGE] = header.GetIndex("pdbx_formal_charge"); @@ -535,9 +536,25 @@ void MMCifReader::ParseAndAddAtom(const std::vector<StringRef>& columns) if(!curr_residue_) { update_residue=true; - subst_res_id_ = cif_chain_name + - columns[indices_[AUTH_SEQ_ID]].str() + - columns[indices_[PDBX_PDB_INS_CODE]].str(); + if (indices_[AUTH_SEQ_ID] != -1 && + indices_[PDBX_PDB_INS_CODE] != -1) { + subst_res_id_ = cif_chain_name + + columns[indices_[AUTH_SEQ_ID]].str() + + columns[indices_[PDBX_PDB_INS_CODE]].str(); + } else if (!valid_res_num) { + // Here we didn't have valid residue number in label_seq_id (which is + // expected for ligands and waters). To work around that we store the + // author residue number information (auth_seq_id + pdbx_PDB_ins_code) + // in subst_res_id_. This variable is never read directly, only used + // indirectly to detect if we have to create a new residue. + // If we're here we had both missing missing value in label_seq_id, + // and the auth_seq_id or pdbx_PDB_ins_code were missing. + // There may be more elegant ways to detect that we crossed to a new + // residue that don't rely on auth_seq_id/pdbx_PDB_ins_code. + throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR, + "Missing residue number information", + this->GetCurrentLinenum())); + } } else if (!valid_res_num) { if (indices_[AUTH_SEQ_ID] != -1 && indices_[PDBX_PDB_INS_CODE] != -1) { @@ -601,8 +618,12 @@ void MMCifReader::ParseAndAddAtom(const std::vector<StringRef>& columns) curr_residue_ = editor.AppendResidue(curr_chain_, res_name.str()); } curr_residue_.SetStringProp("pdb_auth_chain_name", auth_chain_name); - curr_residue_.SetStringProp("pdb_auth_resnum", columns[indices_[AUTH_SEQ_ID]].str()); - curr_residue_.SetStringProp("pdb_auth_ins_code", columns[indices_[PDBX_PDB_INS_CODE]].str()); + if (indices_[AUTH_SEQ_ID] != -1) { + curr_residue_.SetStringProp("pdb_auth_resnum", columns[indices_[AUTH_SEQ_ID]].str()); + } + if (indices_[PDBX_PDB_INS_CODE] != -1) { + curr_residue_.SetStringProp("pdb_auth_ins_code", columns[indices_[PDBX_PDB_INS_CODE]].str()); + } curr_residue_.SetStringProp("entity_id", columns[indices_[LABEL_ENTITY_ID]].str()); curr_residue_.SetStringProp("resnum", columns[indices_[LABEL_SEQ_ID]].str()); warned_name_mismatch_=false;