diff --git a/actions/ost-compare-structures b/actions/ost-compare-structures index 75972640de0c7dd4869470593ab00628962beb97..fbae451dcb0dcaf34f906674b84d22c3063ad67a 100644 --- a/actions/ost-compare-structures +++ b/actions/ost-compare-structures @@ -494,6 +494,13 @@ def _ParseArgs(): return parser.parse_args() +def _RoundOrNone(num, decimals = 3): + """ Helper to create valid JSON output + """ + if num is None: + return None + return round(num, decimals) + def _Rename(ent): """Revert chain names to original names. @@ -614,7 +621,7 @@ def _LocalScoresToJSONDict(score_dict): for ch, ch_scores in score_dict.items(): for num, s in ch_scores.items(): ins_code = num.ins_code.strip("\u0000") - json_dict[f"{ch}.{num.num}.{ins_code}"] = s + json_dict[f"{ch}.{num.num}.{ins_code}"] = _RoundOrNone(s) return json_dict def _InterfaceResiduesToJSONList(interface_dict): @@ -635,7 +642,8 @@ def _PatchScoresToJSONList(interface_dict, score_dict): """ json_list = list() for ch, ch_nums in interface_dict.items(): - json_list += score_dict[ch] + for item in score_dict[ch]: + json_list.append(_RoundOrNone(item)) return json_list def _GetAlignedResidues(aln): @@ -711,7 +719,7 @@ def _Process(model, reference, args): out["pepnuc_aligned_residues"] = _GetAlignedResidues(scorer.pepnuc_aln) if args.lddt: - out["lddt"] = scorer.lddt + out["lddt"] = _RoundOrNone(scorer.lddt) if args.local_lddt: out["local_lddt"] = _LocalScoresToJSONDict(scorer.local_lddt) @@ -725,7 +733,7 @@ def _Process(model, reference, args): out["reference_bad_angles"] = [x.ToJSON() for x in scorer.target_bad_angles] if args.bb_lddt: - out["bb_lddt"] = scorer.bb_lddt + out["bb_lddt"] = _RoundOrNone(scorer.bb_lddt) if args.bb_local_lddt: out["bb_local_lddt"] = _LocalScoresToJSONDict(scorer.bb_local_lddt) @@ -737,13 +745,15 @@ def _Process(model, reference, args): out["local_cad_score"] = _LocalScoresToJSONDict(scorer.local_cad_score) if args.qs_score: - out["qs_global"] = scorer.qs_global - out["qs_best"] = scorer.qs_best + out["qs_global"] = _RoundOrNone(scorer.qs_global) + out["qs_best"] = _RoundOrNone(scorer.qs_best) out["qs_reference_interfaces"] = scorer.qs_target_interfaces out["qs_model_interfaces"] = scorer.qs_model_interfaces out["qs_interfaces"] = scorer.qs_interfaces - out["per_interface_qs_global"] = scorer.per_interface_qs_global - out["per_interface_qs_best"] = scorer.per_interface_qs_best + out["per_interface_qs_global"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_qs_global] + out["per_interface_qs_best"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_qs_best] if args.ics or args.ips: out["reference_contacts"] = scorer.native_contacts @@ -751,39 +761,45 @@ def _Process(model, reference, args): out["contact_reference_interfaces"] = scorer.contact_target_interfaces if args.ics: - out["ics_precision"] = scorer.ics_precision - out["ics_recall"] = scorer.ics_recall - out["ics"] = scorer.ics - out["per_interface_ics_precision"] = scorer.per_interface_ics_precision - out["per_interface_ics_recall"] = scorer.per_interface_ics_recall - out["per_interface_ics"] = scorer.per_interface_ics + out["ics_precision"] = _RoundOrNone(scorer.ics_precision) + out["ics_recall"] = _RoundOrNone(scorer.ics_recall) + out["ics"] = _RoundOrNone(scorer.ics) + out["per_interface_ics_precision"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ics_precision] + out["per_interface_ics_recall"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ics_recall] + out["per_interface_ics"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ics] if args.ips: - out["ips_precision"] = scorer.ips_precision - out["ips_recall"] = scorer.ips_recall - out["ips"] = scorer.ips - out["per_interface_ips_precision"] = scorer.per_interface_ips_precision - out["per_interface_ips_recall"] = scorer.per_interface_ips_recall - out["per_interface_ips"] = scorer.per_interface_ips + out["ips_precision"] = _RoundOrNone(scorer.ips_precision) + out["ips_recall"] = _RoundOrNone(scorer.ips_recall) + out["ips"] = _RoundOrNone(scorer.ips) + out["per_interface_ips_precision"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ips_precision] + out["per_interface_ips_recall"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ips_recall] + out["per_interface_ips"] = \ + [_RoundOrNone(x) for x in scorer.per_interface_ips] if args.dockq: out["dockq_reference_interfaces"] = scorer.dockq_target_interfaces out["dockq_interfaces"] = scorer.dockq_interfaces - out["dockq"] = scorer.dockq_scores - out["fnat"] = scorer.fnat - out["irmsd"] = scorer.irmsd - out["lrmsd"] = scorer.lrmsd + out["dockq"] = [_RoundOrNone(x) for x in scorer.dockq_scores] + out["fnat"] = [_RoundOrNone(x) for x in scorer.fnat] + out["irmsd"] = [_RoundOrNone(x) for x in scorer.irmsd] + out["lrmsd"] = [_RoundOrNone(x) for x in scorer.lrmsd] out["nnat"] = scorer.nnat out["nmdl"] = scorer.nmdl - out["dockq_ave"] = scorer.dockq_ave - out["dockq_wave"] = scorer.dockq_wave - out["dockq_ave_full"] = scorer.dockq_ave_full - out["dockq_wave_full"] = scorer.dockq_wave_full + out["dockq_ave"] = _RoundOrNone(scorer.dockq_ave) + out["dockq_wave"] = _RoundOrNone(scorer.dockq_wave) + out["dockq_ave_full"] = _RoundOrNone(scorer.dockq_ave_full) + out["dockq_wave_full"] = _RoundOrNone(scorer.dockq_wave_full) if args.rigid_scores: - out["oligo_gdtts"] = scorer.gdtts - out["oligo_gdtha"] = scorer.gdtha - out["rmsd"] = scorer.rmsd + out["oligo_gdtts"] = _RoundOrNone(scorer.gdtts) + out["oligo_gdtha"] = _RoundOrNone(scorer.gdtha) + out["rmsd"] = _RoundOrNone(scorer.rmsd) data = scorer.transform.data out["transform"] = [data[i:i + 4] for i in range(0, len(data), 4)] @@ -794,11 +810,12 @@ def _Process(model, reference, args): _InterfaceResiduesToJSONList(scorer.target_interface_residues) out["patch_qs"] = _PatchScoresToJSONList(scorer.model_interface_residues, scorer.patch_qs) + out["patch_dockq"] = _PatchScoresToJSONList(scorer.model_interface_residues, scorer.patch_dockq) if args.tm_score: - out["tm_score"] = scorer.tm_score + out["tm_score"] = _RoundOrNone(scorer.tm_score) out["usalign_mapping"] = scorer.usalign_mapping if args.dump_structures: diff --git a/modules/mol/alg/pymod/stereochemistry.py b/modules/mol/alg/pymod/stereochemistry.py index b3708648bf26a4e331f683e9fe7309196450f72c..b6aa98a58406036ede61eb3a072d5982fd0b50f7 100644 --- a/modules/mol/alg/pymod/stereochemistry.py +++ b/modules/mol/alg/pymod/stereochemistry.py @@ -365,7 +365,7 @@ class ClashInfo: self.dist = dist self.tolerated_dist = tolerated_dist - def ToJSON(self): + def ToJSON(self, decimals = 3): """ Return JSON serializable dict Atoms are represented by a string in format: @@ -373,8 +373,8 @@ class ClashInfo: """ return {"a1": _AtomToQualifiedName(self.a1), "a2": _AtomToQualifiedName(self.a2), - "dist": self.dist, - "tolerated_dist": self.tolerated_dist} + "dist": round(self.dist, decimals), + "tolerated_dist": round(self.tolerated_dist, decimals)} class BondViolationInfo: @@ -395,7 +395,7 @@ class BondViolationInfo: self.exp_length = exp_length self.std = std - def ToJSON(self): + def ToJSON(self, decimals = 3): """ Return JSON serializable dict Atoms are represented by a string in format: @@ -403,9 +403,9 @@ class BondViolationInfo: """ return {"a1": _AtomToQualifiedName(self.a1), "a2": _AtomToQualifiedName(self.a2), - "length": self.length, - "exp_length": self.exp_length, - "std": self.std} + "length": round(self.length, decimals), + "exp_length": round(self.exp_length, decimals), + "std": round(self.std, decimals)} class AngleViolationInfo: @@ -428,7 +428,7 @@ class AngleViolationInfo: self.exp_angle = exp_angle self.std = std - def ToJSON(self): + def ToJSON(self, decimals = 3): """ Return JSON serializable dict Atoms are represented by a string in format: @@ -437,9 +437,9 @@ class AngleViolationInfo: return {"a1": _AtomToQualifiedName(self.a1), "a2": _AtomToQualifiedName(self.a2), "a3": _AtomToQualifiedName(self.a3), - "angle": self.angle, - "exp_angle": self.exp_angle, - "std": self.std} + "angle": round(self.angle, decimals), + "exp_angle": round(self.exp_angle, decimals), + "std": round(self.std, decimals)} def GetClashes(ent, vdw_radii = None, tolerance = 1.5, disulfid_dist = 2.03,