diff --git a/modules/io/pymod/export_omf_io.cc b/modules/io/pymod/export_omf_io.cc index bb3e8169c1e61cff430c82fb1c42562702119568..2a19fce3f4951cfda10033e05a2f09231737dc56 100644 --- a/modules/io/pymod/export_omf_io.cc +++ b/modules/io/pymod/export_omf_io.cc @@ -56,20 +56,19 @@ void export_omf_io() { enum_<OMF::OMFOption>("OMFOption") .value("DEFAULT_PEPLIB", OMF::DEFAULT_PEPLIB) - .value("LOSSY", OMF::LOSSY) .value("AVG_BFACTORS", OMF::AVG_BFACTORS) .value("ROUND_BFACTORS", OMF::ROUND_BFACTORS) .value("SKIP_SS", OMF::SKIP_SS) .value("INFER_PEP_BONDS", OMF::INFER_PEP_BONDS) - .value("INFER_POS", OMF::INFER_POS) ; class_<OMF, OMFPtr>("OMF",no_init) - .def("FromEntity", &OMF::FromEntity, (arg("ent"), arg("options")=0)).staticmethod("FromEntity") + .def("FromEntity", &OMF::FromEntity, (arg("ent"), arg("max_error")=0.0, arg("options")=0)).staticmethod("FromEntity") .def("FromFile", &OMF::FromFile).staticmethod("FromFile") .def("FromBytes", &wrap_from_bytes).staticmethod("FromBytes") .def("ToFile", &OMF::ToFile) .def("ToBytes", &wrap_to_bytes) + .def("GetMaxError", &OMF::GetMaxError) .def("GetAU", &OMF::GetAU) .def("GetEntity", &OMF::GetEntity) .def("GetAUChain", &OMF::GetAUChain) diff --git a/modules/io/src/mol/omf.cc b/modules/io/src/mol/omf.cc index 2f559e7d580ec1d6ffdf06ae0f3b233c99b14e0f..95795a468112aa3ef1467262df2890da210d208d 100644 --- a/modules/io/src/mol/omf.cc +++ b/modules/io/src/mol/omf.cc @@ -9,6 +9,76 @@ namespace{ + const uint32_t _bit_masks[25] = { + 0, // 0000 0000 0... + 2147483648, // 1000 0000 0... + 3221225472, // 1100 0000 0... + 3758096384, // 1110 0000 0... + 4026531840, // 1111 0000 0... + 4160749568, // 1111 1000 0... + 4227858432, // 1111 1100 0... + 4261412864, // 1111 1110 0... + 4278190080, // 1111 1111 0... + 4286578688 // 1111 1111 1... + }; + + class BitStorage { + // stores arbitrary unsigned integers up to 9 bits + // no range checks performed + public: + BitStorage(): data_(2, 0), writing_bit_pos_(0), reading_bit_pos_(0) { } + + void Push(uint32_t v, int n_bits) { + int byte_pos = writing_bit_pos_ / 8; + v = v << (32 - n_bits - writing_bit_pos_ % 8); // shift the relevant bits to left + uint32_t tmp = data_[byte_pos]; + tmp = tmp << 24; // buffer content at byte_pos occupies first 8 bits + tmp = tmp | v; + data_[byte_pos] = (tmp >> 24) & 0xFF; + data_[byte_pos+1] = (tmp >> 16) & 0xFF; + writing_bit_pos_ += n_bits; + + // make sure we have one empty byte in the end + int new_byte_pos = writing_bit_pos_ / 8; + if(new_byte_pos > byte_pos) data_.push_back(0); + } + + uint32_t Read(int n_bits) { + uint32_t reading_mask = _bit_masks[n_bits]; + int right_shift = reading_bit_pos_ % 8; + reading_mask = reading_mask >> right_shift; + int byte_pos = reading_bit_pos_ / 8; + uint32_t tmp = static_cast<uint32_t>(data_[byte_pos]) << 24; + tmp = tmp | (static_cast<uint32_t>(data_[byte_pos+1]) << 16); + reading_bit_pos_ += n_bits; + return (tmp & reading_mask) >> (32 - n_bits - right_shift); + } + + void ResetRead() { + reading_bit_pos_ = 0; + } + + void Dump(std::ostream& stream) const { + stream.write(reinterpret_cast<const char*>(&writing_bit_pos_), sizeof(int)); + int n_bytes = std::ceil(static_cast<Real>(writing_bit_pos_) / 8); + stream.write(reinterpret_cast<const char*>(&data_[0]), n_bytes); + } + + static BitStorage Load(std::istream& stream) { + BitStorage storage; + stream.read(reinterpret_cast<char*>(&storage.writing_bit_pos_), sizeof(int)); + int n_bytes = std::ceil(static_cast<Real>(storage.writing_bit_pos_) / 8); + storage.data_.resize(n_bytes + 3, 0); + stream.read(reinterpret_cast<char*>(&storage.data_[0]), n_bytes); + return storage; + } + + private: + std::vector<uint8_t> data_; + int writing_bit_pos_; + int reading_bit_pos_; + }; + void ConstructOPos(const geom::Vec3& ca_pos, const geom::Vec3& c_pos, const geom::Vec3& n_next_pos, geom::Vec3& o_pos) { geom::Vec3 o_vec = geom::Normalize(geom::Normalize(c_pos - ca_pos) + @@ -76,94 +146,344 @@ namespace{ } inline Real PeptideBond() { - return 1.33; + return 1.3310; } inline Real N_CA_Bond(char olc) { - return 1.46; + switch(olc) { + case 'G': { + return 1.4556; + } + case 'A': { + return 1.4618; + } + case 'S': { + return 1.4610; + } + case 'C': { + return 1.4605; + } + case 'V': { + return 1.4614; + } + case 'I': { + return 1.4616; + } + case 'L': { + return 1.4612; + } + case 'T': { + return 1.4606; + } + case 'R': { + return 1.4614; + } + case 'K': { + return 1.4616; + } + case 'D': { + return 1.4624; + } + case 'N': { + return 1.4614; + } + case 'E': { + return 1.4615; + } + case 'Q': { + return 1.4614; + } + case 'M': { + return 1.4618; + } + case 'H': { + return 1.4612; + } + case 'P': { + return 1.4667; + } + case 'F': { + return 1.4608; + } + case 'Y': { + return 1.4609; + } + case 'W': { + return 1.4611; + } + default: { + return 1.46; + } + } } inline Real CA_C_Bond(char olc) { - return 1.52; + switch (olc) { + case 'G': { + return 1.5164; + } + case 'A': { + return 1.5255; + } + case 'S': { + return 1.5251; + } + case 'C': { + return 1.5242; + } + case 'V': { + return 1.5258; + } + case 'I': { + return 1.5259; + } + case 'L': { + return 1.5248; + } + case 'T': { + return 1.5254; + } + case 'R': { + return 1.5253; + } + case 'K': { + return 1.5255; + } + case 'D': { + return 1.5268; + } + case 'N': { + return 1.5256; + } + case 'E': { + return 1.5258; + } + case 'Q': { + return 1.5254; + } + case 'M': { + return 1.5249; + } + case 'H': { + return 1.5242; + } + case 'P': { + return 1.5255; + } + case 'F': { + return 1.5243; + } + case 'Y': { + return 1.5242; + } + case 'W': { + return 1.5243; + } + default: { + return 1.52; + } + } } inline Real CA_CB_Bond(char olc) { - return 1.52; + switch(olc) { + case 'A': { + return 1.5253; + } + case 'S': { + return 1.5288; + } + case 'C': { + return 1.5294; + } + case 'V': { + return 1.5446; + } + case 'I': { + return 1.5443; + } + case 'L': { + return 1.5310; + } + case 'T': { + return 1.5390; + } + case 'R': { + return 1.5311; + } + case 'K': { + return 1.5312; + } + case 'D': { + return 1.5320; + } + case 'N': { + return 1.5314; + } + case 'E': { + return 1.5316; + } + case 'Q': { + return 1.5308; + } + case 'M': { + return 1.5311; + } + case 'H': { + return 1.5316; + } + case 'P': { + return 1.5332; + } + case 'F': { + return 1.5332; + } + case 'Y': { + return 1.5331; + } + case 'W': { + return 1.5324; + } + default: { + return 1.53; + } + } } inline Real C_CA_CB_Angle(char olc) { - return 1.9111; + switch (olc) { + case 'A': { + return 1.9255; + } + case 'S': { + return 1.9190; + } + case 'C': { + return 1.9205; + } + case 'V': { + return 1.9299; + } + case 'I': { + return 1.9318; + } + case 'L': { + return 1.9209; + } + case 'T': { + return 1.9170; + } + case 'R': { + return 1.9229; + } + case 'K': { + return 1.9227; + } + case 'D': { + return 1.9247; + } + case 'N': { + return 1.9278; + } + case 'E': { + return 1.9236; + } + case 'Q': { + return 1.9230; + } + case 'M': { + return 1.9215; + } + case 'H': { + return 1.9246; + } + case 'P': { + return 1.9356; + } + case 'F': { + return 1.9236; + } + case 'Y': { + return 1.9225; + } + case 'W': { + return 1.9230; + } + default: { + return 1.92; + } + } } inline Real CA_C_N_Angle(char olc) { - return 2.0358; + return 2.0380; } inline Real C_N_CA_Angle(char olc) { - return 2.1185; + return 2.1200; } inline Real N_CA_C_Angle(char olc) { switch(olc) { case 'G': { - return 1.9354; + return 1.9747; } case 'A': { - return 1.9385; + return 1.9374; } case 'S': { - return 1.9422; + return 1.9401; } case 'C': { - return 1.9353; + return 1.9338; } case 'V': { - return 1.9158; + return 1.9140; } case 'I': { - return 1.9150; + return 1.9139; } case 'L': { - return 1.9350; + return 1.9339; } case 'T': { - return 1.9321; + return 1.9314; } case 'R': { - return 1.9370; + return 1.9359; } case 'K': { - return 1.9387; + return 1.9374; } case 'D': { - return 1.9378; + return 1.9364; } case 'N': { - return 1.9460; + return 1.9434; } case 'E': { - return 1.9403; + return 1.9389; } case 'Q': { - return 1.9388; + return 1.9375; } case 'M': { - return 1.9363; + return 1.9350; } case 'H': { - return 1.9388; + return 1.9374; } case 'P': { - return 1.9679; + return 1.9665; } case 'F': { - return 1.9330; + return 1.9323; } case 'Y': { - return 1.9361; + return 1.9341; } case 'W': { - return 1.9354; + return 1.9348; } default: { return 1.94; @@ -175,61 +495,61 @@ namespace{ inline Real N_C_CA_CB_DiAngle(char olc) { switch(olc) { case 'A': { - return 2.1413; + return 2.1423; } case 'S': { - return 2.1409; + return 2.1428; } case 'C': { - return 2.1381; + return 2.1409; } case 'V': { - return 2.1509; + return 2.1533; } case 'I': { - return 2.1509; + return 2.1519; } case 'L': { - return 2.1379; + return 2.1377; } case 'T': { - return 2.1484; + return 2.1496; } case 'R': { - return 2.1426; + return 2.1433; } case 'K': { - return 2.1426; + return 2.1432; } case 'D': { - return 2.1436; + return 2.1449; } case 'N': { - return 2.1507; + return 2.1526; } case 'E': { - return 2.1445; + return 2.1452; } case 'Q': { - return 2.1435; + return 2.1442; } case 'M': { - return 2.1411; + return 2.1419; } case 'H': { - return 2.1410; + return 2.1437; } case 'P': { - return 2.0123; + return 2.0121; } case 'F': { - return 2.1399; + return 2.1426; } case 'Y': { - return 2.1398; + return 2.1423; } case 'W': { - return 2.1400; + return 2.1420; } default: { return 2.14; @@ -281,7 +601,7 @@ namespace{ int res_start_idx, std::vector<std::set<int> >& skip_indices, std::vector<geom::Vec3>& positions, - std::vector<uint8_t>& data) { + BitStorage& data) { // extracts data required to reconstruct positions // if max reconstruction error is below specified threshold, @@ -344,7 +664,7 @@ namespace{ ref_positions[c_two_idx]); Real a_c_two = geom::Angle(positions[ca_three_idx] - positions[ca_two_idx], ref_positions[c_two_idx] - positions[ca_two_idx]); - uint8_t int_da_c_two = round((da_c_two + M_PI)/(2*M_PI)*255); + uint32_t int_da_c_two = round((da_c_two + M_PI)/(2*M_PI)*255); uint8_t int_a_c_two = round((a_c_two)/(M_PI)*255); geom::Vec3 reconstructed_c_two; ConstructAtomPos(positions[ca_one_idx], positions[ca_three_idx], @@ -363,7 +683,7 @@ namespace{ ref_positions[n_two_idx]); Real a_n_two = geom::Angle(positions[ca_three_idx] - positions[ca_two_idx], ref_positions[n_two_idx] - positions[ca_two_idx]); - uint8_t int_da_n_two = round((da_n_two + M_PI)/(2*M_PI)*255); + uint16_t int_da_n_two = round((da_n_two + M_PI)/(2*M_PI)*255); uint8_t int_a_n_two = round((a_n_two)/(M_PI)*255); geom::Vec3 reconstructed_n_two; ConstructAtomPos(positions[ca_one_idx], positions[ca_three_idx], @@ -382,7 +702,7 @@ namespace{ ref_positions[n_three_idx]); Real a_n_three = geom::Angle(positions[ca_two_idx] - reconstructed_c_two, ref_positions[n_three_idx] - reconstructed_c_two); - uint8_t int_da_n_three = round((da_n_three + M_PI)/(2*M_PI)*255); + uint16_t int_da_n_three = round((da_n_three + M_PI)/(2*M_PI)*255); // store angle as diff to ideal angle Real diff = a_n_three-CA_C_N_Angle(def_two.olc); // quantization by 0.5 degrees => 0.0087 in radians @@ -408,7 +728,7 @@ namespace{ ref_positions[c_three_idx]); Real a_c_three = geom::Angle(reconstructed_n_three - positions[ca_three_idx], ref_positions[c_three_idx] - positions[ca_three_idx]); - uint8_t int_da_c_three = round((da_c_three + M_PI)/(2*M_PI)*255); + uint16_t int_da_c_three = round((da_c_three + M_PI)/(2*M_PI)*255); // store angle as diff to ideal angle derived from N_CA_C_Angle function diff = a_c_three-N_CA_C_Angle(def_three.olc); // quantization by 0.5 degrees => 0.0087 in radians @@ -434,7 +754,7 @@ namespace{ ref_positions[c_one_idx]); Real a_c_one = geom::Angle(positions[ca_two_idx] - reconstructed_n_two, ref_positions[c_one_idx] - reconstructed_n_two); - uint8_t int_da_c_one = round((da_c_one + M_PI)/(2*M_PI)*255); + uint16_t int_da_c_one = round((da_c_one + M_PI)/(2*M_PI)*255); // store angle as diff to ideal peptide angle diff = a_c_one-C_N_CA_Angle(def_two.olc); // quantization by 0.5 degrees => 0.0087 in radians @@ -460,7 +780,7 @@ namespace{ ref_positions[n_one_idx]); Real a_n_one = geom::Angle(reconstructed_c_one - positions[ca_one_idx], ref_positions[n_one_idx] - positions[ca_one_idx]); - uint8_t int_da_n_one = round((da_n_one + M_PI)/(2*M_PI)*255); + uint16_t int_da_n_one = round((da_n_one + M_PI)/(2*M_PI)*255); // store angle as diff to ideal angle derived from N_CA_C_Angle function diff = a_n_one-N_CA_C_Angle(def_one.olc); // quantization by 0.5 degrees => 0.0087 in radians @@ -510,7 +830,7 @@ namespace{ max_error = std::max(max_error, geom::Distance(reconstructed_cb_one, ref_positions[cb_one_idx])); cb_data.push_back(int_a_cb); - cb_data.back() += (int_da_cb << 4); + cb_data.push_back(int_da_cb); } if(cb_two_idx != -1) { @@ -539,7 +859,7 @@ namespace{ max_error = std::max(max_error, geom::Distance(reconstructed_cb_two, ref_positions[cb_two_idx])); cb_data.push_back(int_a_cb); - cb_data.back() += (int_da_cb << 4); + cb_data.push_back(int_da_cb); } if(cb_three_idx != -1) { @@ -568,7 +888,7 @@ namespace{ max_error = std::max(max_error, geom::Distance(reconstructed_cb_three, ref_positions[cb_three_idx])); cb_data.push_back(int_a_cb); - cb_data.back() += (int_da_cb << 4); + cb_data.push_back(int_da_cb); } if(max_error < error_thresh) { @@ -594,25 +914,28 @@ namespace{ FillInferredTriPeptideIndices(def_one, def_two, def_three, res_idx, skip_indices); - // push back dihedrals to data - data.push_back(int_da_c_two); - data.push_back(int_da_n_two); - data.push_back(int_da_n_three); - data.push_back(int_da_c_three); - data.push_back(int_da_c_one); - data.push_back(int_da_n_one); - - // push back angles to data - data.push_back(int_a_c_two); - data.push_back(int_a_n_two); - - // angle diffs have some bit shifting magic - data.push_back(int_a_n_three + (int_a_c_three << 4)); - data.push_back(int_a_c_one + (int_a_n_one << 4)); - - // add cb data - data.insert(data.end(), cb_data.begin(), cb_data.end()); - + // push dihedrals to data + data.Push(int_da_c_two, 8); + data.Push(int_da_n_two, 8); + data.Push(int_da_n_three, 8); + data.Push(int_da_c_three, 8); + data.Push(int_da_c_one, 8); + data.Push(int_da_n_one, 8); + + // push angles to data + data.Push(int_a_c_two, 8); + data.Push(int_a_n_two, 8); + + // push angle diffs to data + data.Push(int_a_n_three, 4); + data.Push(int_a_c_three, 4); + data.Push(int_a_c_one, 4); + data.Push(int_a_n_one, 4); + + // push cb data + for(auto it = cb_data.begin(); it != cb_data.end(); ++it) { + data.Push(*it, 4); + } return true; } return false; @@ -623,44 +946,82 @@ namespace{ int res_idx, int res_start_idx, std::vector<std::set<int> >& skip_indices, std::vector<geom::Vec3>& positions, - std::vector<uint8_t>& chi_angles) { + BitStorage& data) { + + const std::vector<ost::io::SidechainAtomRule>& at_rules = + def.GetSidechainAtomRules(); int res_n_atoms = def.anames.size(); std::vector<geom::Vec3> res_ref_positions(ref_positions.begin() + res_start_idx, ref_positions.begin() + res_start_idx + res_n_atoms); std::vector<geom::Vec3> res_positions(positions.begin() + res_start_idx, positions.begin() + res_start_idx + res_n_atoms); - std::vector<uint8_t> comp_angles; - comp_angles.reserve(def.chi_definitions.size()); - for(auto it = def.chi_definitions.begin(); it != def.chi_definitions.end(); ++it) { - Real a = geom::DihedralAngle(res_positions[it->idx_one], - res_positions[it->idx_two], - res_positions[it->idx_three], - res_ref_positions[it->idx_four]); - comp_angles.push_back(std::round((a + M_PI)/(2*M_PI)*255)); - } - const std::vector<ost::io::SidechainAtomRule>& at_rules = - def.GetSidechainAtomRules(); + // deliberately delay angle computations + // may lead to tiny corrections for second, third... angle + // for errors that were introduced for earlier ones + std::vector<uint32_t> comp_dihedrals(def.chi_definitions.size(), 0.0); + std::vector<bool> dihedral_set(def.chi_definitions.size(), false); + std::vector<uint32_t> angle_diffs; + + Real max_error = 0.0; for(auto it = at_rules.begin(); it != at_rules.end(); ++it) { + Real bond = it->bond_length; + Real angle = it->angle; Real dihedral = it->base_dihedral; - if(it->dihedral_idx != 4) { - uint8_t comp_angle = comp_angles[it->dihedral_idx]; - dihedral += static_cast<Real>(comp_angle)/255*2*M_PI-M_PI; + + int d_idx = it->dihedral_idx; + if(d_idx != 5) { + if(!dihedral_set[d_idx]) { + const ost::io::ChiDefinition& chi_def = def.chi_definitions[d_idx]; + Real a = geom::DihedralAngle(res_positions[chi_def.idx_one], + res_positions[chi_def.idx_two], + res_positions[chi_def.idx_three], + res_ref_positions[chi_def.idx_four]); + comp_dihedrals[d_idx] = std::round((a + M_PI)/(2*M_PI)*255); + + dihedral_set[d_idx] = true; + } + dihedral += static_cast<Real>(comp_dihedrals[d_idx])/255*2*M_PI-M_PI; } + + if(def.critical_sidechain_angles.find(it->sidechain_atom_idx) != + def.critical_sidechain_angles.end()) { + Real a = geom::Angle(res_ref_positions[it->sidechain_atom_idx] - + res_positions[it->anchor_idx[2]], + res_positions[it->anchor_idx[1]] - + res_positions[it->anchor_idx[2]]); + Real angle_diff = a - angle; + // quantization by 0.5 degrees => 0.0087 in radians + int int_diff = std::round(angle_diff/0.0087); + int_diff = std::min(8, std::max(-7, int_diff)) + 7; + angle_diffs.push_back(int_diff); + + angle += ((int_diff-7)*0.0087); + } + ConstructAtomPos(res_positions[it->anchor_idx[0]], res_positions[it->anchor_idx[1]], res_positions[it->anchor_idx[2]], - it->bond_length, it->angle, dihedral, + bond, angle, dihedral, res_positions[it->sidechain_atom_idx]); + + max_error = std::max(max_error, geom::Distance(res_positions[it->sidechain_atom_idx], + res_ref_positions[it->sidechain_atom_idx])); if(geom::Distance(res_positions[it->sidechain_atom_idx], res_ref_positions[it->sidechain_atom_idx]) > error_thresh) { return false; } } - chi_angles.insert(chi_angles.end(), comp_angles.begin(), - comp_angles.end()); + for(auto it = comp_dihedrals.begin(); it != comp_dihedrals.end(); ++it) { + data.Push(*it, 8); + } + + for(auto it = angle_diffs.begin(); it != angle_diffs.end(); ++it) { + data.Push(*it, 4); + } + FillInferredRotIndices(def, res_idx, skip_indices); for(auto it = at_rules.begin(); it != at_rules.end(); ++it) { positions[res_start_idx + it->sidechain_atom_idx] = @@ -673,7 +1034,7 @@ namespace{ const ost::io::ResidueDefinition& def_two, const ost::io::ResidueDefinition& def_three, int res_start_idx, - uint8_t*& data, + BitStorage& data, std::vector<geom::Vec3>& positions) { int n_one_idx = def_one.GetIdx("N"); @@ -714,24 +1075,21 @@ namespace{ cb_three_idx += (res_start_idx + def_one_size + def_two_size); } - int int_da_c_two = data[0]; - int int_da_n_two = data[1]; - int int_da_n_three = data[2]; - int int_da_c_three = data[3]; - int int_da_c_one = data[4]; - int int_da_n_one = data[5]; + int int_da_c_two = data.Read(8); + int int_da_n_two = data.Read(8); + int int_da_n_three = data.Read(8); + int int_da_c_three = data.Read(8); + int int_da_c_one = data.Read(8); + int int_da_n_one = data.Read(8); - int int_a_c_two = data[6]; - int int_a_n_two = data[7]; + int int_a_c_two = data.Read(8); + int int_a_n_two = data.Read(8); - int int_a_n_three = data[8] & 15; // 15 => 0000 1111 - int int_a_c_three = (data[8] & 240) >> 4; // 240 => 1111 0000 + int int_a_n_three = data.Read(4); + int int_a_c_three = data.Read(4); - int int_a_c_one = data[9] & 15; - int int_a_n_one = (data[9] & 240) >> 4; - - // update data ptr - data += 10; + int int_a_c_one = data.Read(4); + int int_a_n_one = data.Read(4); ConstructAtomPos(positions[ca_one_idx], positions[ca_three_idx], @@ -776,9 +1134,8 @@ namespace{ positions[n_one_idx]); if(cb_one_idx != -1) { - int int_a_cb = *data & 15; - int int_da_cb = (*data & 240) >> 4; - ++data; + int int_a_cb = data.Read(4); + int int_da_cb = data.Read(4); ConstructAtomPos(positions[n_one_idx], positions[c_one_idx], positions[ca_one_idx], CA_CB_Bond(def_one.olc), @@ -788,9 +1145,8 @@ namespace{ } if(cb_two_idx != -1) { - int int_a_cb = *data & 15; - int int_da_cb = (*data & 240) >> 4; - ++data; + int int_a_cb = data.Read(4); + int int_da_cb = data.Read(4); ConstructAtomPos(positions[n_two_idx], positions[c_two_idx], positions[ca_two_idx], CA_CB_Bond(def_two.olc), @@ -800,9 +1156,8 @@ namespace{ } if(cb_three_idx != -1) { - int int_a_cb = *data & 15; - int int_da_cb = (*data & 240) >> 4; - ++data; + int int_a_cb = data.Read(4); + int int_da_cb = data.Read(4); ConstructAtomPos(positions[n_three_idx], positions[c_three_idx], positions[ca_three_idx], CA_CB_Bond(def_three.olc), @@ -813,26 +1168,32 @@ namespace{ } void DecodePepRotamer(const ost::io::ResidueDefinition& def, - int res_start_idx, uint8_t*& data_ptr, + int res_start_idx, BitStorage& data, std::vector<geom::Vec3>& positions) { const std::vector<ost::io::SidechainAtomRule>& at_rules = def.GetSidechainAtomRules(); std::vector<Real> dihedral_angles; for(int i = 0; i < def.GetNChiAngles(); ++i) { - dihedral_angles.push_back(static_cast<Real>(*data_ptr)/255*2*M_PI-M_PI); - ++data_ptr; + uint32_t asdf = data.Read(8); + dihedral_angles.push_back(static_cast<Real>(asdf)/255*2*M_PI-M_PI); } for(auto it = at_rules.begin(); it != at_rules.end(); ++it) { Real dihedral = it->base_dihedral; - if(it->dihedral_idx != 4) { + if(it->dihedral_idx != 5) { dihedral += dihedral_angles[it->dihedral_idx]; } + Real angle = it->angle; + if(def.critical_sidechain_angles.find(it->sidechain_atom_idx) != + def.critical_sidechain_angles.end()) { + int diff = data.Read(4); + angle += ((diff-7) * 0.0087); + } ConstructAtomPos(positions[res_start_idx+it->anchor_idx[0]], positions[res_start_idx+it->anchor_idx[1]], positions[res_start_idx+it->anchor_idx[2]], - it->bond_length, it->angle, dihedral, + it->bond_length, angle, dihedral, positions[res_start_idx+it->sidechain_atom_idx]); } } @@ -1099,19 +1460,20 @@ namespace{ stream.write(&ch, sizeof(char)); } + // dump and load maps with string as key and ChainDataPtr as value void Load(std::istream& stream, std::map<String, ost::io::ChainDataPtr>& map, const std::vector<ost::io::ResidueDefinition>& res_def, - int version, bool lossy, bool avg_bfactors, bool round_bfactors, - bool skip_ss, bool infer_pos) { + int version, Real max_error, bool avg_bfactors, bool round_bfactors, + bool skip_ss) { uint32_t size; stream.read(reinterpret_cast<char*>(&size), sizeof(uint32_t)); map.clear(); for(uint i = 0; i < size; ++i) { ost::io::ChainDataPtr p(new ost::io::ChainData); - p->FromStream(stream, res_def, version, lossy, avg_bfactors, - round_bfactors, skip_ss, infer_pos); + p->FromStream(stream, res_def, version, max_error, avg_bfactors, + round_bfactors, skip_ss); map[p->ch_name] = p; } } @@ -1119,15 +1481,15 @@ namespace{ void Dump(std::ostream& stream, const std::map<String, ost::io::ChainDataPtr>& map, const std::vector<ost::io::ResidueDefinition>& res_def, - bool lossy, bool avg_bfactors, bool round_bfactors, - bool skip_ss, bool infer_pos) { + Real max_error, bool avg_bfactors, bool round_bfactors, + bool skip_ss) { uint32_t size = map.size(); stream.write(reinterpret_cast<char*>(&size), sizeof(uint32_t)); for(auto it = map.begin(); it != map.end(); ++it) { // we don't dump the key (chain name), that's an attribute of the // chain itself anyway - it->second->ToStream(stream, res_def, lossy, avg_bfactors, - round_bfactors, skip_ss, infer_pos); + it->second->ToStream(stream, res_def, max_error, avg_bfactors, + round_bfactors, skip_ss); } } @@ -1816,9 +2178,8 @@ ChainData::ChainData(const ost::mol::ChainHandle& chain, void ChainData::ToStream(std::ostream& stream, const std::vector<ResidueDefinition>& res_def, - bool lossy, bool avg_bfactors, - bool round_bfactors, bool skip_ss, - bool infer_pos) const { + Real max_error, bool avg_bfactors, + bool round_bfactors, bool skip_ss) const { Dump(stream, ch_name); if(chain_type > std::numeric_limits<int8_t>::max()) { throw ost::Error("ChainType out of bounds"); @@ -1850,13 +2211,23 @@ void ChainData::ToStream(std::ostream& stream, DumpBFactors(stream, bfactors, round_bfactors); } + // Lossy means to reduce the accuracy of atom coordinates to one decimal. + // In terms of eucledian distance, this gives a max error of 0.087. Enable + // lossy compression if we're above. + bool lossy = max_error > 0.087; + // Even when going lower, we might get some lucky shots with internal + // coordinates. However, at some point it's not worth the overhead... + bool infer_pos = max_error > 0.05; + if(infer_pos) { int n_res = res_def_indices.size(); // required info for peptide specific compression - std::vector<uint8_t> pep_chi_data; - std::vector<uint8_t> pep_bb_data; + BitStorage inference_data; + bool inferred_pep_rotamer = false; + bool inferred_pep_bb = false; + bool inferred_pep_o = false; std::vector<bool> pep_rotamer_compression; std::vector<bool> pep_bb_compression; std::vector<bool> pep_o_compression; @@ -1899,17 +2270,18 @@ void ChainData::ToStream(std::ostream& stream, pep_bb_compression.push_back(EncodeTriPeptide(res_def_one, res_def_two, res_def_three, - 0.5, positions, + max_error, positions, res_idx, res_start_idx, skip_indices, comp_positions, - pep_bb_data)); + inference_data)); if(pep_bb_compression.back()) { res_idx += 3; res_start_idx += res_def_one.anames.size(); res_start_idx += res_def_two.anames.size(); res_start_idx += res_def_three.anames.size(); + inferred_pep_bb = true; } else { ++res_idx; res_start_idx += res_def_one.anames.size(); @@ -1927,13 +2299,17 @@ void ChainData::ToStream(std::ostream& stream, for(res_idx = 0; res_idx < n_res; ++res_idx) { const ResidueDefinition& def = res_def[res_def_indices[res_idx]]; if(def.chem_type == 'A' && !def.GetRotamericAtoms().empty()) { - pep_rotamer_compression.push_back(EncodePepRotamer(def, 0.5, + pep_rotamer_compression.push_back(EncodePepRotamer(def, max_error, positions, res_idx, res_start_idx, skip_indices, comp_positions, - pep_chi_data)); + inference_data)); + if(pep_rotamer_compression.back()) { + inferred_pep_rotamer = true; + } + } res_start_idx += def.anames.size(); } @@ -1958,10 +2334,12 @@ void ChainData::ToStream(std::ostream& stream, comp_positions[res_start_idx + c_idx], comp_positions[res_start_idx + n_atoms + n_next_idx], reconstructed_o); - if(geom::Distance(positions[res_start_idx + o_idx], - reconstructed_o) < 0.5) { + Real error = geom::Distance(positions[res_start_idx + o_idx], + reconstructed_o); + if(error < max_error) { pep_o_compression.back() = true; skip_indices[res_idx].insert(o_idx); + inferred_pep_o = true; } } } @@ -1970,28 +2348,29 @@ void ChainData::ToStream(std::ostream& stream, } // done peptide compression int8_t flags = 0; - if(!pep_chi_data.empty()) { + if(inferred_pep_rotamer) { flags += 1; } - if(!pep_bb_data.empty()) { + if(inferred_pep_bb) { flags += 2; } - if(!pep_o_compression.empty()) { + if(inferred_pep_o) { flags += 4; } stream.write(reinterpret_cast<char*>(&flags), sizeof(uint8_t)); - if(!pep_chi_data.empty()) { - DumpIntVec(stream, pep_chi_data); + if(inferred_pep_rotamer) { Dump(stream, pep_rotamer_compression); } - if(!pep_bb_data.empty()) { - DumpIntVec(stream, pep_bb_data); + if(inferred_pep_bb) { Dump(stream, pep_bb_compression); } - if(!pep_o_compression.empty()) { + if(inferred_pep_o) { Dump(stream, pep_o_compression); } + if(inferred_pep_rotamer || inferred_pep_bb) { + inference_data.Dump(stream); + } // construct vector containing all positions that cannot be inferred geom::Vec3List positions_to_dump; @@ -2027,8 +2406,8 @@ void ChainData::ToStream(std::ostream& stream, void ChainData::FromStream(std::istream& stream, const std::vector<ResidueDefinition>& res_def, - int version, bool lossy, bool avg_bfactors, - bool round_bfactors, bool skip_ss, bool infer_pos) { + int version, Real max_error, bool avg_bfactors, + bool round_bfactors, bool skip_ss) { Load(stream, ch_name); int8_t type; @@ -2050,6 +2429,14 @@ void ChainData::FromStream(std::istream& stream, } else { LoadBFactors(stream, bfactors, round_bfactors); } + + // Lossy means to reduce the accuracy of atom coordinates to one decimal. + // In terms of eucledian distance, this gives a max error of 0.087. Enable + // lossy compression if we're above. + bool lossy = max_error > 0.087; + // Even when going lower, we might get some lucky shots with internal + // coordinates. However, at some point it's not worth the overhead... + bool infer_pos = max_error > 0.05; if(infer_pos) { @@ -2059,8 +2446,7 @@ void ChainData::FromStream(std::istream& stream, n_at += res_def[*it].anames.size(); } - std::vector<uint8_t> pep_chi_data; - std::vector<uint8_t> pep_bb_data; + BitStorage inference_data; std::vector<bool> pep_bb_compression; std::vector<bool> pep_rotamer_compression; std::vector<bool> pep_o_compression; @@ -2068,16 +2454,17 @@ void ChainData::FromStream(std::istream& stream, int8_t flags = 0; stream.read(reinterpret_cast<char*>(&flags), sizeof(uint8_t)); if(flags & 1) { - LoadIntVec(stream, pep_chi_data); Load(stream, pep_rotamer_compression); } if(flags & 2) { - LoadIntVec(stream, pep_bb_data); Load(stream, pep_bb_compression); } if(flags & 4) { Load(stream, pep_o_compression); } + if(flags & 1 || flags & 2) { + inference_data = BitStorage::Load(stream); + } // Check which atoms are inferred from the different compression strategies std::vector<std::set<int> > inferred_indices(n_res); @@ -2154,7 +2541,6 @@ void ChainData::FromStream(std::istream& stream, int res_idx = 0; int bb_comp_idx = 0; int res_start_idx = 0; - uint8_t* data_ptr = &pep_bb_data[0]; // ptr is updated in Decode calls while(res_idx < n_res-2) { const ResidueDefinition& res_def_one = res_def[res_def_indices[res_idx]]; const ResidueDefinition& res_def_two = res_def[res_def_indices[res_idx+1]]; @@ -2163,7 +2549,7 @@ void ChainData::FromStream(std::istream& stream, res_def_three.chem_type == 'A') { if(pep_bb_compression[bb_comp_idx++]) { DecodeTriPeptide(res_def_one, res_def_two, res_def_three, - res_start_idx, data_ptr, full_positions); + res_start_idx, inference_data, full_positions); res_idx += 3; res_start_idx += res_def_one.anames.size(); res_start_idx += res_def_two.anames.size(); @@ -2179,12 +2565,11 @@ void ChainData::FromStream(std::istream& stream, if(!pep_rotamer_compression.empty()) { int res_start_idx = 0; int rot_comp_idx = 0; - uint8_t* data_ptr = &pep_chi_data[0]; // ptr is updated in Decode calls for(int res_idx = 0; res_idx < n_res; ++res_idx) { const ResidueDefinition& def = res_def[res_def_indices[res_idx]]; if(def.chem_type == 'A' && !def.GetRotamericAtoms().empty()) { if(pep_rotamer_compression[rot_comp_idx++]) { - DecodePepRotamer(def, res_start_idx, data_ptr, full_positions); + DecodePepRotamer(def, res_start_idx, inference_data, full_positions); } } res_start_idx += def.anames.size(); @@ -2366,13 +2751,15 @@ DefaultPepLib::DefaultPepLib() { res_def._AddChiDefinition(1, 2, 4, 3); res_def._AddChiDefinition(2, 4, 3, 7); res_def._AddChiDefinition(4, 3, 7, 5); - res_def._AddAtomRule(4, 6, 1, 2, 1.52, 1.9867, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 4, 1.52, 1.9511, 1, 0.0); // CD - res_def._AddAtomRule(7, 2, 4, 3, 1.46, 1.9492, 2, 0.0); // NE - res_def._AddAtomRule(5, 4, 3, 7, 1.33, 2.1780, 3, 0.0); // CZ - res_def._AddAtomRule(8, 3, 7, 5, 1.33, 2.1056, 4, 0.0); // NH1 - res_def._AddAtomRule(9, 3, 7, 5, 1.33, 2.0879, 4, M_PI); // NH2 + res_def._AddChiDefinition(3, 7, 5, 8); + res_def._AddAtomRule(4, 6, 1, 2, 1.5209, 1.9872, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 4, 1.5220, 1.9507, 1, 0.0); // CD + res_def._AddAtomRule(7, 2, 4, 3, 1.4604, 1.9486, 2, 0.0); // NE + res_def._AddAtomRule(5, 4, 3, 7, 1.3304, 2.1771, 3, 0.0); // CZ + res_def._AddAtomRule(8, 3, 7, 5, 1.3287, 2.1053, 4, 0.0); // NH1 + res_def._AddAtomRule(9, 3, 7, 5, 1.3272, 2.0893, 4, M_PI); // NH2 res_def.rotameric_atoms.insert({4, 3, 7, 5, 8, 9}); + res_def.critical_sidechain_angles.insert({3, 4, 5, 7}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2442,6 +2829,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2499,10 +2887,11 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(2); res_def._AddChiDefinition(4, 1, 2, 3); res_def._AddChiDefinition(1, 2, 3, 7); - res_def._AddAtomRule(3, 4, 1, 2, 1.52, 1.9656, 0, 0.0); // CG - res_def._AddAtomRule(7, 1, 2, 3, 1.23, 2.1092, 1, 0.0); // OD1 - res_def._AddAtomRule(5, 1, 2, 3, 1.33, 2.0330, 1, M_PI); // ND2 + res_def._AddAtomRule(3, 4, 1, 2, 1.5154, 1.9661, 0, 0.0); // CG + res_def._AddAtomRule(7, 1, 2, 3, 1.2329, 2.1098, 1, 0.0); // OD1 + res_def._AddAtomRule(5, 1, 2, 3, 1.3272, 2.0328, 1, M_PI); // ND2 res_def.rotameric_atoms.insert({3, 7, 5}); + res_def.critical_sidechain_angles.insert({3}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2557,6 +2946,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2614,10 +3004,11 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(4, 1, 2, 3); res_def._AddChiDefinition(1, 2, 3, 6); - res_def._AddAtomRule(3, 4, 1, 2, 1.52, 1.9733, 0, 0.0); // CG - res_def._AddAtomRule(6, 1, 2, 3, 1.25, 2.0808, 1, 0.0); // OD1 - res_def._AddAtomRule(7, 1, 2, 3, 1.25, 2.0633, 1, M_PI); // OD2 + res_def._AddAtomRule(3, 4, 1, 2, 1.5192, 1.9737, 0, 0.0); // CG + res_def._AddAtomRule(6, 1, 2, 3, 1.2505, 2.0798, 1, 0.0); // OD1 + res_def._AddAtomRule(7, 1, 2, 3, 1.2508, 2.0593, 1, M_PI); // OD2 res_def.rotameric_atoms.insert({3, 6, 7}); + res_def.critical_sidechain_angles.insert({3}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2672,6 +3063,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2740,6 +3132,7 @@ DefaultPepLib::DefaultPepLib() { res_def._AddAtomRule(8, 2, 4, 3, 1.24, 2.1094, 2, 0.0); // OE1 res_def._AddAtomRule(6, 2, 4, 3, 1.33, 2.0333, 2, M_PI); // NE2 res_def.rotameric_atoms.insert({4, 3, 8, 6}); + res_def.critical_sidechain_angles.insert({3, 4}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2799,6 +3192,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2862,11 +3256,12 @@ DefaultPepLib::DefaultPepLib() { res_def._AddChiDefinition(5, 1, 2, 4); res_def._AddChiDefinition(1, 2, 4, 3); res_def._AddChiDefinition(2, 4, 3, 7); - res_def._AddAtomRule(4, 5, 1, 2, 1.52, 1.9865, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 4, 1.52, 1.9776, 1, 0.0); // CD - res_def._AddAtomRule(7, 2, 4, 3, 1.25, 2.0773, 2, 0.0); // OE1 - res_def._AddAtomRule(8, 2, 4, 3, 1.25, 2.0609, 2, M_PI); // OE2 + res_def._AddAtomRule(4, 5, 1, 2, 1.5215, 1.9869, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 4, 1.5212, 1.9786, 1, 0.0); // CD + res_def._AddAtomRule(7, 2, 4, 3, 1.2522, 2.0762, 2, 0.0); // OE1 + res_def._AddAtomRule(8, 2, 4, 3, 1.2516, 2.0610, 2, M_PI); // OE2 res_def.rotameric_atoms.insert({4, 3, 7, 8}); + res_def.critical_sidechain_angles.insert({3, 4}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2926,6 +3321,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -2990,11 +3386,12 @@ DefaultPepLib::DefaultPepLib() { res_def._AddChiDefinition(1, 2, 5, 3); res_def._AddChiDefinition(2, 5, 3, 4); res_def._AddChiDefinition(5, 3, 4, 7); - res_def._AddAtomRule(5, 6, 1, 2, 1.52, 1.9867, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 5, 1.52, 1.9511, 1, 0.0); // CD - res_def._AddAtomRule(4, 2, 5, 3, 1.46, 1.9492, 2, 0.0); // CE - res_def._AddAtomRule(7, 5, 3, 4, 1.33, 2.1780, 3, 0.0); // NZ + res_def._AddAtomRule(5, 6, 1, 2, 1.5217, 1.9903, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 5, 1.5230, 1.9488, 1, 0.0); // CD + res_def._AddAtomRule(4, 2, 5, 3, 1.5215, 1.9493, 2, 0.0); // CE + res_def._AddAtomRule(7, 5, 3, 4, 1.4922, 1.9498, 3, 0.0); // NZ res_def.rotameric_atoms.insert({5, 3, 4, 7}); + res_def.critical_sidechain_angles.insert({3, 4, 5}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3054,6 +3451,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3100,7 +3498,7 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def.bond_orders.push_back(1); res_def._AddChiDefinition(3, 1, 2, 5); - res_def._AddAtomRule(5, 3, 1, 2, 1.417, 1.9334, 0, 0.0); // OG + res_def._AddAtomRule(5, 3, 1, 2, 1.4171, 1.9335, 0, 0.0); // OG res_def.rotameric_atoms.insert(5); residue_definitions.push_back(res_def); @@ -3192,7 +3590,7 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def.bond_orders.push_back(1); res_def._AddChiDefinition(3, 1, 2, 5); - res_def._AddAtomRule(5, 3, 1, 2, 1.808, 1.9865, 0, 0.0); // SG + res_def._AddAtomRule(5, 3, 1, 2, 1.8072, 1.9860, 0, 0.0); // SG res_def.rotameric_atoms.insert(5); residue_definitions.push_back(res_def); @@ -3295,10 +3693,11 @@ DefaultPepLib::DefaultPepLib() { res_def._AddChiDefinition(5, 1, 2, 4); res_def._AddChiDefinition(1, 2, 4, 7); res_def._AddChiDefinition(2, 4, 7, 3); - res_def._AddAtomRule(4, 5, 1, 2, 1.52, 1.9841, 0, 0.0); // CG - res_def._AddAtomRule(7, 1, 2, 4, 1.81, 1.9668, 1, 0.0); // SD - res_def._AddAtomRule(3, 2, 4, 7, 1.79, 1.7560, 2, 0.0); // CE + res_def._AddAtomRule(4, 5, 1, 2, 1.5199, 1.9856, 0, 0.0); // CG + res_def._AddAtomRule(7, 1, 2, 4, 1.8063, 1.9668, 1, 0.0); // SD + res_def._AddAtomRule(3, 2, 4, 7, 1.7868, 1.7561, 2, 0.0); // CE res_def.rotameric_atoms.insert({4, 7, 3}); + res_def.critical_sidechain_angles.insert({4, 7}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3352,10 +3751,11 @@ DefaultPepLib::DefaultPepLib() { res_def._AddChiDefinition(5, 1, 2, 4); res_def._AddChiDefinition(1, 2, 4, 8); res_def._AddChiDefinition(2, 4, 8, 3); - res_def._AddAtomRule(4, 5, 1, 2, 1.52, 1.9841, 0, 0.0); // CG - res_def._AddAtomRule(8, 1, 2, 4, 1.81, 1.9668, 1, 0.0); // SD - res_def._AddAtomRule(3, 2, 4, 8, 1.79, 1.7560, 2, 0.0); // CE + res_def._AddAtomRule(4, 5, 1, 2, 1.5199, 1.9856, 0, 0.0); // CG + res_def._AddAtomRule(8, 1, 2, 4, 1.8063, 1.9668, 1, 0.0); // SD + res_def._AddAtomRule(3, 2, 4, 8, 1.7868, 1.7561, 2, 0.0); // CE res_def.rotameric_atoms.insert({4, 8, 3}); + res_def.critical_sidechain_angles.insert({4, 8}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3449,16 +3849,17 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(11, 1, 2, 7); res_def._AddChiDefinition(1, 2, 7, 3); - res_def._AddAtomRule(7, 11, 1, 2, 1.50, 1.9914, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 7, 1.37, 2.2178, 1, 0.0); // CD1 - res_def._AddAtomRule(4, 1, 2, 7, 1.43, 2.2106, 1, M_PI); // CD2 - res_def._AddAtomRule(5, 3, 7, 4, 1.40, 1.8937, 4, 0.0); // CE2 - res_def._AddAtomRule(12, 2, 7, 3, 1.38, 1.8937, 4, M_PI); // NE1 => changed atoms - res_def._AddAtomRule(6, 3, 7, 4, 1.40, 2.3358, 4, M_PI); // CE3 - res_def._AddAtomRule(10, 5, 4, 6, 1.40, 2.0944, 4, 0.0); // CZ3 - res_def._AddAtomRule(8, 4, 6, 10, 1.40, 2.0944, 4, 0.0); // CH2 - res_def._AddAtomRule(9, 6, 10, 8, 1.40, 2.0944, 4, 0.0); // CZ2 + res_def._AddAtomRule(7, 11, 1, 2, 1.4986, 1.9896, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 7, 1.3674, 2.2179, 1, 0.0); // CD1 + res_def._AddAtomRule(4, 1, 2, 7, 1.4330, 2.2097, 1, M_PI); // CD2 + res_def._AddAtomRule(5, 3, 7, 4, 1.4127, 1.8710, 5, 0.0); // CE2 + res_def._AddAtomRule(12, 2, 7, 3, 1.3749, 1.9219, 5, M_PI); // NE1 + res_def._AddAtomRule(6, 3, 7, 4, 1.4001, 2.3370, 5, M_PI); // CE3 + res_def._AddAtomRule(10, 5, 4, 6, 1.3882, 2.0715, 5, 0.0); // CZ3 + res_def._AddAtomRule(8, 4, 6, 10, 1.4025, 2.1130, 5, 0.0); // CH2 + res_def._AddAtomRule(9, 6, 10, 8, 1.3714, 2.1213, 5, 0.0); // CZ2 res_def.rotameric_atoms.insert({7, 3, 4, 5, 12, 6, 10, 8, 9}); + res_def.critical_sidechain_angles.insert({3, 4, 6, 7, 8, 10}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3549,6 +3950,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3629,14 +4031,15 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(9, 1, 2, 7); res_def._AddChiDefinition(1, 2, 7, 3); - res_def._AddAtomRule(7, 9, 1, 2, 1.51, 1.9862, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 7, 1.39, 2.1115, 1, 0.0); // CD1 - res_def._AddAtomRule(4, 1, 2, 7, 1.39, 2.1087, 1, M_PI); // CD2 - res_def._AddAtomRule(5, 4, 7, 3, 1.39, 2.0944, 4, 0.0); // CE1 - res_def._AddAtomRule(6, 3, 7, 4, 1.39, 2.0944, 4, 0.0); // CE2 - res_def._AddAtomRule(8, 7, 3, 5, 1.39, 2.0944, 4, 0.0); // CZ - res_def._AddAtomRule(11, 3, 5, 8, 1.39, 2.0906, 4, M_PI); // OH + res_def._AddAtomRule(7, 9, 1, 2, 1.5104, 1.9853, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 7, 1.3910, 2.1111, 1, 0.0); // CD1 + res_def._AddAtomRule(4, 1, 2, 7, 1.3903, 2.1093, 1, M_PI); // CD2 + res_def._AddAtomRule(5, 4, 7, 3, 1.3888, 2.1144, 5, 0.0); // CE1 + res_def._AddAtomRule(6, 3, 7, 4, 1.3885, 2.1147, 5, 0.0); // CE2 + res_def._AddAtomRule(8, 7, 3, 5, 1.3814, 2.0866, 5, 0.0); // CZ + res_def._AddAtomRule(11, 3, 5, 8, 1.3771, 2.0909, 5, M_PI); // OH res_def.rotameric_atoms.insert({7, 3, 4, 5, 6, 8, 11}); + res_def.critical_sidechain_angles.insert({3, 4, 5, 7, 8}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3714,6 +4117,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -3765,8 +4169,8 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def.bond_orders.push_back(1); res_def._AddChiDefinition(4, 1, 2, 6); - res_def._AddAtomRule(6, 4, 1, 2, 1.43, 1.9056, 0, 0.0); // OG1 - res_def._AddAtomRule(3, 4, 1, 2, 1.53, 1.9396, 0, -2.0944); // CG2 + res_def._AddAtomRule(6, 4, 1, 2, 1.4323, 1.9059, 0, 0.0); // OG1 + res_def._AddAtomRule(3, 6, 1, 2, 1.5239, 1.9412, 5, -2.1068); // CG2 res_def.rotameric_atoms.insert({6, 3}); residue_definitions.push_back(res_def); @@ -3868,13 +4272,8 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def.bond_orders.push_back(1); res_def._AddChiDefinition(5, 1, 2, 3); - res_def._AddAtomRule(3, 5, 1, 2, 1.527, 1.9321, 0, 0.0); // CG1 - //res_def._AddAtomRule(4, 3, 1, 2, 1.527, 1.9268, 4, 2.1640); // CG2 - res_def._AddAtomRule(4, 3, 1, 2, 1.527, 1.9268, 4, 2.0857); // CG2 - - - - + res_def._AddAtomRule(3, 5, 1, 2, 1.5262, 1.9338, 0, 0.0); // CG1 + res_def._AddAtomRule(4, 3, 1, 2, 1.5257, 1.9294, 5, 2.1478); // CG2 res_def.rotameric_atoms.insert({3, 4}); residue_definitions.push_back(res_def); @@ -3982,11 +4381,11 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(6, 1, 2, 4); res_def._AddChiDefinition(1, 2, 4, 3); - res_def._AddAtomRule(4, 6, 1, 2, 1.527, 1.9321, 0, 0.0); // CG1 - //res_def._AddAtomRule(5, 4, 1, 2, 1.527, 1.9268, 4, -2.2696); // CG2 - res_def._AddAtomRule(5, 4, 1, 2, 1.527, 1.9268, 4, -2.1174); // CG2 - res_def._AddAtomRule(3, 1, 2, 4, 1.52, 1.9892, 1, 0.0); // CD1 + res_def._AddAtomRule(4, 6, 1, 2, 1.5331, 1.9286, 0, 0.0); // CG1 + res_def._AddAtomRule(5, 4, 1, 2, 1.5300, 1.9320, 5, -2.1534); // CG2 + res_def._AddAtomRule(3, 1, 2, 4, 1.5194, 1.9887, 1, 0.0); // CD1 res_def.rotameric_atoms.insert({4, 5, 3}); + res_def.critical_sidechain_angles.insert({4}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4041,6 +4440,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4098,13 +4498,11 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(6, 1, 2, 5); res_def._AddChiDefinition(1, 2, 5, 3); - res_def._AddAtomRule(5, 6, 1, 2, 1.53, 2.0263, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 5, 1.524, 1.9246, 1, 0.0); // CD1 - //res_def._AddAtomRule(4, 3, 2, 5, 1.525, 1.9300, 4, 2.0944); // CD2 - res_def._AddAtomRule(4, 3, 2, 5, 1.525, 1.9300, 4, 1.8895); // CD2 - - + res_def._AddAtomRule(5, 6, 1, 2, 1.5298, 2.0276, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 5, 1.5236, 1.9276, 1, 0.0); // CD1 + res_def._AddAtomRule(4, 3, 2, 5, 1.5242, 1.9316, 5, 2.1459); // CD2 res_def.rotameric_atoms.insert({5, 3, 4}); + res_def.critical_sidechain_angles.insert({5}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4159,6 +4557,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4279,9 +4678,10 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(5, 1, 2, 4); res_def._AddChiDefinition(1, 2, 4, 3); - res_def._AddAtomRule(4, 5, 1, 2, 1.49, 1.8188, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 4, 1.50, 1.8331, 1, 0.0); // CD + res_def._AddAtomRule(4, 5, 1, 2, 1.4955, 1.8224, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 4, 1.5063, 1.8391, 1, 0.0); // CD res_def.rotameric_atoms.insert({4, 3}); + res_def.critical_sidechain_angles.insert({4}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4404,12 +4804,13 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(6, 1, 2, 5); res_def._AddChiDefinition(1, 2, 5, 7); - res_def._AddAtomRule(5, 6, 1, 2, 1.49, 1.9851, 0, 0.0); // CG - res_def._AddAtomRule(7, 1, 2, 5, 1.38, 2.1441, 1, 0.0); // ND1 - res_def._AddAtomRule(3, 1, 2, 5, 1.35, 2.2796, 1, M_PI); // CD2 - res_def._AddAtomRule(4, 3, 5, 7, 1.32, 1.8937, 4, 0.0); // CE1 - res_def._AddAtomRule(8, 7, 5, 3, 1.35, 1.8937, 4, 0.0); // NE2 + res_def._AddAtomRule(5, 6, 1, 2, 1.4953, 1.9832, 0, 0.0); // CG + res_def._AddAtomRule(7, 1, 2, 5, 1.3783, 2.1399, 1, 0.0); // ND1 + res_def._AddAtomRule(3, 1, 2, 5, 1.3551, 2.2869, 1, M_PI); // CD2 + res_def._AddAtomRule(4, 3, 5, 7, 1.3234, 1.9046, 5, 0.0); // CE1 + res_def._AddAtomRule(8, 7, 5, 3, 1.3734, 1.8712, 5, 0.0); // NE2 res_def.rotameric_atoms.insert({5, 7, 3, 4, 8}); + res_def.critical_sidechain_angles.insert({3, 5, 7}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4477,6 +4878,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4552,13 +4954,14 @@ DefaultPepLib::DefaultPepLib() { res_def.bond_orders.push_back(1); res_def._AddChiDefinition(9, 1, 2, 7); res_def._AddChiDefinition(1, 2, 7, 3); - res_def._AddAtomRule(7, 9, 1, 2, 1.50, 1.9871, 0, 0.0); // CG - res_def._AddAtomRule(3, 1, 2, 7, 1.39, 2.0944, 1, 0.0); // CD1 - res_def._AddAtomRule(4, 1, 2, 7, 1.39, 2.0944, 1, M_PI); // CD2 - res_def._AddAtomRule(5, 4, 7, 3, 1.39, 2.0944, 4, 0.0); // CE1 - res_def._AddAtomRule(6, 3, 7, 4, 1.39, 2.0944, 4, 0.0); // CE2 - res_def._AddAtomRule(8, 7, 3, 5, 1.39, 2.0944, 4, 0.0); // CZ + res_def._AddAtomRule(7, 9, 1, 2, 1.5043, 1.9866, 0, 0.0); // CG + res_def._AddAtomRule(3, 1, 2, 7, 1.3883, 2.1071, 1, 0.0); // CD1 + res_def._AddAtomRule(4, 1, 2, 7, 1.3879, 2.1039, 1, M_PI); // CD2 + res_def._AddAtomRule(5, 4, 7, 3, 1.3906, 2.1079, 5, 0.0); // CE1 + res_def._AddAtomRule(6, 3, 7, 4, 1.3902, 2.1082, 5, 0.0); // CE2 + res_def._AddAtomRule(8, 7, 3, 5, 1.3832, 2.0928, 5, 0.0); // CZ res_def.rotameric_atoms.insert({7, 3, 4, 5, 6, 8}); + res_def.critical_sidechain_angles.insert({3, 4, 5, 7}); residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4631,6 +5034,7 @@ DefaultPepLib::DefaultPepLib() { res_def.chi_definitions = residue_definitions.back().chi_definitions; res_def.sidechain_atom_rules = residue_definitions.back().sidechain_atom_rules; res_def.rotameric_atoms = residue_definitions.back().rotameric_atoms; + res_def.critical_sidechain_angles = residue_definitions.back().critical_sidechain_angles; residue_definitions.push_back(res_def); res_def = ResidueDefinition(); @@ -4645,17 +5049,19 @@ DefaultPepLib::DefaultPepLib() { } OMFPtr OMF::FromEntity(const ost::mol::EntityHandle& ent, + Real max_error, uint8_t options) { + if(max_error < 0.0 || max_error > 10.0) { + throw ost::Error("max_error must be in [0.0, 10.0]"); + } + OMFPtr omf(new OMF); omf->name_ = ent.GetName(); + omf->max_error_ = 1000 * max_error; omf->options_ = options; omf->version_ = OMF_VERSION; - if(omf->OptionSet(INFER_POS) && !omf->OptionSet(DEFAULT_PEPLIB)) { - throw ost::Error("Must set DEFAULT_PEPLIB when INFER_POS is enabled"); - } - ////////////////////////////////////////////////////////////////////////////// // Generate kind of a "mini compound library"... Eeach unique residue gets // // an own entry in the residue_definitions_ vector. // @@ -4859,13 +5265,14 @@ ost::mol::EntityHandle OMF::GetAUChain(const String& name) const{ void OMF::ToStream(std::ostream& stream) const { - uint32_t magic_number = 42; - stream.write(reinterpret_cast<char*>(&magic_number), sizeof(uint32_t)); + uint16_t magic_number = 42; + stream.write(reinterpret_cast<char*>(&magic_number), sizeof(uint16_t)); // We set it to the current version... // If you loaded a structure from a previous version and you dump it again, // the version will be updated. - uint32_t version = version_; - stream.write(reinterpret_cast<char*>(&version), sizeof(uint32_t)); + uint8_t version = version_; + stream.write(reinterpret_cast<char*>(&version), sizeof(uint8_t)); + stream.write(reinterpret_cast<const char*>(&max_error_), sizeof(uint16_t)); stream.write(reinterpret_cast<const char*>(&options_), sizeof(uint8_t)); DumpName(stream, name_); @@ -4881,9 +5288,8 @@ void OMF::ToStream(std::ostream& stream) const { Dump(stream, residue_definitions_); } - Dump(stream, chain_data_, residue_definitions_, OptionSet(LOSSY), - OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS), - OptionSet(INFER_POS)); + Dump(stream, chain_data_, residue_definitions_, this->GetMaxError(), + OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS)); Dump(stream, bond_chain_names_); Dump(stream, bond_atoms_); Dump(stream, bond_orders_); @@ -4891,14 +5297,14 @@ void OMF::ToStream(std::ostream& stream) const { void OMF::FromStream(std::istream& stream) { - uint32_t magic_number; - stream.read(reinterpret_cast<char*>(&magic_number), sizeof(uint32_t)); + uint16_t magic_number; + stream.read(reinterpret_cast<char*>(&magic_number), sizeof(uint16_t)); if(magic_number != 42) { throw ost::Error("Cannot read corrupted OMF stream"); } - uint32_t version; - stream.read(reinterpret_cast<char*>(&version), sizeof(uint32_t)); + uint8_t version; + stream.read(reinterpret_cast<char*>(&version), sizeof(uint8_t)); if(version < 3) { std::stringstream ss; ss << "Old OMF versions are deprecated. Can only load versions >= 3, "; @@ -4907,6 +5313,8 @@ void OMF::FromStream(std::istream& stream) { } version_ = version; + + stream.read(reinterpret_cast<char*>(&max_error_), sizeof(uint16_t)); stream.read(reinterpret_cast<char*>(&options_), sizeof(uint8_t)); LoadName(stream, name_); @@ -4922,9 +5330,8 @@ void OMF::FromStream(std::istream& stream) { Load(stream, residue_definitions_); } - Load(stream, chain_data_, residue_definitions_, version_, OptionSet(LOSSY), - OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS), - OptionSet(INFER_POS)); + Load(stream, chain_data_, residue_definitions_, version_, this->GetMaxError(), + OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS)); Load(stream, bond_chain_names_); Load(stream, bond_atoms_); Load(stream, bond_orders_); diff --git a/modules/io/src/mol/omf.hh b/modules/io/src/mol/omf.hh index adaf4006c31b6113cba516f6a4e963c066aad40b..7fd8dd331f315bbe5a4ea0f3967c40ef1d8e6339 100644 --- a/modules/io/src/mol/omf.hh +++ b/modules/io/src/mol/omf.hh @@ -116,6 +116,7 @@ struct ResidueDefinition { std::set<int> rotameric_atoms; std::vector<ChiDefinition> chi_definitions; std::vector<SidechainAtomRule> sidechain_atom_rules; + std::set<int> critical_sidechain_angles; }; struct ChainData { @@ -132,13 +133,13 @@ struct ChainData { void ToStream(std::ostream& stream, const std::vector<ResidueDefinition>& res_def, - bool lossy, bool avg_bfactors, bool round_bfactors, - bool skip_ss, bool infer_pos) const; + Real max_error, bool avg_bfactors, bool round_bfactors, + bool skip_ss) const; void FromStream(std::istream& stream, const std::vector<ResidueDefinition>& res_def, - int version, bool lossy, bool avg_bfactors, - bool round_bfactors, bool skip_ss, bool infer_pos); + int version, Real max_error, bool avg_bfactors, + bool round_bfactors, bool skip_ss); // chain features String ch_name; @@ -180,15 +181,15 @@ class OMF { public: - enum OMFOption {DEFAULT_PEPLIB = 1, LOSSY = 2, AVG_BFACTORS = 4, - ROUND_BFACTORS = 8, SKIP_SS = 16, INFER_PEP_BONDS = 32, - INFER_POS = 64}; + enum OMFOption {DEFAULT_PEPLIB = 1, AVG_BFACTORS = 2, ROUND_BFACTORS = 4, + SKIP_SS = 8, INFER_PEP_BONDS = 16}; bool OptionSet(OMFOption opt) const { return (opt & options_) == opt; } static OMFPtr FromEntity(const ost::mol::EntityHandle& ent, + Real max_error = 0.0, uint8_t options = 0); static OMFPtr FromFile(const String& fn); @@ -211,12 +212,12 @@ public: return this->GetAUChain(name); } - ost::mol::EntityHandle GetBU(int bu_idx) const; - int GetVersion() const { return version_; } static int GetCurrentOMFVersion() { return OMF_VERSION; } + Real GetMaxError() const { return 0.001 * max_error_; } + // data access without requirement of generating a full // OpenStructure entity @@ -244,6 +245,7 @@ private: ost::mol::ChainHandle& chain) const; String name_; + uint16_t max_error_; std::vector<ResidueDefinition> residue_definitions_; std::map<String, ChainDataPtr> chain_data_; diff --git a/modules/io/tests/test_io_omf.py b/modules/io/tests/test_io_omf.py index 81c19f2e889bbd5dd9601bd69e0ae23bbbedc665..c691fd2ecce51ad22850e2b4dad931bc8f8c3583 100644 --- a/modules/io/tests/test_io_omf.py +++ b/modules/io/tests/test_io_omf.py @@ -127,7 +127,7 @@ class TestOMF(unittest.TestCase): def test_default_peplib(self): omf = io.OMF.FromEntity(self.ent) omf_bytes = omf.ToBytes() - omf_def_pep = io.OMF.FromEntity(self.ent, io.OMFOption.DEFAULT_PEPLIB) + omf_def_pep = io.OMF.FromEntity(self.ent, options = io.OMFOption.DEFAULT_PEPLIB) omf_def_pep_bytes = omf_def_pep.ToBytes() loaded_omf_def_pep = io.OMF.FromBytes(omf_def_pep_bytes) loaded_ent = loaded_omf_def_pep.GetAU() @@ -135,24 +135,10 @@ class TestOMF(unittest.TestCase): self.assertTrue(len(omf_def_pep_bytes) < len(omf_bytes)) self.assertTrue(compare_ent(self.ent, loaded_ent)) - def test_lossy(self): - omf = io.OMF.FromEntity(self.ent) - omf_bytes = omf.ToBytes() - omf_lossy = io.OMF.FromEntity(self.ent, io.OMFOption.LOSSY) - omf_lossy_bytes = omf_lossy.ToBytes() - loaded_omf_lossy = io.OMF.FromBytes(omf_lossy_bytes) - loaded_ent = loaded_omf_lossy.GetAU() - - self.assertTrue(len(omf_lossy_bytes) < len(omf_bytes)) - self.assertFalse(compare_ent(self.ent, loaded_ent)) - max_dist = math.sqrt(3*0.05*0.05) - self.assertTrue(compare_ent(self.ent, loaded_ent, - at_dist_thresh=max_dist)) - def test_avg_bfactors(self): omf = io.OMF.FromEntity(self.ent) omf_bytes = omf.ToBytes() - omf_avg_bfac = io.OMF.FromEntity(self.ent, io.OMFOption.AVG_BFACTORS) + omf_avg_bfac = io.OMF.FromEntity(self.ent, options = io.OMFOption.AVG_BFACTORS) omf_avg_bfac_bytes = omf_avg_bfac.ToBytes() loaded_omf_avg_bfac = io.OMF.FromBytes(omf_avg_bfac_bytes) loaded_ent = loaded_omf_avg_bfac.GetAU() @@ -173,7 +159,7 @@ class TestOMF(unittest.TestCase): def test_round_bfactors(self): omf = io.OMF.FromEntity(self.ent) omf_bytes = omf.ToBytes() - omf_round_bfac = io.OMF.FromEntity(self.ent, io.OMFOption.ROUND_BFACTORS) + omf_round_bfac = io.OMF.FromEntity(self.ent, options = io.OMFOption.ROUND_BFACTORS) omf_round_bfac_bytes = omf_round_bfac.ToBytes() loaded_omf_round_bfac = io.OMF.FromBytes(omf_round_bfac_bytes) loaded_ent = loaded_omf_round_bfac.GetAU() @@ -186,7 +172,7 @@ class TestOMF(unittest.TestCase): def test_skip_ss(self): omf = io.OMF.FromEntity(self.ent) omf_bytes = omf.ToBytes() - omf_skip_ss = io.OMF.FromEntity(self.ent, io.OMFOption.SKIP_SS) + omf_skip_ss = io.OMF.FromEntity(self.ent, options = io.OMFOption.SKIP_SS) omf_skip_ss_bytes = omf_skip_ss.ToBytes() loaded_omf_skip_ss = io.OMF.FromBytes(omf_skip_ss_bytes) loaded_ent = loaded_omf_skip_ss.GetAU() @@ -199,7 +185,7 @@ class TestOMF(unittest.TestCase): omf = io.OMF.FromEntity(self.ent) omf_bytes = omf.ToBytes() omf_infer_pep_bonds = io.OMF.FromEntity(self.ent, - io.OMFOption.INFER_PEP_BONDS) + options = io.OMFOption.INFER_PEP_BONDS) omf_infer_pep_bonds_bytes = omf_infer_pep_bonds.ToBytes() loaded_omf_infer_pep_bonds = io.OMF.FromBytes(omf_infer_pep_bonds_bytes) loaded_ent = loaded_omf_infer_pep_bonds.GetAU()