diff --git a/.gitignore b/.gitignore
index 71a47aca6f0cb322c46981610abe785b73597f04..be2ace82869f093288d4893aa88f98d3859a3e74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,5 +19,6 @@ html
 scratch
 pov_*test.pov
 pov_*test.inc
+*-out.pdb
 CMakeLists.txt.user
 OpenStructure.cbp
diff --git a/modules/io/src/CMakeLists.txt b/modules/io/src/CMakeLists.txt
index e77cfda20a98d8b856113f12c0b50deb470a2e92..f61c471d31a52f363fb17d43917719b927ebe06c 100644
--- a/modules/io/src/CMakeLists.txt
+++ b/modules/io/src/CMakeLists.txt
@@ -13,6 +13,7 @@ io_utils.hh
 io_exception.hh
 convert.hh
 converting_streams.hh
+formatted_line.hh
 )
 
 set(OST_IO_SOURCES
diff --git a/modules/io/src/formatted_line.hh b/modules/io/src/formatted_line.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f42bcac73aaec7166026bb36b530087fe0258ec8
--- /dev/null
+++ b/modules/io/src/formatted_line.hh
@@ -0,0 +1,218 @@
+#ifndef OST_IO_FORMATTED_LINE_HH
+#define OST_IO_FORMATTED_LINE_HH
+
+#include <ost/string_ref.hh>
+
+/*
+  Author: Marco Biasini
+ */
+
+namespace ost { namespace io {
+
+namespace fmt {
+
+struct LPadded : public StringRef {
+  LPadded(const char* s, size_t l): 
+    StringRef(s, l)
+  { }
+  
+  explicit LPadded(const String& s): StringRef(s.data(), s.size())
+  { }
+  
+  explicit LPadded(const char* s): StringRef(s, strlen(s))
+  { }
+};
+
+struct RPadded : public StringRef {
+  RPadded(const char* s, size_t l): 
+    StringRef(s, l)
+  { }
+  
+  explicit RPadded(const String& s): StringRef(s.data(), s.size())
+  { }
+  
+  explicit RPadded(const char* s): StringRef(s, strlen(s))
+  { }
+};
+
+
+struct LPaddedInt {
+  LPaddedInt(int val) {
+    size_t curr=0;
+    bool minus=val<0;
+    val=std::abs(val);
+    if (minus) {
+      data[curr]='-';
+      ++curr;
+    }
+    do {
+      int m=val%10;
+      data[curr]='0'+m;
+      ++curr;
+      val/=10;
+    } while(val);
+    // swap
+    for (size_t i=0, e=(curr-int(minus))/2; i<e; ++i) {
+      std::swap(data[int(minus)+i], data[curr-i-1]);
+    }
+    data[curr]='\0';
+    len=curr;
+  }
+  char   data[20];
+  size_t len;
+};
+
+// BIG FAT WARNING: Before using this class to output floats with lots of 
+// digits, make sure you indeed get the result you want. The function has 
+// not been tested enough for numerical stability.
+struct LPaddedFloat {
+  LPaddedFloat(Real val, int prec)
+  {
+    double rounded_val=round(val*pow(10, prec))*pow(0.1, prec);
+    size_t curr=0;
+    bool minus=rounded_val<0;
+    rounded_val=std::abs(rounded_val);
+    int int_val=int(rounded_val);
+    if (minus) {
+      data[curr]='-';
+      ++curr;
+    }
+    do {
+      int m=int_val%10;
+      data[curr]='0'+m;
+      ++curr;
+      int_val/=10;
+    } while(int_val);
+    // swap
+    for (size_t i=0, e=(curr-int(minus))/2; i<e; ++i) {
+      std::swap(data[int(minus)+i], data[curr-i-1]);
+    }
+    data[curr]='\0';
+    len=curr;
+    if (prec==0) {
+      return;
+    }
+    data[curr]='.';
+    curr++;
+    rounded_val-=int(rounded_val);
+    while(prec>0) {
+      rounded_val*=10;
+      int m=int(rounded_val);
+      rounded_val-=int(rounded_val);
+      data[curr]='0'+m;
+      curr++;
+      --prec;
+    }
+    data[curr]='\0';
+    len=curr;
+  }
+  char   data[20];
+  size_t len;  
+};
+
+
+
+}
+
+class LineSlice {
+public:
+  LineSlice(char* data, size_t l): data_(data), len_(l) 
+  {
+  }
+
+  LineSlice& operator=(const StringRef& str)
+  {
+    assert(str.length()==len_);
+    memcpy(data_, str.data(), str.size());
+    return *this;
+  }
+  
+  LineSlice& operator=(const fmt::LPadded& str)
+  {
+    assert(str.size()<=len_);
+    memcpy(data_+len_-str.size(), str.data(), str.size());
+    return *this;
+  }
+  
+  LineSlice& operator=(const fmt::RPadded& str)
+  {
+    assert(str.size()==len_);
+    memcpy(data_, str.data(), str.size());
+    return *this;
+  }
+  
+  LineSlice& operator=(const fmt::LPaddedInt& i) 
+  {
+    assert(i.len<=len_);
+    memcpy(data_+len_-i.len, i.data, i.len);
+    return *this;
+  }
+  
+  LineSlice& operator=(const fmt::LPaddedFloat& f)
+  {
+    assert(f.len<=len_);
+    memcpy(data_+len_-f.len, f.data, f.len);
+    return *this;
+  }
+  void Clear()
+  {
+    memset(data_, ' ', len_);
+  }
+private:
+  char* data_;
+  size_t len_;
+};
+
+class FormattedLine {
+public:
+  FormattedLine(size_t width): 
+    data_(new char[width]), len_(width)
+  {
+    this->Clear();
+  }
+  
+  void Clear()
+  {
+    memset(data_, ' ', len_);
+  }
+  ~FormattedLine() { delete[] data_; }
+  
+  LineSlice operator()(int start, int len) 
+  { 
+    assert(start>=0 && start+len<len_);
+    return LineSlice(data_+start, len);
+  }
+  
+  const char* Data() const { return data_; }
+  
+  size_t GetWidth() const { return len_; }
+  
+  char operator[](size_t index) const
+  {
+    assert(index<len_);
+    return data_[index];
+  }
+  
+  char& operator[](size_t index)
+  {
+    assert(index<_len_);
+    return data_[index];
+  }
+private:
+  FormattedLine& operator=(const FormattedLine& rhs);
+  FormattedLine(const FormattedLine& rhs);
+  char*       data_;
+  size_t      len_;
+};
+
+inline std::ostream& operator<<(std::ostream& stream, const FormattedLine& line)
+{
+  stream.write(line.Data(), line.GetWidth()); 
+  stream << std::endl;
+  return stream;
+}
+
+
+}}
+
+#endif
diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc
index 775bec870c7f4fc2ef02e4a8087472060803a37c..f46f70d040aa473edf037d443835edd24450096e 100644
--- a/modules/io/src/mol/pdb_writer.cc
+++ b/modules/io/src/mol/pdb_writer.cc
@@ -22,6 +22,7 @@
 #include <boost/format.hpp>
 #include <string.h>
 #include <ost/io/io_exception.hh>
+
 #include "pdb_writer.hh"
 
 using boost::format;
@@ -31,63 +32,119 @@ namespace ost { namespace io {
 
 namespace {
 
-void write_atom(std::ostream& ostr, const mol::AtomHandle& atom, int atomnum, 
+// determine whether the element name has to be shifted to to the left by one
+// column.
+bool shift_left(const String& atom_name, bool is_hetatm, 
+                const String& element, float mass) 
+{
+  if (is_hetatm==false) {
+    return false;
+  }
+
+  if (isnumber(atom_name[0]) || atom_name=="UNK" ||
+      atom_name.length()==4) {
+    return true;
+  }
+  if (mass>34) {
+    if (element=="W" || element=="V") {
+      return false;
+    }    
+    return true;
+  }
+  return (element=="K" || element=="CA" || element=="NA" || 
+          element=="MG" || element=="LI");
+}
+
+void write_atom(std::ostream& ostr, FormattedLine& line, 
+                const mol::AtomHandle& atom, int atomnum, 
                 bool is_pqr)
 {
   mol::ResidueHandle res=atom.GetResidue();
   char ins_code=res.GetNumber().GetInsCode();
-  String record_name=atom.GetAtomProps().is_hetatm ? "HETATM" : "ATOM  ";
-  String aname_str=atom.GetName();
-  if(aname_str.length()<4) {
-    aname_str=" "+aname_str;
-  }
+  StringRef record_name(atom.IsHetAtom() ? "HETATM" : "ATOM  ", 6);
   std::vector<String> names=atom.GetAltGroupNames();
+  
+  geom::Vec3 p=atom.GetPos();
+  line( 0, 6)=record_name;
+  line( 6, 5)=fmt::LPaddedInt(atomnum);
+  String atom_name=atom.GetName();
+  if (atom_name.size()>4) {
+    throw IOException("Atom name '"+atom.GetQualifiedName()+
+                      "' is too long for PDB output. At most 4 character "
+                      "are allowed");
+  }
+  if (shift_left(atom_name, atom.IsHetAtom(), atom.GetElement(), 
+                 atom.GetMass())) {
+    line(12, 4)=fmt::RPadded(atom_name);
+  } else {
+    line(13, 3)=fmt::RPadded(atom_name);
+  }
+  if (res.GetKey().size()>3) {
+    throw IOException("Residue name '"+res.GetQualifiedName()+
+                      "' is too long for PDB output. At most 3 characters are "
+                      "allowed");
+  }
+  line(17, 3)=fmt::LPadded(res.GetKey());
+  
+  String chain_name=res.GetChain().GetName();
+  if (chain_name.size()>0) {
+    if (chain_name.size()==1) {
+      line[21]=chain_name[0];
+    } else {
+      throw IOException("PDB format only support single-letter chain names");
+    }
+  }
+  line(22, 4)=fmt::LPaddedInt(res.GetNumber().GetNum());
+  if (ins_code!=0) {
+    line[26]=ins_code;
+  }
+  
+  // deal with alternative atom locations
   if (names.empty()) {
-    geom::Vec3 p=atom.GetPos();
-    String ins_str=(ins_code==0 ? " " : String(1, ins_code));
-    ostr << record_name << format("%5d") % atomnum
-         << format(" %-4s") % aname_str
-         << " "
-         << format("%.3s") % res.GetKey()
-         << format(" %.1s") % res.GetChain().GetName()
-         << format("%4d%s") % res.GetNumber().GetNum() %  ins_str
-         << "   "
-         << format("%8.3f%8.3f%8.3f") % p[0] % p[1] % p[2];
-    if(is_pqr) {
-      ostr << format("%6.2f") % atom.GetAtomProps().charge
-           << format("%6.2f") % atom.GetAtomProps().radius;
+    line(30, 8)=fmt::LPaddedFloat(p[0],  3);
+    line(38, 8)=fmt::LPaddedFloat(p[1],  3);
+    line(46, 8)=fmt::LPaddedFloat(p[2],  3);
+    
+    if (is_pqr) {
+      line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2);
+      line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2);
     } else {
-      ostr << format("%6.2f") % atom.GetAtomProps().occupancy
-           << format("%6.2f") % atom.GetAtomProps().b_factor;
+      line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2);
+      line(60, 6)=fmt::LPaddedFloat(atom.GetBFactor(), 2);
     }
-    ostr << format("%10s%2s") % "" % atom.GetAtomProps().element
-         << std::endl
-    ;    
+    
+    line(76, 2)=fmt::LPadded(atom.GetElement());
+    ostr << line;
   } else {
-    for (std::vector<String>::const_iterator i=names.begin(), 
-         e=names.end(); i!=e; ++i) {
-       geom::Vec3 p=atom.GetAltPos(*i);
-       String ins_str=(ins_code==0 ? " " : String(1, ins_code));
-       ostr << record_name << format("%5d") % atomnum
-            << format(" %-4s") % aname_str
-            << *i
-            << format("%.3s") % res.GetKey()
-            << format(" %.1s") % res.GetChain().GetName()
-            << format("%4d%s") % res.GetNumber().GetNum() %  ins_str
-            << "   "
-            << format("%8.3f%8.3f%8.3f") % p[0] % p[1] % p[2];
-       if(is_pqr) {
-         ostr << format("%6.2f") % atom.GetAtomProps().charge
-              << format("%6.2f") % atom.GetAtomProps().radius;
-       } else {
-         ostr << format("%6.2f") % atom.GetAtomProps().occupancy
-              << format("%6.2f") % atom.GetAtomProps().b_factor;
-       }
-       ostr << format("%10s%2s") % "" % atom.GetAtomProps().element
-            << std::endl
-       ;       
+    for (std::vector<String>::const_iterator
+         i=names.begin(), e=names.end(); i!=e; ++i) {
+      p=atom.GetAltPos(*i);
+      line(30, 50).Clear();
+
+      if (i->size()>1) {
+        throw IOException("Alternative atom indicator '"+atom.GetQualifiedName()+
+                          "("+*i+")' too long for PDB output. At most 1 "
+                          "character is allowed");
+      }
+      line[16]=(*i)[0];
+      line(30, 8)=fmt::LPaddedFloat(p[0],  3);
+      line(38, 8)=fmt::LPaddedFloat(p[1],  3);
+      line(46, 8)=fmt::LPaddedFloat(p[2],  3);
+
+      if (is_pqr) {
+       line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2);
+       line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2);
+      } else {
+       line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2);
+       line(60, 6)=fmt::LPaddedFloat(atom.GetBFactor(), 2);
+      }
+
+      line(76, 2)=fmt::LPadded(atom.GetElement());
+      ostr << line;
     }
   }
+
+  line.Clear();
 }
 
 void write_conect(std::ostream& ostr, int atom_index,
@@ -109,35 +166,63 @@ void write_conect(std::ostream& ostr, int atom_index,
 
 class PDBWriterImpl : public mol::EntityVisitor {
 public:
-  PDBWriterImpl(std::ostream& ostream, std::map<long,int>& atom_indices)
-    : ostr_(ostream), counter_(0), is_pqr_(false), last_chain_(),
-      atom_indices_(atom_indices) {
+  PDBWriterImpl(std::ostream& ostream, FormattedLine& line, 
+                std::map<long,int>& atom_indices)
+    : ostr_(ostream), counter_(0), is_pqr_(false),
+      atom_indices_(atom_indices), line_(line), peptide_(false) {
   }
 private:
 public:
   virtual bool VisitAtom(const mol::AtomHandle& atom) {
     counter_++;
-    if (last_chain_!=atom.GetResidue().GetChain()) {
-      if (last_chain_.IsValid()) {
-        ostr_ << "TER" << std::endl;
-      }
-      last_chain_=atom.GetResidue().GetChain();
-    }    
-    write_atom(ostr_, atom, counter_, is_pqr_);
+    write_atom(ostr_, line_, atom, counter_, is_pqr_);
     if (atom.GetAtomProps().is_hetatm) {
       atom_indices_[atom.GetHashCode()]=counter_;
     }
     return true;
   }
+  
+  virtual bool VisitResidue(const mol::ResidueHandle& res)
+  {
+    if (res.IsPeptideLinking()) {
+      peptide_=true;
+    } else {
+      if (peptide_) {
+        this->WriteTer(prev_);
+      }
+      peptide_=false;
+    }
+    prev_=res;
+    return true;
+  }
+  
+  void WriteTer(mol::ResidueHandle res)
+  {
+    counter_++;
+    line_(0, 6)=StringRef("TER   ", 6);
+    line_( 6, 5)=fmt::LPaddedInt(counter_);
+    line_(17, 3)=fmt::LPadded(res.GetKey());
+    line_[21]=res.GetChain().GetName()[0];
+    line_(22, 4)=fmt::LPaddedInt(res.GetNumber().GetNum());
+    char ins_code=res.GetNumber().GetInsCode();
+    if (ins_code!=0) {
+      line_[26]=ins_code;
+    }    
+    ostr_ << line_;
+    line_.Clear();
+  }
+  
   void SetIsPQR(bool t) {
     is_pqr_=t;
   }
 private:
-  std::ostream&    ostr_;
-  int              counter_;
-  bool             is_pqr_;
-  mol::ChainHandle last_chain_;
+  std::ostream&       ostr_;
+  int                 counter_;
+  bool                is_pqr_;
   std::map<long,int>& atom_indices_;
+  FormattedLine&      line_;
+  mol::ResidueHandle  prev_;
+  bool                peptide_;
 };
 
 class PDBConectWriterImpl : public mol::EntityVisitor {
@@ -175,15 +260,18 @@ private:
 }
 
 PDBWriter::PDBWriter(std::ostream& stream):
-  outfile_(), outstream_(stream)
-{}
+  outfile_(), outstream_(stream), mol_count_(0), line_(80)
+{
+  
+}
 
 PDBWriter::PDBWriter(const boost::filesystem::path& filename):
-  outfile_(filename.file_string().c_str()), outstream_(outfile_), mol_count_(0)
+  outfile_(filename.file_string().c_str()), outstream_(outfile_), 
+  mol_count_(0), line_(80)
 {}
 
 PDBWriter::PDBWriter(const String& filename):
-  outfile_(filename.c_str()), outstream_(outfile_), mol_count_(0)
+  outfile_(filename.c_str()), outstream_(outfile_), mol_count_(0), line_(80)
 {}
 
 void PDBWriter::WriteModelLeader()
@@ -208,7 +296,7 @@ template <typename H>
 void PDBWriter::WriteModel(H ent)
 {
   this->WriteModelLeader();
-  PDBWriterImpl writer(outstream_,atom_indices_);
+  PDBWriterImpl writer(outstream_,line_, atom_indices_);
   if (PDB::Flags() & PDB::PQR_FORMAT) {
     writer.SetIsPQR(true);
   }
@@ -235,14 +323,7 @@ void PDBWriter::Write(const mol::AtomHandleList& atoms)
   mol::ChainHandle last_chain;
   for (mol::AtomHandleList::const_iterator i=atoms.begin(),
        e=atoms.end(); i!=e; ++i, ++counter) {
-
-    if (last_chain!=(*i).GetResidue().GetChain()) {
-      if (last_chain.IsValid()) {
-        outstream_ << "TER" << std::endl;
-      }
-      last_chain=(*i).GetResidue().GetChain();
-    }
-    write_atom(outstream_, *i, counter, PDB::Flags() & PDB::PQR_FORMAT);
+    write_atom(outstream_, line_, *i, counter, PDB::Flags() & PDB::PQR_FORMAT);
   }
   this->WriteModelTrailer();
 }
diff --git a/modules/io/src/mol/pdb_writer.hh b/modules/io/src/mol/pdb_writer.hh
index 68a9332a95587b79afe16caea37ca72414de52ec..40ed1cbffa5cf8094f8a5ab04cd366500414a445 100644
--- a/modules/io/src/mol/pdb_writer.hh
+++ b/modules/io/src/mol/pdb_writer.hh
@@ -28,9 +28,11 @@
 #include <boost/filesystem/fstream.hpp>
 #include <boost/iostreams/filtering_stream.hpp>
 
+#include <ost/mol/mol.hh>
+
 #include <ost/io/module_config.hh>
+#include <ost/io/formatted_line.hh>
 
-#include <ost/mol/mol.hh>
 
 #include "pdb_io.hh"
 
@@ -58,6 +60,7 @@ private:
   std::ostream&   outstream_;
   int mol_count_;
   std::map<long, int> atom_indices_;
+  FormattedLine       line_;
 };
  
 }}
diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc
index 811c459a891d1f08e8400242ef896979a3829fbb..053705f01f820d376dff3da00209fe2d7f5d5a25 100644
--- a/modules/io/tests/test_io_pdb.cc
+++ b/modules/io/tests/test_io_pdb.cc
@@ -17,8 +17,10 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 //------------------------------------------------------------------------------
 #include <ost/mol/mol.hh>
+#include <ost/conop/conop.hh>
 #include <ost/io/mol/entity_io_pdb_handler.hh>
 #include <ost/io/pdb_reader.hh>
+#include <ost/io/pdb_writer.hh>
 #include <ost/io/io_exception.hh>
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
@@ -27,6 +29,36 @@ using boost::unit_test_framework::test_suite;
 using namespace ost;
 using namespace ost::io;
 
+
+bool compare_files(const String& test, const String& gold_standard)
+{
+  std::ifstream test_stream(test.c_str());
+  std::ifstream gold_stream(gold_standard.c_str());
+  String test_line, gold_line;
+  while (true) {
+    bool test_end=std::getline(test_stream, test_line);
+    bool gold_end=std::getline(gold_stream, gold_line);
+    if (!(test_end || gold_end)) {
+      return true;
+    }
+    if (!test_end) {
+      std::cerr << gold_standard << " contains additional line(s):"
+                << std::endl << gold_line;
+      return false;
+    }
+    if (!gold_end) {
+      std::cerr << test << " contains additional line(s):"
+                << std::endl << test_line;
+      return false;
+    }
+    if (gold_line!=test_line) {
+      std::cerr << "line mismatch:" << std::endl << "test: " << test_line 
+                << std::endl << "gold: " << gold_line;
+      return false;
+    }
+  }
+  return true;
+}
 BOOST_AUTO_TEST_SUITE( io )
 
 
@@ -186,7 +218,54 @@ BOOST_AUTO_TEST_CASE(no_endmdl_record)
   PDBReader reader(fname);
   mol::EntityHandle ent=mol::CreateEntity();
   BOOST_CHECK_THROW(reader.Import(ent), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(write_atom)
+{
+  std::stringstream out;
+  PDBWriter writer(out);
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.RequestXCSEditor();
+  mol::ChainHandle ch=edi.InsertChain("A");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "GLY");
+  mol::AtomProp c_prop;
+  c_prop.element="C";
+  c_prop.occupancy=1.0;
+  c_prop.b_factor=128.0;
+  mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), 
+                                   c_prop);
+  writer.Write(ent);
+  String s=out.str();
+  BOOST_CHECK_EQUAL(s.substr(0, 54), 
+                    "ATOM      1  CA  GLY A   1      32.000-128.000  -2.500");
+  BOOST_CHECK_EQUAL(s.substr(54, 26), 
+                    "  1.00128.00           C  ");
+}
 
