diff --git a/modules/io/pymod/export_omf_io.cc b/modules/io/pymod/export_omf_io.cc
index 43355a4a908f97ae3f567daba57f5f0e739c34c5..974211d4542b97c6ecd92942fd37fa911873eafa 100644
--- a/modules/io/pymod/export_omf_io.cc
+++ b/modules/io/pymod/export_omf_io.cc
@@ -61,6 +61,7 @@ void export_omf_io() {
     .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)
diff --git a/modules/io/src/mol/omf.cc b/modules/io/src/mol/omf.cc
index 647f4f96f112831e361f7f5928519187886c0ceb..09eb7c1d7131bbb1b3bf3a01df125ef4c01ddc99 100644
--- a/modules/io/src/mol/omf.cc
+++ b/modules/io/src/mol/omf.cc
@@ -388,14 +388,14 @@ namespace{
             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 skip_ss, bool infer_pos) {
     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);
+                    round_bfactors, skip_ss, infer_pos);
       map[p->ch_name] = p;
     }
   }
@@ -404,14 +404,14 @@ namespace{
             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 skip_ss, bool infer_pos) {
     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); 
+                           round_bfactors, skip_ss, infer_pos); 
     }
   }
 
@@ -1212,7 +1212,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) const {
+                         bool round_bfactors, bool skip_ss,
+                         bool infer_pos) const {
   Dump(stream, ch_name);
   if(chain_type > std::numeric_limits<int8_t>::max()) {
     throw ost::Error("ChainType out of bounds");
@@ -1244,7 +1245,7 @@ void ChainData::ToStream(std::ostream& stream,
     DumpBFactors(stream, bfactors, round_bfactors);
   }
 
-  if(lossy) {
+  if(infer_pos) {
     geom::Vec3List positions_to_dump;
     std::vector<Real> pep_chi_angles;
     std::vector<bool> pep_oxygen_compression;
@@ -1278,15 +1279,19 @@ void ChainData::ToStream(std::ostream& stream,
             geom::Vec3 n_pos = positions[res_start_idx + res_n_atoms +
                                          n_idx_next];
             geom::Vec3 o_pos = positions[res_start_idx + o_idx];
-            ca_pos[0] = 0.1*std::round(ca_pos[0]*10);
-            ca_pos[1] = 0.1*std::round(ca_pos[1]*10);
-            ca_pos[2] = 0.1*std::round(ca_pos[2]*10);
-            c_pos[0] = 0.1*std::round(c_pos[0]*10);
-            c_pos[1] = 0.1*std::round(c_pos[1]*10);
-            c_pos[2] = 0.1*std::round(c_pos[2]*10);
-            n_pos[0] = 0.1*std::round(n_pos[0]*10);
-            n_pos[1] = 0.1*std::round(n_pos[1]*10);
-            n_pos[2] = 0.1*std::round(n_pos[2]*10);
+            if(lossy) {
+              // mimic lossy behaviour and reconstruct with reduced accuracy
+              // so we can still guarantee a hard threshold of 0.5A
+              ca_pos[0] = 0.1*std::round(ca_pos[0]*10);
+              ca_pos[1] = 0.1*std::round(ca_pos[1]*10);
+              ca_pos[2] = 0.1*std::round(ca_pos[2]*10);
+              c_pos[0] = 0.1*std::round(c_pos[0]*10);
+              c_pos[1] = 0.1*std::round(c_pos[1]*10);
+              c_pos[2] = 0.1*std::round(c_pos[2]*10);
+              n_pos[0] = 0.1*std::round(n_pos[0]*10);
+              n_pos[1] = 0.1*std::round(n_pos[1]*10);
+              n_pos[2] = 0.1*std::round(n_pos[2]*10);
+            }
             geom::Vec3 reconstructed_o_pos;
             ConstructOPos(ca_pos, c_pos, n_pos, reconstructed_o_pos);
             if(geom::Length2(reconstructed_o_pos - o_pos) <= Real(0.25)) {
@@ -1300,11 +1305,17 @@ void ChainData::ToStream(std::ostream& stream,
                                           positions.begin() + res_start_idx +
                                           res_n_atoms);
           std::vector<geom::Vec3> comp_res_pos;
-          for(auto it = res_pos.begin(); it != res_pos.end(); ++it) {
-            int x = std::round((*it)[0]*10);
-            int y = std::round((*it)[1]*10);
-            int z = std::round((*it)[2]*10);
-            comp_res_pos.push_back(geom::Vec3(0.1*x, 0.1*y, 0.1*z));
+          if(lossy) {
+            // mimic lossy behaviour and reconstruct with reduced accuracy
+            // so we can still guarantee a hard threshold of 0.5A
+            for(auto it = res_pos.begin(); it != res_pos.end(); ++it) {
+              int x = std::round((*it)[0]*10);
+              int y = std::round((*it)[1]*10);
+              int z = std::round((*it)[2]*10);
+              comp_res_pos.push_back(geom::Vec3(0.1*x, 0.1*y, 0.1*z));
+            }
+          } else {
+            comp_res_pos = res_pos;
           }
 
           std::vector<Real> angles;
@@ -1315,6 +1326,7 @@ void ChainData::ToStream(std::ostream& stream,
                                                  res_pos[it->idx_three],
                                                  res_pos[it->idx_four]));
           }
+          // angles are compressed anyways, independent if lossy or not
           std::vector<Real> comp_angles;
           for(auto it = angles.begin(); it != angles.end(); ++it) {
             int tmp = std::round((*it + M_PI)/(2*M_PI)*255);
@@ -1377,9 +1389,9 @@ void ChainData::ToStream(std::ostream& stream,
     if(!pep_rotamer_compression.empty()) {
       Dump(stream, pep_rotamer_compression);
     }
-    DumpPositions(stream, positions_to_dump, true);
+    DumpPositions(stream, positions_to_dump, lossy);
   } else {
-    DumpPositions(stream, positions, false);
+    DumpPositions(stream, positions, lossy);
   }
   DumpBonds(stream, bonds);
   DumpBondOrders(stream, bond_orders);
@@ -1391,7 +1403,7 @@ 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 round_bfactors, bool skip_ss, bool infer_pos) {
   
   Load(stream, ch_name);
   if(version >= 2) {
@@ -1415,7 +1427,7 @@ void ChainData::FromStream(std::istream& stream,
     LoadBFactors(stream, bfactors, round_bfactors);
   }
   
-  if(lossy) {
+  if(infer_pos) {
     std::vector<Real> pep_chi_angles;
     std::vector<bool> pep_oxygen_compression;
     std::vector<bool> pep_rotamer_compression;
@@ -1431,13 +1443,7 @@ void ChainData::FromStream(std::istream& stream,
       Load(stream, pep_rotamer_compression);
     }
 
-    if(!pep_oxygen_compression.empty()) {
-      flags += 2;
-    }
-    if(!pep_rotamer_compression.empty()) {
-      flags += 4;
-    }
-    LoadPositions(stream, positions, true);
+    LoadPositions(stream, positions, lossy);
 
     int n_res = res_def_indices.size();
     int n_at = 0;
@@ -1519,7 +1525,7 @@ void ChainData::FromStream(std::istream& stream,
     }
     std::swap(positions, full_positions);
   } else {
-    LoadPositions(stream, positions, false);
+    LoadPositions(stream, positions, lossy);
   }
   LoadBonds(stream, bonds);
   LoadBondOrders(stream, bond_orders);
@@ -3950,6 +3956,10 @@ OMFPtr OMF::FromEntity(const ost::mol::EntityHandle& ent,
   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.                         //
@@ -4250,7 +4260,8 @@ void OMF::ToStream(std::ostream& stream) const {
 
   Dump(stream, biounit_definitions_);
   Dump(stream, chain_data_, residue_definitions_, OptionSet(LOSSY),
-       OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS));
+       OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS),
+       OptionSet(INFER_POS));
   Dump(stream, bond_chain_names_);
   Dump(stream, bond_atoms_);
   Dump(stream, bond_orders_);
@@ -4293,7 +4304,8 @@ void OMF::FromStream(std::istream& stream) {
 
   Load(stream, biounit_definitions_);
   Load(stream, chain_data_, residue_definitions_, version_, OptionSet(LOSSY),
-       OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS));
+       OptionSet(AVG_BFACTORS), OptionSet(ROUND_BFACTORS), OptionSet(SKIP_SS),
+       OptionSet(INFER_POS));
   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 ca40ab16fd45e3e6a472d4c04082eb080820744b..c912bcec35525078d6310240f7bf12770027d539 100644
--- a/modules/io/src/mol/omf.hh
+++ b/modules/io/src/mol/omf.hh
@@ -152,12 +152,12 @@ struct ChainData {
   void ToStream(std::ostream& stream,
                 const std::vector<ResidueDefinition>& res_def,
                 bool lossy, bool avg_bfactors, bool round_bfactors,
-                bool skip_ss) const;
+                bool skip_ss, bool infer_pos) 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 round_bfactors, bool skip_ss, bool infer_pos);
 
   // chain features
   String ch_name;
@@ -200,7 +200,8 @@ class OMF {
 public:
 
   enum OMFOption {DEFAULT_PEPLIB = 1, LOSSY = 2, AVG_BFACTORS = 4,
-                  ROUND_BFACTORS = 8, SKIP_SS = 16, INFER_PEP_BONDS = 32};
+                  ROUND_BFACTORS = 8, SKIP_SS = 16, INFER_PEP_BONDS = 32,
+                  INFER_POS = 64};
 
   bool OptionSet(OMFOption opt) const {
     return (opt & options_) == opt;