diff --git a/modules/io/src/mol/mmcif_writer.cc b/modules/io/src/mol/mmcif_writer.cc index 6ea364aa868975fbb5cee1a8956809de576726d6..3e086fa8aa986928021857cdd3488b434f57bc78 100644 --- a/modules/io/src/mol/mmcif_writer.cc +++ b/modules/io/src/mol/mmcif_writer.cc @@ -811,6 +811,19 @@ namespace { String comp_id = res.GetName(); auto at_list = res.GetAtomList(); + + // sanity check that we have no duplicates + std::set<String> anames; + for(auto a: at_list) { + if(anames.find(a.GetName()) != anames.end()) { + std::stringstream ss; + ss << "Duplicate atom \"" << a.GetName() << "\" in residue "; + ss << a.GetResidue() << std::endl; + throw ost::io::IOException(ss.str()); + } + anames.insert(a.GetName()); + } + String auth_asym_id = res.GetChain().GetName(); if(res.HasProp("pdb_auth_chain_name")) { auth_asym_id = res.GetStringProp("pdb_auth_chain_name"); @@ -1328,9 +1341,35 @@ namespace { auto chain_list = ent.GetChainList(); for(auto chain: chain_list) { String cname = chain.GetName(); + + auto res_list = chain.GetResidueList(); + // sanity check that residue numbers are strictly increasing and have no + // insertion codes which is a requirement for mmCIF conform chains + // (not only for polymers) + for(size_t i = 0; i < res_list.size(); ++i) { + if(res_list[i].GetNumber().GetInsCode() != '\0') { + std::stringstream ss; + ss << "Residue number insertion codes must be empty if "; + ss << "mmcif_conform is enabled. Got \""; + ss << res_list[i].GetNumber().GetInsCode() << "\" in residue "; + ss << res_list[i]; + throw ost::io::IOException(ss.str()); + } + if(i>0) { + if(res_list[i-1].GetNumber().GetNum() >= + res_list[i].GetNumber().GetNum()) { + std::stringstream ss; + ss << "Residue numbers must be strictly increasing in consecutive "; + ss << "residues if mmcif_conform is enabled. "; + ss << "Got " << res_list[i-1] << " followed by " << res_list[i]; + ss << "."; + throw ost::io::IOException(ss.str()); + } + } + } + if(preassigned_polymer_chains.find(cname) != preassigned_polymer_chains.end()) { - auto res_list = chain.GetResidueList(); int entity_id = preassigned_polymer_chains[cname]; AddAsymResnum(cname, res_list, entity_info[entity_id], true); Feed_atom_site(atom_site, cname, entity_id+1, entity_info[entity_id], res_list); @@ -1338,7 +1377,6 @@ namespace { entity_info[entity_id], res_list); } else { // do automated matching - auto res_list = chain.GetResidueList(); int entity_id = SetupEntity(cname, chain.GetType(), res_list,