+BOOST_AUTO_TEST_CASE(write_hetatom)
+{
+  std::stringstream out;
+  PDBWriter writer(out);
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.RequestXCSEditor();
+  mol::ChainHandle ch=edi.InsertChain("A");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "CA");
+  mol::AtomProp c_prop;
+  c_prop.element="CA";
+  c_prop.is_hetatm=true;
+  c_prop.mass=40.01;
+  c_prop.occupancy=1.0;
+  c_prop.b_factor=40.75;
+  mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), 
+                                   c_prop);
+  writer.Write(ent);
+  String s=out.str();
+  BOOST_CHECK_EQUAL(s.substr(0, 54), 
+                    "HETATM    1 CA    CA A   1      32.000-128.000  -2.500");
+  BOOST_CHECK_EQUAL(s.substr(54, 26), 
+                    "  1.00 40.75          CA  ");
 }
 
 BOOST_AUTO_TEST_CASE(no_endmdl_record_fault_tolerant)
@@ -207,4 +286,82 @@ BOOST_AUTO_TEST_CASE(no_endmdl_record_fault_tolerant)
   PDB::PopFlags();
 }
 
+BOOST_AUTO_TEST_CASE(alt_loc_import_export)
+{
+  String fname("testfiles/pdb/alt-loc.pdb");  
+  // this scope is required to force the writer stream to be closed before 
+  // opening the file again in compare_files. Avoids a race condition.
+  {
+    PDBReader reader(fname);
+    PDBWriter writer(String("testfiles/pdb/alt-loc-out.pdb"));
+    
+    mol::EntityHandle ent=mol::CreateEntity();
+    reader.Import(ent);
+    writer.Write(ent);
+  }
+  BOOST_CHECK(compare_files("testfiles/pdb/alt-loc.pdb", 
+                            "testfiles/pdb/alt-loc-out.pdb"));
+}
+
+BOOST_AUTO_TEST_CASE(write_ter)
+{
+  String fname("testfiles/pdb/ter.pdb");  
+  // this scope is required to force the writer stream to be closed before 
+  // opening the file again in compare_files. Avoids a race condition.
+  {
+    PDBReader reader(fname);
+    PDBWriter writer(String("testfiles/pdb/ter-out.pdb"));
+    
+    mol::EntityHandle ent=mol::CreateEntity();
+    reader.Import(ent);
+    // we use conopology to mark amino acids as peptide-linking. this is require 
+    // for proper TER output
+    conop::Conopology& conop_inst=conop::Conopology::Instance();
+    conop_inst.ConnectAll(conop_inst.GetBuilder(), ent);
+    writer.Write(ent);
+  }
+  BOOST_CHECK(compare_files("testfiles/pdb/ter.pdb", 
+                            "testfiles/pdb/ter-out.pdb"));
+}
+
+
+BOOST_AUTO_TEST_CASE(res_name_too_long)
+{
+  std::stringstream out;
+  PDBWriter writer(out);
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.RequestXCSEditor();
+  mol::ChainHandle ch=edi.InsertChain("A");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "CALCIUM");
+  mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5));
+  BOOST_CHECK_THROW(writer.Write(ent), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(chain_name_too_long)
+{
+  std::stringstream out;
+  PDBWriter writer(out);
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.RequestXCSEditor();
+  mol::ChainHandle ch=edi.InsertChain("AB");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "CA");
+  mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5));
+  BOOST_CHECK_THROW(writer.Write(ent), IOException);
+}
+
+BOOST_AUTO_TEST_CASE(atom_name_too_long)
+{
+  std::stringstream out;
+  PDBWriter writer(out);
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.RequestXCSEditor();
+  mol::ChainHandle ch=edi.InsertChain("A");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "CA");
+  mol::AtomHandle a=edi.InsertAtom(r, "CALCIUM", geom::Vec3(32.0, -128.0, -2.5));
+  BOOST_CHECK_THROW(writer.Write(ent), IOException);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/io/tests/testfiles/pdb/alt-loc.pdb b/modules/io/tests/testfiles/pdb/alt-loc.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..b08f834596a2ff3d094fe2964479beccdbf168c0
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/alt-loc.pdb
@@ -0,0 +1,3 @@
+ATOM      1  N  AMET A   1      16.000  64.000   0.000  0.50  1.00           N  
+ATOM      1  N  BMET A   1       8.000-128.000   0.000  0.50  1.00           N  
+END   
\ No newline at end of file
diff --git a/modules/io/tests/testfiles/pdb/ter.pdb b/modules/io/tests/testfiles/pdb/ter.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..fb85bb40350acded72722a6598b4b965409ec00f
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/ter.pdb
@@ -0,0 +1,15 @@
+ATOM      1  N   THR A 161      29.926 -12.642 -13.047  1.00 25.35           N  
+ATOM      2  CA  THR A 161      29.978 -12.367 -11.602  1.00 25.36           C  
+ATOM      3  C   THR A 161      29.215 -13.430 -10.777  1.00 27.67           C  
+ATOM      4  O   THR A 161      29.065 -13.298  -9.552  1.00 26.09           O  
+ATOM      5  CB  THR A 161      29.363 -11.029 -11.309  1.00 24.99           C  
+ATOM      6  OG1 THR A 161      28.023 -11.041 -11.744  1.00 22.56           O  
+ATOM      7  CG2 THR A 161      29.998  -9.872 -12.148  1.00 23.85           C  
+ATOM      8  N   ALA A 162      28.657 -14.427 -11.463  1.00 28.77           N  
+ATOM      9  CA  ALA A 162      28.111 -15.569 -10.810  1.00 30.99           C  
+ATOM     10  C   ALA A 162      29.301 -16.453 -10.436  1.00 33.52           C  
+ATOM     11  O   ALA A 162      29.230 -17.243  -9.498  1.00 36.04           O  
+ATOM     12  CB  ALA A 162      27.155 -16.295 -11.713  1.00 30.93           C  
+TER      13      ALA A 162                                                      
+HETATM   14  O   HOH A 164      25.516   0.940  27.392  1.00 38.40           O  
+END   
\ No newline at end of file