diff --git a/modules/io/src/mol/sdf_reader.cc b/modules/io/src/mol/sdf_reader.cc
index 72488aa989ec1bc26e690d211fb39ae25cad4b06..a64a46ec918332e4bdb27af3e6fe0c657ea80352 100644
--- a/modules/io/src/mol/sdf_reader.cc
+++ b/modules/io/src/mol/sdf_reader.cc
@@ -55,27 +55,37 @@ SDFReader::SDFReader(std::istream& instream)
   this->ClearState(boost::filesystem::path(""));
 }
 
+boost::iostreams::filtering_stream<boost::iostreams::input>& SDFReader::GetLine(
+  boost::iostreams::filtering_stream<boost::iostreams::input>& in,
+  String& line)
+  // Read next line from in and place it in line.
+  // Remove trailing \r characters.
+{
+  std::getline(in, line);
+  size_t cr_pos = line.find("\r");
+  if (cr_pos != String::npos) {
+      LOG_TRACE( "Remove CR@" << cr_pos);
+      line.erase(cr_pos);
+  }
+  return in;
+}
+
 // import data from provided stream
 void SDFReader::Import(mol::EntityHandle& ent)
 {
   String line;
   mol::XCSEditor editor=ent.EditXCS(mol::BUFFERED_EDIT);
-  while (std::getline(in_,line)) {
+  while (GetLine(in_,line)) {
     ++line_num;
 
-    // std::getline removes EOL character but may leave a DOS CR (\r) in Unix
-    size_t cr_pos = line.find("\r");
-    if (cr_pos != String::npos) {
-        LOG_TRACE( "Remove CR@" << cr_pos);
-        line.erase(cr_pos);
-    }
-
     if (line_num<=4) {
-      ParseAndAddHeader(line, line_num, ent, editor);
-    } else if (line_num<=atom_count_+4) {
-      ParseAndAddAtom(line, line_num, ent, true, editor);
-    } else if (line_num<=bond_count_+atom_count_+4) {
-      ParseAndAddBond(line, line_num, ent, editor);
+      ParseHeader(line, line_num, ent, editor);
+    } else if (version_ == "V2000" && line_num<=atom_count_+4) {
+      AddAtom(ParseAtom(line, line_num), line_num, ent, true, editor);
+    } else if (version_ == "V2000" && line_num<=bond_count_+atom_count_+4) {
+      AddBond(ParseBond(line, line_num), line_num, ent, editor);
+    } else if (version_ == "V2000" &&  boost::iequals(line.substr(0,6), "M  CHG")) {
+      AddCharge(ParseMCharge(line, line_num), line_num, ent, editor);
     } else if (boost::iequals(line.substr(0,2), "> ")) {
       // parse data items
       int data_header_start = line.find('<');
@@ -89,13 +99,15 @@ void SDFReader::Import(mol::EntityHandle& ent)
         throw IOException(str(format(msg) % line_num));
       }
       String data_value="";
-      while(std::getline(in_,line) && !boost::iequals(line, "")) {
+      while(GetLine(in_,line) && !boost::iequals(line, "")) {
         data_value.append(line);
       }
       curr_chain_.SetStringProp(data_header, data_value);
     } else if (boost::iequals(line, "$$$$")) {
       LOG_VERBOSE("MOLECULE " << curr_chain_.GetName() << " (" << chain_count_ << ") added.")
       NextMolecule();
+    } else if (version_ == "V3000") {
+      ProcessV3000Line(line, ent, editor);
     }
   }
 
@@ -117,6 +129,10 @@ void SDFReader::ClearState(const boost::filesystem::path& loc)
   atom_count_=0;
   bond_count_=0;
   line_num=0;
+  version_="";
+  v3000_bond_block_=false;
+  v3000_atom_block_=false;
+  charges_reset_=false;
 }
 
 void SDFReader::NextMolecule()
@@ -125,12 +141,16 @@ void SDFReader::NextMolecule()
   atom_count_=0;
   bond_count_=0;
   line_num=0;
+  version_="";
+  v3000_bond_block_=false;
+  v3000_atom_block_=false;
+  charges_reset_=false;
   curr_residue_ = ost::mol::ResidueHandle();
   curr_chain_ = ost::mol::ChainHandle();
 }
 
-void SDFReader::ParseAndAddHeader(const String& line, int line_num,
-                                  mol::EntityHandle& ent, mol::XCSEditor& editor)
+void SDFReader::ParseHeader(const String& line, int line_num,
+                            mol::EntityHandle& ent, mol::XCSEditor& editor)
 {
   LOG_TRACE( "line: [" << line << "]" );
   format chain_fmter("%05i_%s");
@@ -165,34 +185,41 @@ void SDFReader::ParseAndAddHeader(const String& line, int line_num,
         throw IOException(str(format(msg) % line_num % line.length()));
       }
       String version_str=line.substr(34, 5);
-      if (version_str != "V2000") {
+      if (version_str == "V2000" || version_str == "V3000") {
+        version_=version_str;
+      }
+      else {
         String msg="Unsupported SDF version: %s.";
         throw IOException(str(format(msg) % version_str));
       }
+      // Counts will be overridden in V3000
       String s_anum=line.substr(0,3);
-      try {
-        atom_count_=boost::lexical_cast<int>(boost::trim_copy(s_anum));
-      } catch(boost::bad_lexical_cast&) {
-        String msg="Bad counts line %d: Can't convert number of atoms"
-                   " '%s' to integral constant.";
-        throw IOException(str(format(msg) % line_num % s_anum));
-      }
       String s_bnum=line.substr(3,3);
-      try {
-        bond_count_=boost::lexical_cast<int>(boost::trim_copy(s_bnum));
-      } catch(boost::bad_lexical_cast&) {
-        String msg="Bad counts line %d: Can't convert number of bonds"
-                   " '%s' to integral constant.";
-        throw IOException(str(format(msg) % line_num % s_bnum));
-      }
+      SetCounts(s_anum, s_bnum, line_num);
       break;
     }
   }
 }
 
-void SDFReader::ParseAndAddAtom(const String& line, int line_num,
-                                mol::EntityHandle& ent, bool hetatm,
-                                mol::XCSEditor& editor)
+void SDFReader::SetCounts(const String& anum, const String bnum, int line_num)
+{
+  try {
+    atom_count_=boost::lexical_cast<int>(boost::trim_copy(anum));
+  } catch(boost::bad_lexical_cast&) {
+    String msg="Bad counts line %d: Can't convert number of atoms"
+               " '%s' to integral constant.";
+    throw IOException(str(format(msg) % line_num % anum));
+  }
+  try {
+    bond_count_=boost::lexical_cast<int>(boost::trim_copy(bnum));
+  } catch(boost::bad_lexical_cast&) {
+    String msg="Bad counts line %d: Can't convert number of bonds"
+               " '%s' to integral constant.";
+    throw IOException(str(format(msg) % line_num % bnum));
+  }
+}
+
+SDFReader::atom_data SDFReader::ParseAtom(const String& line, int line_num)
 {
 
   LOG_TRACE( "line: [" << line << "]" );
@@ -215,6 +242,16 @@ void SDFReader::ParseAndAddAtom(const String& line, int line_num,
   String s_ele=line.substr(31,3);
   String s_charge=line.substr(36,3);
 
+  return std::make_tuple(anum, s_posx, s_posy, s_posz, s_ele, s_charge);
+}
+
+void SDFReader::AddAtom(const atom_data& atom_tuple, int line_num, mol::EntityHandle& ent,
+                        bool hetatm, mol::XCSEditor& editor)
+{
+  int anum;
+  String s_posx, s_posy, s_posz, s_ele, s_charge;
+  tie(anum, s_posx, s_posy, s_posz, s_ele, s_charge) = atom_tuple;
+
   geom::Vec3 apos;
   try {
     apos=geom::Vec3(boost::lexical_cast<Real>(boost::trim_copy(s_posx)),
@@ -262,8 +299,7 @@ void SDFReader::ParseAndAddAtom(const String& line, int line_num,
 }
 
 
-void SDFReader::ParseAndAddBond(const String& line, int line_num,
-                                mol::EntityHandle& ent, mol::XCSEditor& editor)
+SDFReader::bond_data SDFReader::ParseBond(const String& line, int line_num)
 {
 
   LOG_TRACE( "line: [" << line << "]" );
@@ -283,10 +319,20 @@ void SDFReader::ParseAndAddBond(const String& line, int line_num,
   String s_first_name=line.substr(0,3);
   String s_second_name=line.substr(3,3);
   String s_type=line.substr(6,3);
-  String first_name, second_name;
+
+  return std::make_tuple(s_first_name, s_second_name, s_type);
+}
+
+void SDFReader::AddBond(const bond_data& bond_tuple, int line_num, mol::EntityHandle& ent,
+                        mol::XCSEditor& editor)
+{
+  String s_first_name, s_second_name, s_type;
+  tie(s_first_name, s_second_name, s_type) = bond_tuple;
+
   unsigned char type;
   mol::BondHandle bond;
 
+  String first_name, second_name;
   first_name=boost::trim_copy(s_first_name);
   second_name=boost::trim_copy(s_second_name);
 
@@ -323,4 +369,295 @@ void SDFReader::ParseAndAddBond(const String& line, int line_num,
             << s_type << ") ");
 }
 
+
+void SDFReader::ResetCharges()
+// from doc of V2000 Atom Block:
+// > Retained for compatibility with older Ctabs, M CHG and M RAD lines take
+// > precedence.
+// Therefore we must reset all charges of the residue if we encounter an
+// M  CHG line.
+{
+  LOG_DEBUG("Resetting all charges to 0.");
+  for (mol::AtomHandle & atom : curr_residue_.GetAtomList()) {
+    atom.SetCharge(0.0);
+  }
+  charges_reset_=true;
+}
+
+
+SDFReader::charge_data SDFReader::ParseMCharge(const String& line, int line_num)
+{
+
+  LOG_TRACE( "line: [" << line << "]" );
+
+  if (!charges_reset_) {
+    ResetCharges();
+  }
+
+  if(line.length()<15 || line.length()>17) {
+    // Handle the case where we have trailing space characters
+    if (line.length()>17 && boost::trim_copy(line.substr(17)) == "") {
+      LOG_DEBUG( "Ignoring trailing space" );
+    }
+    else {
+      String msg="Bad Charge line %d: Not correct number of characters on the"
+                 " line: %i (should be between 15 and 17)";
+      throw IOException(str(format(msg) % line_num % line.length()));
+    }
+  }
+
+  String atom_index=line.substr(10,3);
+  String charge=line.substr(14,3);
+
+  return std::make_tuple(atom_index, charge);
+}
+
+  void SDFReader::AddCharge(const charge_data& charge_tuple, int line_num, mol::EntityHandle& ent,
+                        mol::XCSEditor& editor)
+{
+  String s_atom_index, s_charge;
+  tie(s_atom_index, s_charge) = charge_tuple;
+
+  int atom_index;
+  Real charge;
+
+  try {
+    atom_index=boost::lexical_cast<int>(boost::trim_copy(s_atom_index));
+    if (atom_index > atom_count_) {
+      String msg="Bad charge line %d: Atom index"
+                      " '%d' greater than number of atoms in the molecule (%d).";
+      throw IOException(str(format(msg) % line_num % atom_index % atom_count_));
+    } else if (atom_index < 1) {
+      String msg="Bad charge line %d: Atom index %d < 1.";
+      throw IOException(str(format(msg) % line_num % atom_index));
+    }
+  } catch(boost::bad_lexical_cast&) {
+    String msg="Bad charge line %d: Can't convert atom index"
+                " '%s' to integral constant.";
+    throw IOException(str(format(msg) % line_num % s_atom_index));
+  }
+
+  try {
+    charge=boost::lexical_cast<Real>(boost::trim_copy(s_charge));
+  } catch(boost::bad_lexical_cast&) {
+    String msg="Bad charge line %d: Can't convert charge"
+                " '%s' to real number.";
+    throw IOException(str(format(msg) % line_num % s_charge));
+  }
+
+  curr_residue_.GetAtomList()[atom_index - 1].SetCharge(charge);
+
+  LOG_DEBUG("Setting charge of atom " << atom_index - 1 << " to " << charge);
+}
+
+SDFReader::v3000_line_tokens SDFReader::TokenizeV3000Line(const String& line,
+                                                          int line_num,
+                                                          int num_posval)
+// Read whitespace-separated tokens from a V3000 line.
+// Tokens can be separated by any amount of whitespace.
+// The function is guaranteed to return exactly num_posval positional elements,
+// or throws an error. It returns any number of keyword elements with only
+// syntax checks (ie no checks if the keywords are correct, only well-formed).
+{
+  std::istringstream v30_stream(line);
+  std::vector<String> positional;
+  std::map<String, String> keywords;
+  String token;
+  bool keywords_reached = false;
+  size_t kw_equal_pos;
+  positional.reserve(num_posval);
+
+  while (v30_stream.tellg() != -1) {
+    std::getline(v30_stream, token, ' ');
+    if (token.empty()) {
+      continue;
+    }
+    kw_equal_pos = token.find('=');
+    if (kw_equal_pos != String::npos) {
+      keywords_reached = true;
+    }
+    if (keywords_reached) {
+      // Token can contain a list in round brackets
+      // We don't use them in OST so no fancy parsing, just capture them
+      // as a string keyword
+      if (token.find('(') == kw_equal_pos + 1) {
+        // Search for the closing bracket
+        while (token.find(')') == String::npos) {
+          String next_token;
+          std::getline(v30_stream, next_token, ' ');
+          token = token + " " + next_token;
+        }
+      }
+
+      // Check if keyword is well formed
+      if (token.size() < 3 // too short
+          || kw_equal_pos == String::npos // no =
+          || kw_equal_pos == 0 // no key (starts with =)
+          || kw_equal_pos == token.size() - 1 // no value (ends with =)
+          ) {
+        String msg="Bad V3000 keyword on line %d: '%s'.";
+        throw IOException(str(format(msg) % line_num % token));
+      }
+      String key = token.substr(0, kw_equal_pos);
+      String value = token.substr(kw_equal_pos + 1);
+      keywords.insert({key, value});
+    }
+    else {
+      positional.push_back(token);
+    }
+  }
+
+  int obtained_posval = positional.size();
+  if (obtained_posval != num_posval) {
+    String msg="Bad V3000 line %d: expected %d positional values, got %d.";
+    throw IOException(str(format(msg) % line_num % num_posval %
+                          obtained_posval));
+  }
+
+  return std::make_tuple(positional, keywords);
+}
+
+String SDFReader::CleanupV3000Line(const String& line)
+// String cleanup and aggregation for V3000
+// Return a string with no "M  V30 " and not ending with -
+{
+  String v30_line = line;
+  if (v30_line.substr(0, 7) != "M  V30 ") {
+    String msg="Bad V3000 line %d: starts with '%s'.";
+    throw IOException(str(format(msg) % line_num % line.substr(0, 6)));
+  }
+
+  // Handle line continuation character -
+  while (v30_line.find("-") == v30_line.length()-1) {
+    // Read and append the next line
+    String next_line;
+    GetLine(in_,next_line);
+    ++line_num; // Update class member
+
+    // Ensure we have a valid next_line
+    if (next_line.substr(0, 7) != "M  V30 ") {
+      String msg="Bad V3000 line %d: starts with '%s'.";
+      throw IOException(str(format(msg) % line_num % next_line.substr(0, 6)));
+    }
+    // All clear, add data
+    v30_line = v30_line.erase(v30_line.find("-")) + next_line.substr(7);
+    LOG_TRACE( "V3000 line: [" << v30_line << "]" );
+  }
+
+  // Cleanup the line
+  return v30_line.substr(7); // We previously ensured it starts with M  V30
+}
+
+SDFReader::atom_data SDFReader::ParseV3000Atom(const String& line, int line_num)
+{
+  v3000_line_tokens tokens = TokenizeV3000Line(line, line_num, 6);
+  std::vector<String> posval;
+  std::map<String, String> keywords;
+  tie(posval, keywords) = tokens;
+
+  String s_anum = posval[0];
+  String atype = posval[1];
+  String posx = posval[2];
+  String posy = posval[3];
+  String posz = posval[4];
+
+  String chg;
+  try {
+    chg = keywords.at("CHG");
+  } catch(std::out_of_range&) {
+    chg = "0";
+  }
+
+  int anum;
+  try {
+    anum=boost::lexical_cast<int>(boost::trim_copy(s_anum));
+  } catch(boost::bad_lexical_cast&) {
+    String msg="Bad atom index '%s' on line %d.";
+    throw IOException(str(format(msg) % s_anum % line_num));
+  }
+
+  return std::make_tuple(anum, posx, posy, posz, atype, chg);
+}
+
+SDFReader::bond_data SDFReader::ParseV3000Bond(const String& line, int line_num)
+{
+  v3000_line_tokens tokens = TokenizeV3000Line(line, line_num, 4);
+  std::vector<String> posval;
+  tie(posval, std::ignore) = tokens;
+
+  String btype = posval[1];
+  String s_first_name = posval[2];
+  String s_second_name = posval[3];
+
+  return std::make_tuple(s_first_name, s_second_name, btype);
+}
+
+std::tuple<String, String> SDFReader::ParseV3000Counts(const String& line, int line_num)
+{
+  v3000_line_tokens tokens = TokenizeV3000Line(line, line_num, 5);
+  std::vector<String> posval;
+  tie(posval, std::ignore) = tokens;
+
+  String anum = posval[0];
+  String bnum = posval[1];
+
+  return std::make_tuple(anum, bnum);
+}
+
+void SDFReader::VerifyV3000Counts()
+{
+  int actual_atom_count = curr_residue_.GetAtomCount();
+  int actual_bond_count = curr_residue_.GetBondCount();
+  if (actual_atom_count != atom_count_) {
+      String msg="Bad counts for molecule ending on line %d: "
+                 "expected %d atoms, got %d.";
+      throw IOException(str(format(msg) % line_num % atom_count_ %
+                        actual_atom_count));
+    }
+  if (actual_bond_count != bond_count_) {
+      String msg="Bad counts for molecule ending on line %d: "
+                 "expected %d bonds, got %d.";
+      throw IOException(str(format(msg) % line_num % bond_count_ %
+                        actual_bond_count));
+    }
+}
+
+void SDFReader::ProcessV3000Line(const String& line,
+                                 mol::EntityHandle& ent,
+                                 mol::XCSEditor& editor)
+{
+  if (line.substr(0, 6) == "M  END") {
+    VerifyV3000Counts();
+    return;
+  }
+  String v30_line = CleanupV3000Line(line);
+
+  if (v30_line.substr(0, 6) == "COUNTS") {
+    String anum, bnum;
+    std::tie(anum, bnum) = ParseV3000Counts(v30_line.substr(7), line_num);
+    SetCounts(anum, bnum, line_num);
+  }
+  else if (v30_line.substr(0, 10) == "BEGIN ATOM") {
+    v3000_atom_block_=true;
+  }
+  else if (v30_line.substr(0, 8) == "END ATOM") {
+    v3000_atom_block_=false;
+  }
+  else if (v30_line.substr(0, 10) == "BEGIN BOND") {
+    v3000_bond_block_=true;
+  }
+  else if (v30_line.substr(0, 8) == "END BOND") {
+    v3000_bond_block_=false;
+  }
+  else if (v3000_atom_block_) {
+    AddAtom(ParseV3000Atom(v30_line, line_num), line_num, ent, true, editor);
+  }
+  else if (v3000_bond_block_) {
+    AddBond(ParseV3000Bond(v30_line, line_num), line_num, ent, editor);
+  }
+  else {
+    LOG_TRACE( "ignoring line: [" << v30_line << "]" );
+  }
+}
+
 }}
diff --git a/modules/io/src/mol/sdf_reader.hh b/modules/io/src/mol/sdf_reader.hh
index f786f4e5426bf5068022ef0f8ed3657c8481be2c..f704462c2c93d9467b1bab3ba933b28ab7e50f25 100644
--- a/modules/io/src/mol/sdf_reader.hh
+++ b/modules/io/src/mol/sdf_reader.hh
@@ -22,6 +22,7 @@
 #ifndef OST_IO_SDF_READER_HH
 #define OST_IO_SDF_READER_HH
 
+#include <tuple>
 #include <boost/iostreams/filtering_stream.hpp>
 #include <boost/filesystem/fstream.hpp>
 #include <ost/mol/chain_handle.hh>
@@ -30,6 +31,9 @@
 
 namespace ost { namespace io {
 
+
+
+
 class DLLEXPORT_OST_IO SDFReader {
 public:
   SDFReader(const String& filename);
@@ -41,17 +45,45 @@ public:
   void Import(mol::EntityHandle& ent);
 
 private:
+  typedef std::tuple<int, String, String, String, String, String> atom_data;
+  typedef std::tuple<String, String, String> bond_data;
+  typedef std::tuple<String, String> charge_data;
+  typedef std::tuple<std::vector<String>, std::map<String, String>> v3000_line_tokens;
+
+  boost::iostreams::filtering_stream<boost::iostreams::input>& GetLine(
+  boost::iostreams::filtering_stream<boost::iostreams::input>& in,
+    String& line);
+
   void ClearState(const boost::filesystem::path& loc);
   void NextMolecule();
 
-  void ParseAndAddHeader(const String& line, int line_num, mol::EntityHandle& ent,
+  void ParseHeader(const String& line, int line_num, mol::EntityHandle& ent,
                          mol::XCSEditor& editor);
+  void SetCounts(const String& anum, const String bnum, int line_num);
 
-  void ParseAndAddAtom(const String& line, int line_num, mol::EntityHandle& ent,
-                       bool hetatm, mol::XCSEditor& editor);
+  atom_data ParseAtom(const String& line, int line_num);
+  void AddAtom(const atom_data& atom_tuple, int line_num, mol::EntityHandle& ent,
+               bool hetatm, mol::XCSEditor& editor);
+
+  bond_data ParseBond(const String& line, int line_num);
+  void AddBond(const bond_data& bond_tuple, int line_num, mol::EntityHandle& ent,
+                       mol::XCSEditor& editor);
+
+  charge_data ParseMCharge(const String& line, int line_num);
+  void AddCharge(const charge_data& charge_tuple, int line_num, mol::EntityHandle& ent,
+                       mol::XCSEditor& editor);
+  void ResetCharges();
 
-  void ParseAndAddBond(const String& line, int line_num, mol::EntityHandle& ent,
+  // V3000 methods
+  v3000_line_tokens TokenizeV3000Line(const String& line, int line_num,
+                                      int num_posval);
+  String CleanupV3000Line(const String& line);
+  void ProcessV3000Line(const String& line, mol::EntityHandle& ent,
                        mol::XCSEditor& editor);
+  atom_data ParseV3000Atom(const String& line, int line_num);
+  bond_data ParseV3000Bond(const String& line, int line_num);
+  std::tuple<String, String> ParseV3000Counts(const String& line, int line_num);
+  void VerifyV3000Counts();
 
   String curr_chain_name_;
   mol::ResidueKey curr_res_key_;
@@ -65,6 +97,10 @@ private:
   boost::filesystem::ifstream infile_;
   std::istream& instream_;
   boost::iostreams::filtering_stream<boost::iostreams::input>  in_;
+  String version_;
+  bool v3000_atom_block_;
+  bool v3000_bond_block_;
+  bool charges_reset_;
 };
 
 }}
diff --git a/modules/io/tests/CMakeLists.txt b/modules/io/tests/CMakeLists.txt
index fbfef7413858ee6fdf249e801ca721f10aeb500d..e19fd631ec247f9ecd8fcf0ef5ff7685572281c0 100644
--- a/modules/io/tests/CMakeLists.txt
+++ b/modules/io/tests/CMakeLists.txt
@@ -8,6 +8,7 @@ set(OST_IO_UNIT_TESTS
   test_io_crd.cc
   test_io_dcd.cc
   test_io_sdf.cc
+  test_io_sdf_v3000.cc
   test_io_sequence_profile.cc
   test_pir.cc
   test_iomanager.cc
diff --git a/modules/io/tests/test_io_sdf.py b/modules/io/tests/test_io_sdf.py
index 735158fc3c38f8ed2345415ae913143f8b7d1bf1..5ca35b7fe4f576f7a16830fceb9c9f71b815b425 100644
--- a/modules/io/tests/test_io_sdf.py
+++ b/modules/io/tests/test_io_sdf.py
@@ -38,6 +38,13 @@ class TestSDF(unittest.TestCase):
       ent.FindAtom("00001_Simple Ligand", 1, "6").charge = -4
       io.EntityToSDFStr(ent)
 
+  def test_MChg(self):
+    ent = io.LoadSDF('testfiles/sdf/m_chg.sdf')
+    cl_at = ent.FindAtom("00001_Simple Ligand", 1, "6")
+    self.assertEqual(cl_at.charge, -1)
+    # Charge from atom line is ignored
+    n_at = ent.FindAtom("00001_Simple Ligand", 1, "1")
+    self.assertEqual(n_at.charge, 0)
     
 if __name__== '__main__':
   from ost import testutils
diff --git a/modules/io/tests/test_io_sdf_v3000.cc b/modules/io/tests/test_io_sdf_v3000.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e9b26a1fd2e663bf0055cf040f580c6f9a047139
--- /dev/null
+++ b/modules/io/tests/test_io_sdf_v3000.cc
@@ -0,0 +1,194 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2020 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
+using boost::unit_test_framework::test_suite;
+
+#include <ost/test_utils/compare_files.hh>
+#include <ost/mol/mol.hh>
+#include <ost/io/mol/entity_io_sdf_handler.hh>
+#include <ost/io/mol/save_entity.hh>
+#include <ost/io/io_exception.hh>
+
+using namespace ost;
+using namespace ost::io;
+
+BOOST_AUTO_TEST_SUITE( io );
+
+BOOST_AUTO_TEST_CASE(simple_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+  sdfh.Import(eh,"testfiles/sdf_v3000/simple.sdf");
+
+  // check compounds/atoms/bonds count
+  BOOST_CHECK_EQUAL(eh.GetChainCount(), 1);
+  BOOST_CHECK_EQUAL(eh.GetAtomCount(),  6);
+  BOOST_CHECK_EQUAL(eh.GetBondCount(),  6);
+  BOOST_CHECK_CLOSE(eh.GetMass(), Real(121.546997), Real(1e-4));
+
+  // check atom/bond types
+  mol::AtomHandle ah=eh.GetAtomList()[0];
+  mol::AtomHandle ah2=eh.GetAtomList()[5];
+
+  BOOST_CHECK_EQUAL(ah.GetElement(),  "N");
+  BOOST_CHECK_EQUAL(ah2.GetElement(), "CL");
+  BOOST_CHECK_CLOSE(ah.GetRadius(),  Real(1.55), Real(1e-2));
+  BOOST_CHECK_CLOSE(ah2.GetRadius(), Real(1.75), Real(1e-2));
+  BOOST_CHECK_CLOSE(ah.GetMass(),  Real(14.007), Real(1e-4));
+  BOOST_CHECK_CLOSE(ah2.GetMass(), Real(35.453), Real(1e-3));
+  BOOST_CHECK_EQUAL(ah.GetBondCount(),  3);
+  BOOST_CHECK_EQUAL(ah2.GetBondCount(), 1);
+  BOOST_CHECK_EQUAL(ah.GetCharge(),  1);
+  BOOST_CHECK_EQUAL(ah2.GetCharge(), 0);
+
+  mol::BondHandle bh=ah.GetBondList()[0];
+  BOOST_CHECK_EQUAL(bh.GetBondOrder(), 2);
+}
+
+BOOST_AUTO_TEST_CASE(multiple_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+  sdfh.Import(eh,"testfiles/sdf_v3000/multiple.sdf");
+
+  // check number of compounds
+  BOOST_CHECK_EQUAL(eh.GetChainCount(), 4);
+}
+
+BOOST_AUTO_TEST_CASE(properties_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+  sdfh.Import(eh,"testfiles/sdf_v3000/properties.sdf");
+
+  // check number of compounds
+  mol::ChainHandleList chl=eh.GetChainList();
+  int count=1;
+  for (mol::ChainHandleList::iterator i=chl.begin();i!=chl.end();++i,count++)
+  {
+    BOOST_REQUIRE(i->HasProp("prop_one"));
+    BOOST_REQUIRE(i->HasProp("prop_two"));
+    BOOST_CHECK_CLOSE(boost::lexical_cast<Real>(i->GetStringProp("prop_one")),
+                      Real(count),Real(1e-4));
+    BOOST_CHECK_CLOSE(boost::lexical_cast<Real>(i->GetStringProp("prop_two")),
+                      Real(count*(-2.2)),Real(1e-4));
+  }
+}
+
+BOOST_AUTO_TEST_CASE(read_sdf_v3000)
+{
+  const String fname("testfiles/sdf_v3000/compound.sdf");
+
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  // check import
+  sdfh.Import(eh,"testfiles/sdf_v3000/compound.sdf");
+
+  // check atoms/bonds
+  BOOST_CHECK_EQUAL(eh.GetChainCount(), 4);
+  BOOST_CHECK_EQUAL(eh.GetAtomCount(), 180);
+  BOOST_CHECK_EQUAL(eh.GetBondCount(), 188);
+
+  // check molecule name
+  mol::ChainHandle ch=eh.FindChain("00003_Test Ligand");
+  BOOST_CHECK(ch.IsValid());
+
+  // check properties
+  BOOST_CHECK(ch.HasProp("r_i_glide_rmsd"));
+  BOOST_CHECK_EQUAL(boost::lexical_cast<float>(boost::trim_copy
+                     (ch.GetStringProp("r_i_glide_rmsd"))),
+                     0.543804f);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_atomcount_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_atomcount.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_bondcount_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_bondcount.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_atomlinelength_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_atomlinelength.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_atompos_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_atompos.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_charge_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_charge.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_bondlinelength_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_bondlinelength.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_bondtype_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_bondtype.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_bondatomnumber_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_bondatomnumber.sdf"), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(wrong_keyword_error_sdf_v3000)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOSDFHandler sdfh;
+
+  BOOST_CHECK_THROW(sdfh.Import(eh,"testfiles/sdf_v3000/wrong_keyword.sdf"), IOException);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/modules/io/tests/testfiles/sdf/m_chg.sdf b/modules/io/tests/testfiles/sdf/m_chg.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..e13bae5a74e887fb15e6bd876a38ee642ec09977
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf/m_chg.sdf
@@ -0,0 +1,19 @@
+Simple Ligand
+
+ Teststructure
+  6  6  0  0  1  0            999 V2000
+    0.0000    0.0000    0.0000 N   0  3  0  0  0  0
+    1.0000    0.0000    0.0000 C   0  0  0  0  0  0
+    0.0000    1.0000    0.0000 O   0  0  0  0  0  0
+    1.0000    1.0000    0.0000 S   0  0  0  0  0  0
+    2.0000    2.0000    0.0000 C   0  0  0  0  0  0
+   -1.0000   -1.0000    0.0000 Cl  0  0  0  0  0  0
+  1  2  2  0  0  0
+  1  3  1  0  0  0
+  1  6  1  0  0  0
+  2  4  1  0  0  0
+  3  4  1  0  0  0
+  4  5  3  0  0  0
+M  CHG  1   6  -1
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/compound.sdf b/modules/io/tests/testfiles/sdf_v3000/compound.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..c1820344e37589ce52e37fade327060a95adb615
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/compound.sdf
@@ -0,0 +1,660 @@
+Test Ligand
+ OpenBabel06052308503D
+
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 45 47 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 35.9455 5.9021 22.1706 0
+M  V30 2 O 34.6074 5.5226 22.4445 0
+M  V30 3 C 33.9561 6.2475 23.4088 0
+M  V30 4 C 32.6324 6.6232 23.1367 0
+M  V30 5 C 34.5295 6.5843 24.6557 0
+M  V30 6 C 31.8762 7.3329 24.0856 0
+M  V30 7 C 33.7671 7.2733 25.6188 0
+M  V30 8 C 32.4286 7.646 25.3459 0
+M  V30 9 C 31.5951 8.3119 26.371 0
+M  V30 10 C 31.3314 7.914 27.6484 0
+M  V30 11 C 31.8735 6.7525 28.4344 0
+M  V30 12 O 32.356 5.724 27.9527 0
+M  V30 13 N 30.4351 8.7885 28.2094 0
+M  V30 14 N 31.7811 6.9129 29.7679 0
+M  V30 15 N 30.111 9.7809 27.3482 0
+M  V30 16 C 32.3829 6.0325 30.7674 0
+M  V30 17 C 30.7767 9.482 26.2306 0
+M  V30 18 C 31.3859 4.9676 31.2295 0
+M  V30 19 C 30.7144 10.3135 25.0185 0
+M  V30 20 C 31.915 10.8059 24.4681 0
+M  V30 21 C 31.8995 11.615 23.3143 0
+M  V30 22 Cl 33.3805 12.232 22.6834 0
+M  V30 23 C 30.6694 11.9024 22.6787 0
+M  V30 24 O 30.636 12.6166 21.518 0
+M  V30 25 C 29.4673 11.4261 23.2329 0
+M  V30 26 C 29.4821 10.6385 24.4075 0
+M  V30 27 O 28.2924 10.2274 24.9296 0
+M  V30 28 H 36.3421 5.2876 21.3587 0
+M  V30 29 H 35.9736 6.9432 21.8453 0
+M  V30 30 H 36.6065 5.7791 23.0307 0
+M  V30 31 H 32.1915 6.3459 22.1959 0
+M  V30 32 H 35.5405 6.2957 24.9105 0
+M  V30 33 H 30.8594 7.6089 23.8374 0
+M  V30 34 H 34.2045 7.5053 26.5811 0
+M  V30 35 H 30.0864 8.7388 29.1508 0
+M  V30 36 H 31.3698 7.7591 30.1306 0
+M  V30 37 H 33.2889 5.565 30.3864 0
+M  V30 38 H 32.6785 6.6486 31.6135 0
+M  V30 39 H 31.8211 4.339 32.0105 0
+M  V30 40 H 30.4818 5.4213 31.6393 0
+M  V30 41 H 31.1006 4.3181 30.401 0
+M  V30 42 H 32.8629 10.577 24.9439 0
+M  V30 43 H 29.7848 12.6362 21.103 0
+M  V30 44 H 28.5336 11.6723 22.7555 0
+M  V30 45 H 27.5318 10.6938 24.5843 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 1 28
+M  V30 3 1 1 29
+M  V30 4 1 1 30
+M  V30 5 1 2 3
+M  V30 6 1 3 4
+M  V30 7 2 3 5
+M  V30 8 2 4 6
+M  V30 9 1 4 31
+M  V30 10 1 5 7
+M  V30 11 1 5 32
+M  V30 12 1 6 8
+M  V30 13 1 6 33
+M  V30 14 2 7 8
+M  V30 15 1 7 34
+M  V30 16 1 8 9
+M  V30 17 2 9 10
+M  V30 18 1 9 17
+M  V30 19 1 10 11
+M  V30 20 1 10 13
+M  V30 21 2 11 12
+M  V30 22 1 11 14
+M  V30 23 1 13 15
+M  V30 24 1 13 35
+M  V30 25 1 14 16
+M  V30 26 1 14 36
+M  V30 27 2 15 17
+M  V30 28 1 16 18
+M  V30 29 1 16 37
+M  V30 30 1 16 38
+M  V30 31 1 17 19
+M  V30 32 1 18 39
+M  V30 33 1 18 40
+M  V30 34 1 18 41
+M  V30 35 1 19 20
+M  V30 36 2 19 26
+M  V30 37 2 20 21
+M  V30 38 1 20 42
+M  V30 39 1 21 22
+M  V30 40 1 21 23
+M  V30 41 1 23 24
+M  V30 42 2 23 25
+M  V30 43 1 24 43
+M  V30 44 1 25 26
+M  V30 45 1 25 44
+M  V30 46 1 26 27
+M  V30 47 1 27 45
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <i_i_glide_confnum>
+2
+
+>  <i_i_glide_lignum>
+1
+
+>  <i_i_glide_posenum>
+352
+
+>  <r_i_docking_score>
+-8.84426
+
+>  <r_i_glide_ecoul>
+-16.1644
+
+>  <r_i_glide_einternal>
+6.78671
+
+>  <r_i_glide_emodel>
+-96.9661
+
+>  <r_i_glide_energy>
+-62.2146
+
+>  <r_i_glide_erotb>
+0.517993
+
+>  <r_i_glide_esite>
+-0.0291388
+
+>  <r_i_glide_evdw>
+-46.0502
+
+>  <r_i_glide_gscore>
+-8.84426
+
+>  <r_i_glide_hbond>
+-0.960751
+
+>  <r_i_glide_ligand_efficiency>
+-0.327565
+
+>  <r_i_glide_ligand_efficiency_ln>
+-2.0588
+
+>  <r_i_glide_ligand_efficiency_sa>
+-0.982695
+
+>  <r_i_glide_lipo>
+-2.84534
+
+>  <r_i_glide_metal>
+-0
+
+>  <r_i_glide_rewards>
+-0.799851
+
+>  <r_i_glide_rmsd>
+0.6819
+
+$$$$
+Test Ligand
+ OpenBabel06052308503D
+
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 45 47 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 34.3938 4.9895 21.4537 0
+M  V30 2 O 34.9786 5.7318 22.5298 0
+M  V30 3 C 34.145 6.3862 23.4047 0
+M  V30 4 C 34.6745 6.7394 24.6654 0
+M  V30 5 C 32.7998 6.7274 23.0916 0
+M  V30 6 C 33.8742 7.4015 25.612 0
+M  V30 7 C 32.0035 7.3913 24.0448 0
+M  V30 8 C 32.5275 7.723 25.3191 0
+M  V30 9 C 31.6607 8.3431 26.3377 0
+M  V30 10 C 31.4133 7.937 27.6169 0
+M  V30 11 C 31.9782 6.7689 28.3776 0
+M  V30 12 O 32.369 5.715 27.8804 0
+M  V30 13 N 30.5206 8.8053 28.2099 0
+M  V30 14 N 32.0029 6.9625 29.7121 0
+M  V30 15 N 30.1677 9.805 27.357 0
+M  V30 16 C 32.5238 6.0208 30.6934 0
+M  V30 17 C 30.8244 9.5086 26.2225 0
+M  V30 18 C 31.3863 5.1079 31.1861 0
+M  V30 19 C 30.7465 10.3438 25.0101 0
+M  V30 20 C 31.9316 10.8558 24.4417 0
+M  V30 21 C 31.892 11.6586 23.2829 0
+M  V30 22 Cl 33.3681 12.254 22.6096 0
+M  V30 23 C 30.6518 11.9231 22.66 0
+M  V30 24 O 30.5979 12.6244 21.4907 0
+M  V30 25 C 29.4612 11.4393 23.2345 0
+M  V30 26 C 29.4978 10.6576 24.4073 0
+M  V30 27 O 28.313 10.2277 24.9428 0
+M  V30 28 H 35.1654 4.4015 20.952 0
+M  V30 29 H 33.6444 4.2945 21.836 0
+M  V30 30 H 33.93 5.6189 20.6923 0
+M  V30 31 H 35.7051 6.503 24.9029 0
+M  V30 32 H 32.3569 6.4909 22.1252 0
+M  V30 33 H 34.2923 7.6473 26.581 0
+M  V30 34 H 30.9795 7.6612 23.8114 0
+M  V30 35 H 30.1658 8.7432 29.1625 0
+M  V30 36 H 31.6728 7.8452 30.0908 0
+M  V30 37 H 33.3536 5.4297 30.2888 0
+M  V30 38 H 32.9238 6.5957 31.5354 0
+M  V30 39 H 31.7451 4.4444 31.9834 0
+M  V30 40 H 30.5677 5.7018 31.5922 0
+M  V30 41 H 31.0015 4.4903 30.3675 0
+M  V30 42 H 32.8807 10.6312 24.9124 0
+M  V30 43 H 29.7389 12.639 21.0888 0
+M  V30 44 H 28.5134 11.6612 22.7648 0
+M  V30 45 H 27.5338 10.6743 24.5952 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 1 28
+M  V30 3 1 1 29
+M  V30 4 1 1 30
+M  V30 5 1 2 3
+M  V30 6 1 3 4
+M  V30 7 2 3 5
+M  V30 8 2 4 6
+M  V30 9 1 4 31
+M  V30 10 1 5 7
+M  V30 11 1 5 32
+M  V30 12 1 6 8
+M  V30 13 1 6 33
+M  V30 14 2 7 8
+M  V30 15 1 7 34
+M  V30 16 1 8 9
+M  V30 17 2 9 10
+M  V30 18 1 9 17
+M  V30 19 1 10 11
+M  V30 20 1 10 13
+M  V30 21 2 11 12
+M  V30 22 1 11 14
+M  V30 23 1 13 15
+M  V30 24 1 13 35
+M  V30 25 1 14 16
+M  V30 26 1 14 36
+M  V30 27 2 15 17
+M  V30 28 1 16 18
+M  V30 29 1 16 37
+M  V30 30 1 16 38
+M  V30 31 1 17 19
+M  V30 32 1 18 39
+M  V30 33 1 18 40
+M  V30 34 1 18 41
+M  V30 35 1 19 20
+M  V30 36 2 19 26
+M  V30 37 2 20 21
+M  V30 38 1 20 42
+M  V30 39 1 21 22
+M  V30 40 1 21 23
+M  V30 41 1 23 24
+M  V30 42 2 23 25
+M  V30 43 1 24 43
+M  V30 44 1 25 26
+M  V30 45 1 25 44
+M  V30 46 1 26 27
+M  V30 47 1 27 45
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <i_i_glide_confnum>
+14
+
+>  <i_i_glide_lignum>
+1
+
+>  <i_i_glide_posenum>
+302
+
+>  <r_i_docking_score>
+-8.79327
+
+>  <r_i_glide_ecoul>
+-16.9687
+
+>  <r_i_glide_einternal>
+5.76514
+
+>  <r_i_glide_emodel>
+-98.4298
+
+>  <r_i_glide_energy>
+-63.3874
+
+>  <r_i_glide_erotb>
+0.517993
+
+>  <r_i_glide_esite>
+-0.00975737
+
+>  <r_i_glide_evdw>
+-46.4187
+
+>  <r_i_glide_gscore>
+-8.79327
+
+>  <r_i_glide_hbond>
+-0.966475
+
+>  <r_i_glide_ligand_efficiency>
+-0.325677
+
+>  <r_i_glide_ligand_efficiency_ln>
+-2.04693
+
+>  <r_i_glide_ligand_efficiency_sa>
+-0.97703
+
+>  <r_i_glide_lipo>
+-2.69167
+
+>  <r_i_glide_metal>
+-0
+
+>  <r_i_glide_rewards>
+-0.777126
+
+>  <r_i_glide_rmsd>
+0.605551
+
+$$$$
+Test Ligand
+ OpenBabel06052308503D
+
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 45 47 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 36.2241 5.1749 22.8554 0
+M  V30 2 O 35.0609 5.8871 22.4479 0
+M  V30 3 C 34.2768 6.4601 23.4276 0
+M  V30 4 C 34.7199 6.6807 24.7535 0
+M  V30 5 C 32.9608 6.8443 23.074 0
+M  V30 6 C 33.8637 7.2655 25.7079 0
+M  V30 7 C 32.1001 7.4207 24.0338 0
+M  V30 8 C 32.5448 7.6388 25.3572 0
+M  V30 9 C 31.6578 8.2493 26.3632 0
+M  V30 10 C 31.3829 7.8493 27.6381 0
+M  V30 11 C 31.8957 6.6637 28.4136 0
+M  V30 12 O 32.3784 5.637 27.9299 0
+M  V30 13 N 30.4903 8.7246 28.2064 0
+M  V30 14 N 31.7656 6.7961 29.7467 0
+M  V30 15 N 30.1647 9.7304 27.3526 0
+M  V30 16 C 32.1947 5.8187 30.7363 0
+M  V30 17 C 30.843 9.4334 26.233 0
+M  V30 18 C 33.6957 5.9781 31.0077 0
+M  V30 19 C 30.7874 10.2877 25.0301 0
+M  V30 20 C 31.9854 10.7833 24.4695 0
+M  V30 21 C 31.9583 11.608 23.3306 0
+M  V30 22 Cl 33.4405 12.2408 22.7079 0
+M  V30 23 C 30.7247 11.9044 22.7018 0
+M  V30 24 O 30.6845 12.6266 21.5474 0
+M  V30 25 C 29.5221 11.4297 23.2588 0
+M  V30 26 C 29.5448 10.64 24.4309 0
+M  V30 27 O 28.3508 10.232 24.9581 0
+M  V30 28 H 36.6559 4.6879 21.9802 0
+M  V30 29 H 36.9908 5.8287 23.2736 0
+M  V30 30 H 35.9784 4.409 23.5916 0
+M  V30 31 H 35.7217 6.4151 25.0626 0
+M  V30 32 H 32.6094 6.6834 22.0613 0
+M  V30 33 H 34.237 7.4405 26.7062 0
+M  V30 34 H 31.0912 7.6917 23.745 0
+M  V30 35 H 30.1426 8.6905 29.1645 0
+M  V30 36 H 31.3915 7.6554 30.1264 0
+M  V30 37 H 31.6292 6.0008 31.6531 0
+M  V30 38 H 31.9544 4.8033 30.4192 0
+M  V30 39 H 34.0395 5.2434 31.7401 0
+M  V30 40 H 34.2801 5.8472 30.0923 0
+M  V30 41 H 33.9143 6.9734 31.4067 0
+M  V30 42 H 32.9388 10.5461 24.9301 0
+M  V30 43 H 29.8267 12.6411 21.1471 0
+M  V30 44 H 28.5699 11.6759 22.8051 0
+M  V30 45 H 27.5929 10.6933 24.609 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 1 28
+M  V30 3 1 1 29
+M  V30 4 1 1 30
+M  V30 5 1 2 3
+M  V30 6 1 3 4
+M  V30 7 2 3 5
+M  V30 8 2 4 6
+M  V30 9 1 4 31
+M  V30 10 1 5 7
+M  V30 11 1 5 32
+M  V30 12 1 6 8
+M  V30 13 1 6 33
+M  V30 14 2 7 8
+M  V30 15 1 7 34
+M  V30 16 1 8 9
+M  V30 17 2 9 10
+M  V30 18 1 9 17
+M  V30 19 1 10 11
+M  V30 20 1 10 13
+M  V30 21 2 11 12
+M  V30 22 1 11 14
+M  V30 23 1 13 15
+M  V30 24 1 13 35
+M  V30 25 1 14 16
+M  V30 26 1 14 36
+M  V30 27 2 15 17
+M  V30 28 1 16 18
+M  V30 29 1 16 37
+M  V30 30 1 16 38
+M  V30 31 1 17 19
+M  V30 32 1 18 39
+M  V30 33 1 18 40
+M  V30 34 1 18 41
+M  V30 35 1 19 20
+M  V30 36 2 19 26
+M  V30 37 2 20 21
+M  V30 38 1 20 42
+M  V30 39 1 21 22
+M  V30 40 1 21 23
+M  V30 41 1 23 24
+M  V30 42 2 23 25
+M  V30 43 1 24 43
+M  V30 44 1 25 26
+M  V30 45 1 25 44
+M  V30 46 1 26 27
+M  V30 47 1 27 45
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <i_i_glide_confnum>
+1
+
+>  <i_i_glide_lignum>
+1
+
+>  <i_i_glide_posenum>
+177
+
+>  <r_i_docking_score>
+-8.70173
+
+>  <r_i_glide_ecoul>
+-15.8862
+
+>  <r_i_glide_einternal>
+1.84397
+
+>  <r_i_glide_emodel>
+-99.0481
+
+>  <r_i_glide_energy>
+-62.44
+
+>  <r_i_glide_erotb>
+0.517993
+
+>  <r_i_glide_esite>
+-0.0274759
+
+>  <r_i_glide_evdw>
+-46.5538
+
+>  <r_i_glide_gscore>
+-8.70173
+
+>  <r_i_glide_hbond>
+-0.97397
+
+>  <r_i_glide_ligand_efficiency>
+-0.322286
+
+>  <r_i_glide_ligand_efficiency_ln>
+-2.02562
+
+>  <r_i_glide_ligand_efficiency_sa>
+-0.966858
+
+>  <r_i_glide_lipo>
+-2.74283
+
+>  <r_i_glide_metal>
+-0
+
+>  <r_i_glide_rewards>
+-0.764823
+
+>  <r_i_glide_rmsd>
+0.543804
+
+$$$$
+Test Ligand
+ OpenBabel06052308503D
+
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 45 47 0 0 0
+M  V30 BEGIN ATOM
+M  V30 1 C 36.1312 5.0238 22.8745 0
+M  V30 2 O 35.3492 6.1234 22.4285 0
+M  V30 3 C 34.5144 6.6833 23.3611 0
+M  V30 4 C 33.188 6.9515 22.986 0
+M  V30 5 C 34.9381 7.0224 24.661 0
+M  V30 6 C 32.287 7.546 23.8905 0
+M  V30 7 C 34.0422 7.6076 25.572 0
+M  V30 8 C 32.7085 7.8735 25.1943 0
+M  V30 9 C 31.7655 8.4568 26.1623 0
+M  V30 10 C 31.4563 8.0176 27.4151 0
+M  V30 11 C 31.9612 6.8234 28.1735 0
+M  V30 12 O 32.4816 5.8265 27.6667 0
+M  V30 13 N 30.4991 8.8399 27.9505 0
+M  V30 14 N 31.7656 6.8973 29.5011 0
+M  V30 15 N 30.1623 9.8254 27.0921 0
+M  V30 16 C 32.179 5.9073 30.4826 0
+M  V30 17 C 30.8968 9.5864 26.0023 0
+M  V30 18 C 33.4739 6.3765 31.1528 0
+M  V30 19 C 30.8088 10.4312 24.8021 0
+M  V30 20 C 31.98 11.0176 24.2785 0
+M  V30 21 C 31.9238 11.8291 23.1331 0
+M  V30 22 Cl 33.3643 12.5911 22.5784 0
+M  V30 23 C 30.6968 12.0157 22.4634 0
+M  V30 24 O 30.6398 12.6873 21.2763 0
+M  V30 25 C 29.5186 11.4761 23.006 0
+M  V30 26 C 29.5649 10.7043 24.1795 0
+M  V30 27 O 28.3911 10.2293 24.6826 0
+M  V30 28 H 36.6829 4.6047 22.0257 0
+M  V30 29 H 36.8626 5.3082 23.636 0
+M  V30 30 H 35.4815 4.2419 23.2796 0
+M  V30 31 H 32.8514 6.6935 21.9933 0
+M  V30 32 H 35.957 6.8606 24.9671 0
+M  V30 33 H 31.2689 7.7361 23.5858 0
+M  V30 34 H 34.3918 7.8724 26.559 0
+M  V30 35 H 30.065 8.7441 28.8594 0
+M  V30 36 H 31.3489 7.7378 29.8826 0
+M  V30 37 H 31.3881 5.8177 31.2263 0
+M  V30 38 H 32.3154 4.9187 30.0437 0
+M  V30 39 H 33.8094 5.6628 31.9076 0
+M  V30 40 H 34.2829 6.5014 30.4282 0
+M  V30 41 H 33.3311 7.3365 31.6549 0
+M  V30 42 H 32.9245 10.8652 24.7777 0
+M  V30 43 H 29.7851 12.6657 20.8657 0
+M  V30 44 H 28.5664 11.6345 22.5199 0
+M  V30 45 H 27.6152 10.7061 24.3768 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 1 1 2
+M  V30 2 1 1 28
+M  V30 3 1 1 29
+M  V30 4 1 1 30
+M  V30 5 1 2 3
+M  V30 6 1 3 4
+M  V30 7 2 3 5
+M  V30 8 2 4 6
+M  V30 9 1 4 31
+M  V30 10 1 5 7
+M  V30 11 1 5 32
+M  V30 12 1 6 8
+M  V30 13 1 6 33
+M  V30 14 2 7 8
+M  V30 15 1 7 34
+M  V30 16 1 8 9
+M  V30 17 2 9 10
+M  V30 18 1 9 17
+M  V30 19 1 10 11
+M  V30 20 1 10 13
+M  V30 21 2 11 12
+M  V30 22 1 11 14
+M  V30 23 1 13 15
+M  V30 24 1 13 35
+M  V30 25 1 14 16
+M  V30 26 1 14 36
+M  V30 27 2 15 17
+M  V30 28 1 16 18
+M  V30 29 1 16 37
+M  V30 30 1 16 38
+M  V30 31 1 17 19
+M  V30 32 1 18 39
+M  V30 33 1 18 40
+M  V30 34 1 18 41
+M  V30 35 1 19 20
+M  V30 36 2 19 26
+M  V30 37 2 20 21
+M  V30 38 1 20 42
+M  V30 39 1 21 22
+M  V30 40 1 21 23
+M  V30 41 1 23 24
+M  V30 42 2 23 25
+M  V30 43 1 24 43
+M  V30 44 1 25 26
+M  V30 45 1 25 44
+M  V30 46 1 26 27
+M  V30 47 1 27 45
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <i_i_glide_confnum>
+9
+
+>  <i_i_glide_lignum>
+1
+
+>  <i_i_glide_posenum>
+294
+
+>  <r_i_docking_score>
+-8.69162
+
+>  <r_i_glide_ecoul>
+-14.7519
+
+>  <r_i_glide_einternal>
+5.89466
+
+>  <r_i_glide_emodel>
+-97.7232
+
+>  <r_i_glide_energy>
+-63.1839
+
+>  <r_i_glide_erotb>
+0.517993
+
+>  <r_i_glide_esite>
+-0.0119369
+
+>  <r_i_glide_evdw>
+-48.432
+
+>  <r_i_glide_gscore>
+-8.69162
+
+>  <r_i_glide_hbond>
+-0.870172
+
+>  <r_i_glide_ligand_efficiency>
+-0.321912
+
+>  <r_i_glide_ligand_efficiency_ln>
+-2.02327
+
+>  <r_i_glide_ligand_efficiency_sa>
+-0.965735
+
+>  <r_i_glide_lipo>
+-2.92829
+
+>  <r_i_glide_metal>
+-0
+
+>  <r_i_glide_rewards>
+-0.764823
+
+>  <r_i_glide_rmsd>
+0.463026
+
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/multiple.sdf b/modules/io/tests/testfiles/sdf_v3000/multiple.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..339ef0a58f64cb51c493c6296004cda33f1cc37a
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/multiple.sdf
@@ -0,0 +1,100 @@
+Simple Ligand 1
+ OpenBabel06052308472D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
+Simple Ligand 2
+ OpenBabel06052308472D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
+Simple Ligand 3
+ OpenBabel06052308472D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
+Simple Ligand 4
+ OpenBabel06052308472D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/properties.sdf b/modules/io/tests/testfiles/sdf_v3000/properties.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..2f6b6ed0be990baba2708a73a96619264944fcf3
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/properties.sdf
@@ -0,0 +1,62 @@
+Simple Ligand 1
+ OpenBabel06052308492D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <prop_one>
+1
+
+>  <prop_two>
+-2.2
+
+$$$$
+Simple Ligand 2
+ OpenBabel06052308492D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C 2 2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1 2
+M  V30 2 1 1 3
+M  V30 3 1 1 6
+M  V30 4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+>  <prop_one>
+2
+
+>  <prop_two>
+-4.4
+
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/simple.sdf b/modules/io/tests/testfiles/sdf_v3000/simple.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..1d4946404ec77c7ab100a48d1bcd0b17f94744ac
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/simple.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 Rgroups=(2 1 2) CHG=-
+M  V30 3 
+M  V30 2 C 1 0 0 0 
+M  V30 3 O 0 1 0 0 
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/test.py b/modules/io/tests/testfiles/sdf_v3000/test.py
new file mode 100644
index 0000000000000000000000000000000000000000..85fa247dbe95dc5f9bd6aaadbd117f4dc07bb7da
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/test.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+import ost.io
+ent = ost.io.LoadSDF("simple.sdf")
+
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_atomcount.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_atomcount.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..6914bb7be339dd859f1b6dda565a4732ddf69b57
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_atomcount.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 7 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_atomlinelength.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_atomlinelength.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..db284bab1c22ed2683e5a4f485cd114ca6df6a77
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_atomlinelength.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0  
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_bondatomnumber.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_bondatomnumber.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..bd9115bfbae2ca0e49949325a6d6ebb3f6414b23
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_bondatomnumber.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 8
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_bondcount.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_bondcount.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..384d29ff4717fb5949ffe2835ad39c077c328afe
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_bondcount.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 7 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_bondlinelength.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_bondlinelength.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..4b994b3f1accd915bbd822087d2c286487de5d0c
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_bondlinelength.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1  
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_bondtype.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_bondtype.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..da4ad57405ee06f8a4645420e3f6841b5c8b68b8
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_bondtype.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 1
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 -1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_charge.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_charge.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..ac7ee610f06570f2314df73646b1f27d51662b28
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_charge.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 CHG=-
+M  V30 i
+M  V30 2 C 1 0 0 0
+M  V30 3 O 0 1 0 0
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$
diff --git a/modules/io/tests/testfiles/sdf_v3000/wrong_keyword.sdf b/modules/io/tests/testfiles/sdf_v3000/wrong_keyword.sdf
new file mode 100644
index 0000000000000000000000000000000000000000..eb79262e467962dd7ab9b7a2b055e41c1ec4e824
--- /dev/null
+++ b/modules/io/tests/testfiles/sdf_v3000/wrong_keyword.sdf
@@ -0,0 +1,26 @@
+Simple Ligand
+ OpenBabel06022310462D
+Teststructure
+  0  0  0     0  0            999 V3000
+M  V30 BEGIN CTAB
+M  V30 COUNTS 6 6 0 0 1
+M  V30 BEGIN ATOM
+M  V30 1 N 0 0 0 0 Rgroups=(2 1 2) CHG=-
+M  V30 3 
+M  V30 2 C 1 0 0 0 
+M  V30 3 O 0 1 0 0 CHG= 2
+M  V30 4 S 1 1 0 0
+M  V30 5 C   2  2 0 0
+M  V30 6 Cl -1 -1 0 0
+M  V30 END ATOM
+M  V30 BEGIN BOND
+M  V30 1 2 1  2
+M  V30 2 1  1 3
+M  V30 3  1 1 6
+M  V30  4 1 2 4
+M  V30 5 1 3 4
+M  V30 6 3 4 5
+M  V30 END BOND
+M  V30 END CTAB
+M  END
+$$$$