diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,6 +2,11 @@
 
 ## [Unreleased]
 
+## [0.1.2.4] - 2019-12-23
+### Added
+- Preprocessing for pdb-files.
+- Pdb parser.
+
 ## [0.1.2.3] - 2019-12-12
 ### Fixed
 - Fixes for .mae pasrser.
diff --git a/cobot-io.cabal b/cobot-io.cabal
--- a/cobot-io.cabal
+++ b/cobot-io.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 77c33361ec08da24af8711ddff5d4e8185bfe4b1fd097bb10c985f15857655f4
+-- hash: 1ecc108258e91fab1cf40b3e7a3dbb217465d2d0d4b32b76560469f2cf1ca543
 
 name:           cobot-io
-version:        0.1.2.3
+version:        0.1.2.4
 synopsis:       Biological data file formats and IO
 description:    Please see the README on GitHub at <https://github.com/less-wrong/cobot-io#readme>
 category:       Bio
@@ -50,6 +50,8 @@
       Bio.MMTF.MessagePack
       Bio.MMTF.Type
       Bio.PDB
+      Bio.PDB.Parser
+      Bio.PDB.Reader
       Bio.PDB.Type
       Bio.Sequence
       Bio.Sequence.Basecalled
@@ -100,6 +102,7 @@
       MAEParserSpec
       MAESpec
       MMTFSpec
+      PDBSpec
       SequenceSpec
       UniprotSpec
       Paths_cobot_io
diff --git a/src/Bio/PDB/Parser.hs b/src/Bio/PDB/Parser.hs
new file mode 100644
--- /dev/null
+++ b/src/Bio/PDB/Parser.hs
@@ -0,0 +1,157 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+module Bio.PDB.Parser
+  ( pdbP )
+where
+
+
+import           Bio.PDB.Type         (Atom (..), Chain, FieldType, Model,
+                                       PDB (..), RemarkCode)
+import           Control.Applicative  (many, some, (<|>))
+import           Control.DeepSeq      ()
+import           Data.Attoparsec.Text (Parser, choice, count, endOfInput,
+                                       endOfLine, isEndOfLine, satisfy,
+                                       skipWhile, space, string, takeWhile)
+import qualified Data.List            as L (groupBy)
+import           Data.Map.Strict      (Map, fromListWithKey)
+import           Data.Maybe           (catMaybes)
+import           Data.Monoid          ((<>))
+import           Data.Text            as T (Text, concat, pack, stripEnd)
+import qualified Data.Vector          as V (Vector, concat, fromList, singleton)
+import           GHC.Generics         ()
+import           Text.Read            (readMaybe)
+
+pdbP :: Parser PDB
+pdbP = do
+    pdbData <- many (choice [titleP, remarkStringP, manyModelsP, otherFieldP]) -- parser order is important
+    let
+        models         = V.concat $ catMaybes (getModels <$> pdbData)
+        otherFieldsMap = fromRevListWith (<>) $ catMaybes (getOtherField <$> pdbData)
+        title          = T.concat $ catMaybes (getTitle <$> pdbData)
+        remarks        = fromRevListWith (<>) $ catMaybes (getRemarks <$> pdbData)
+
+    return $ PDB title models remarks otherFieldsMap
+  where
+    getModels :: PdbData -> Maybe (V.Vector Model)
+    getModels item = case item of
+      ModelData x -> Just x
+      _           -> Nothing
+    getOtherField :: PdbData -> Maybe (FieldType, V.Vector Text)
+    getOtherField item = case item of
+      OtherFieldData (Just x, y) -> Just (x, V.singleton y)
+      _                          -> Nothing
+    getTitle :: PdbData -> Maybe Text
+    getTitle item = case item of
+      TitleData x -> Just x
+      _           -> Nothing
+    getRemarks :: PdbData -> Maybe (RemarkCode, V.Vector Text)
+    getRemarks item = case item of
+      RemarkData (x, y) -> Just (x, V.singleton y)
+      _                 -> Nothing
+
+data PdbData = ModelData (V.Vector Model)
+             | OtherFieldData (Maybe FieldType, Text)
+             | RemarkData (RemarkCode, Text)
+             | TitleData Text
+  deriving (Show)
+
+notEndLineChar :: Parser Char
+notEndLineChar = satisfy $ not . isEndOfLine
+
+takeText :: Parser Text
+takeText = Data.Attoparsec.Text.takeWhile $ not . isEndOfLine
+
+atomP :: Parser CoordLike
+atomP = let atom = Atom <$>
+                    (string "ATOM " *>                                       -- (1 -  6) # we increased atomSerial field for one symbol
+                    (read <$> count 6 notEndLineChar) <* space)              -- (7 - 11)  atomSerial
+                    <*> (T.pack <$> count 4 notEndLineChar)                  -- (13 - 16) atomName
+                    <*> notEndLineChar                                       -- (17)      atomAltLoc
+                    <*> (T.pack <$> count 3 notEndLineChar) <* space         -- (18 - 20) atomResName
+                    <*> notEndLineChar                                       -- (22)      atomChainID
+                    <*> (read <$> count 4 notEndLineChar)                    -- (23 - 26) atomResSeq
+                    <*> notEndLineChar <* count 3 space                      -- (27)      atomICode
+                    <*> (read <$> count 8 notEndLineChar)                    -- (31 - 38) atomX
+                    <*> (read <$> count 8 notEndLineChar)                    -- (39 - 46) atomY
+                    <*> (read <$> count 8 notEndLineChar)                    -- (47 - 54) atomZ
+                    <*> (read <$> count 6 notEndLineChar)                    -- (55 - 60) atomOccupancy
+                    <*> (read <$> count 6 notEndLineChar) <* count 10 space  -- (61 - 66) atomTempFactor
+                    <*> (T.pack <$> count 2 notEndLineChar)                  -- (77 - 78) atomElement
+                    <*> (T.pack <$> count 2 notEndLineChar)                  -- (79 - 80) atomCharge
+                    <* (endOfLine <|> endOfInput)
+        in AtomLine <$> atom
+
+coordNotAtomP :: Parser CoordLike
+coordNotAtomP = do
+    _ <- string "HETATM" <|> string "TER " <|> string "ANISOU" <|> string "CONECT"
+    skipWhile $ not . isEndOfLine
+    endOfLine
+    return CoordNotAtomLine
+
+data CoordLike = AtomLine Atom | CoordNotAtomLine
+  deriving (Show)
+
+coordLikeP :: Parser [CoordLike]
+coordLikeP = some (coordNotAtomP <|> atomP)
+
+chainsP :: Parser (V.Vector Chain)
+chainsP = do
+    coordLikeLines <- coordLikeP
+    let atoms  = catMaybes (getAtom <$> coordLikeLines)
+        chains = V.fromList (map V.fromList $ groupByChains atoms)
+    pure chains
+  where
+    getAtom :: CoordLike -> Maybe Atom
+    getAtom line = case line of
+      AtomLine x -> Just x
+      _          -> Nothing
+    groupByChains :: [Atom]-> [[Atom]]
+    groupByChains = L.groupBy (\x y ->  atomChainID x == atomChainID y)
+
+modelP :: Parser Model
+modelP = do
+    _ <- string "MODEL"
+    skipWhile $ not . isEndOfLine
+    endOfLine
+    chains <- chainsP
+    string "ENDMDL" >> skipWhile (not . isEndOfLine)
+    endOfLine <|> endOfInput
+    pure chains
+
+manyModelsP :: Parser PdbData
+manyModelsP = do
+    models <- (:[]) <$> chainsP <|> some modelP
+    return $ ModelData (V.fromList models)
+
+titleStringP :: Parser Text
+titleStringP = do
+    _ <- string "TITLE "
+    titleText <- takeText
+    endOfLine
+    pure $ T.stripEnd titleText
+
+titleP :: Parser PdbData
+titleP =  do
+    titleText <- T.concat <$> some titleStringP
+    return $ TitleData titleText
+
+remarkStringP :: Parser PdbData
+remarkStringP = do
+    _ <- string "REMARK"
+    _ <- space
+    (remarkCode :: RemarkCode) <- readMaybe <$> count 3 notEndLineChar
+    _ <- notEndLineChar
+    remarkText <- takeText
+    endOfLine
+    pure $ RemarkData (remarkCode, T.stripEnd remarkText)
+
+fromRevListWith :: Ord k => (a -> a -> a) -> [(k,a)] -> Map k a
+fromRevListWith f xs = fromListWithKey (\_ x y -> f y x) xs
+
+otherFieldP :: Parser PdbData
+otherFieldP = do
+    (fieldType :: Maybe FieldType) <- readMaybe <$> count 6 notEndLineChar
+    fieldTypeText <- takeText
+    endOfLine <|> endOfInput
+    return $ OtherFieldData (fieldType,  T.stripEnd fieldTypeText)
diff --git a/src/Bio/PDB/Reader.hs b/src/Bio/PDB/Reader.hs
new file mode 100644
--- /dev/null
+++ b/src/Bio/PDB/Reader.hs
@@ -0,0 +1,73 @@
+module Bio.PDB.Reader
+  ( fromTextPDB
+  , fromFilePDB
+  ) where
+
+import           Bio.PDB.Parser         (pdbP)
+import           Bio.PDB.Type           (PDB (..))
+import           Control.Monad.IO.Class (MonadIO, liftIO)
+import           Data.Attoparsec.Text   (parseOnly)
+import           Data.Bifunctor         (first)
+import           Data.List              as L (findIndices, length)
+import           Data.Maybe             (catMaybes)
+import           Data.Text              as T (Text, length, lines, pack,
+                                              replicate, take, unlines)
+import qualified Data.Text.IO           as TIO (readFile)
+
+
+type LineNumber = Int
+
+data PDBWarnings = LineTooLong LineNumber
+                 | LineTooShort LineNumber
+  deriving (Show, Eq)
+
+standardizeText :: Text -> ([PDBWarnings], Text)
+standardizeText text = (textWarnings, T.unlines standardizedLines)
+  where
+    textLines = T.lines text
+    desiredLength = 80  -- cause it is max length in standart pdb file
+
+    warnings'n'text = map standardizeLine $ zip [0..] textLines
+    textWarnings = catMaybes (fst <$> warnings'n'text)
+    standardizedLines = snd <$> warnings'n'text
+
+    standardizeLine :: (Int, Text) -> (Maybe PDBWarnings, Text)
+    standardizeLine (lineNumber,line) | lineLength < desiredLength = (Just (LineTooShort lineNumber), line <> T.replicate spacesCount " ")
+                                      | lineLength > desiredLength = (Just (LineTooLong lineNumber), T.take desiredLength line)
+                                      | otherwise = (Nothing, line)
+      where
+        lineLength = T.length line
+        spacesCount = desiredLength - lineLength
+
+
+isMdlLine :: Text -> Bool
+isMdlLine line = elem (T.take 6 line) modelStrings || elem (T.take 5 line) modelStrings
+  where
+    modelStrings = ["MODEL ", "ENDMDL", "ATOM ", "TER   ", "HETATM", "ANISOU", "CONECT"]
+
+checkRow :: [Int] -> Bool
+checkRow [] = True
+checkRow xs = last xs - head xs + 1 == L.length xs
+
+checkMdlLines :: ([PDBWarnings], Text) -> Bool
+checkMdlLines warnings'n'text = checkRow mdlLineNumbers
+  where
+    mdlLineNumbers = findIndices isMdlLine $ T.lines (snd warnings'n'text)
+
+preprocess :: Text -> Either Text ([PDBWarnings], Text)
+preprocess text = do
+  let standardizedText = standardizeText text
+  if checkMdlLines standardizedText
+  then Right standardizedText
+  else Left "There are trash strings between model strings"
+
+fromFilePDB :: MonadIO m => FilePath -> m (Either Text ([PDBWarnings], Either Text PDB))
+fromFilePDB f = do
+  content <- liftIO (TIO.readFile f)
+  let preprocessed = preprocess content
+  pure $ fmap (first pack . parseOnly pdbP) <$> preprocessed
+
+fromTextPDB :: Text -> Either Text ([PDBWarnings], Either Text PDB)
+fromTextPDB text = fmap (first pack . parseOnly pdbP) <$> preprocessed
+  where
+    preprocessed = preprocess text
diff --git a/src/Bio/PDB/Type.hs b/src/Bio/PDB/Type.hs
--- a/src/Bio/PDB/Type.hs
+++ b/src/Bio/PDB/Type.hs
@@ -24,7 +24,7 @@
    -- Title Section (except TITLE and REMARKS)
      HEADER
    | OBSLTE
-   | SPLT
+   | SPLIT
    | CAVEAT
    | COMPND
    | SOURCE
@@ -59,12 +59,18 @@
    | SITE
    -- Crystallographic and Coordinate Transformation Section
    | CRYST1
-   | MTRIXn
-   | ORIGXn
-   | SCALEn
+   | MTRIX1
+   | MTRIX2
+   | MTRIX3
+   | ORIGX1
+   | ORIGX2
+   | ORIGX3
+   | SCALE1
+   | SCALE2
+   | SCALE3
    -- Bookkeeping Section
    | MASTER
-  deriving (Show, Eq, Read, Generic, NFData)
+  deriving (Show, Eq, Read, Generic, NFData, Ord)
 
 type Model = Vector Chain
 
diff --git a/test/PDBSpec.hs b/test/PDBSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/PDBSpec.hs
@@ -0,0 +1,428 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module PDBSpec where
+
+import           Bio.PDB.Reader  (fromTextPDB)
+import           Bio.PDB.Type    (Atom (..), FieldType (..), PDB (..))
+import qualified Data.Map.Strict (empty, fromList, singleton)
+import           Data.Text       as T (Text, intercalate, length, lines, pack,
+                                       replicate, take)
+import qualified Data.Vector     as V (empty, fromList, singleton)
+import           Test.Hspec
+
+
+oneModelSpecP :: Spec
+oneModelSpecP = describe "One model." $
+        it "correctly parses pdb with only one model without strings \"MODEL\" & \"ENDMDL\"" $ do
+        let mt  = fromTextPDB . lenghtenLines $ T.pack ( "HEADER header\n" ++
+                                         "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                         "COMPND compnd\n" ++
+                                         "SOURCE source\n" ++
+                                         "KEYWDS keywds\n" ++
+                                         "AUTHOR  Masha\n" ++
+                                         "REVDAT revdat\n" ++
+                                         "REMARK   1 REFERENCE 1\n" ++
+                                         "SEQRES seqres\n" ++
+                                         "CRYST1 cryst1\n" ++
+                                         "ORIGX1 origx1 n=1\n" ++
+                                         "SCALE2 sclaen n=2\n" ++
+                                         "ATOM   2032  OXT CYS A 214      -4.546 -29.673  26.796  1.0 143.51           O  \n" ++
+                                         "ATOM   2033  H   CYS A 214      -6.124 -27.225  26.558  1.00 15.00           H  \n" ++
+                                         "TER    2034      CYS A 214                                                      \n" ++
+                                         "ATOM   2035  N   GLU B   1      18.637 -61.583  66.852  1.0 118.48           N  \n" ++
+                                         "TER   12534      ARG D 474                                                      \n" ++
+                                         "HETATM12535  C1  NAG B 475       5.791 -20.194  -7.051  1.00 34.66           C  \n" ++
+                                         "HETATM12538  C4  NAG B 475       6.943 -19.507  -9.597  1.00 25.87           C  \n" ++
+                                         "ATOM   2036  CA  GLU B   1      19.722 -62.606  66.868  1.00 19.77           C  \n" ++
+                                         "CONECT conect\n" ++
+                                         "CONECT conect conect\n" ++
+                                         "MASTER 1 2 3 4 5 6 7 8\n" ++
+                                         "END"
+                                       )
+        mt `shouldBe` Right ([], Right oneModelPDB)
+
+oneModelPDB :: PDB
+oneModelPDB =  PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                   , remarks = Data.Map.Strict.singleton (Just 1) (V.singleton "REFERENCE 1")
+                   , models = V.singleton $ V.fromList [V.fromList [Atom {atomSerial = 2032, atomName = " OXT", atomAltLoc = ' ', atomResName = "CYS", atomChainID = 'A', atomResSeq = 214, atomICode = ' ',
+                                                                           atomX = -4.546, atomY = -29.673, atomZ = 26.796, atomOccupancy = 1.0, atomTempFactor = 143.51, atomElement = " O",
+                                                                           atomCharge = "  "},
+                                                                           Atom {atomSerial = 2033, atomName = " H  ", atomAltLoc = ' ', atomResName = "CYS", atomChainID = 'A',
+                                                                           atomResSeq = 214, atomICode = ' ', atomX = -6.124, atomY = -27.225, atomZ = 26.558, atomOccupancy = 1.0, atomTempFactor = 15.0,
+                                                                           atomElement = " H", atomCharge = "  "}],
+                                                                           V.fromList [Atom {atomSerial = 2035, atomName = " N  ", atomAltLoc = ' ', atomResName = "GLU", atomChainID = 'B', atomResSeq = 1, atomICode = ' ',
+                                                                           atomX = 18.637, atomY = -61.583, atomZ = 66.852, atomOccupancy = 1.0, atomTempFactor = 118.48, atomElement = " N", atomCharge = "  "},
+                                                                           Atom {atomSerial = 2036, atomName = " CA ", atomAltLoc = ' ', atomResName = "GLU", atomChainID = 'B', atomResSeq = 1, atomICode = ' ',
+                                                                           atomX = 19.722, atomY = -62.606, atomZ = 66.868, atomOccupancy = 1.0, atomTempFactor = 19.77, atomElement = " C", atomCharge = "  "}]
+                                                                        ]
+                  , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(COMPND,V.fromList[" compnd"]),(SOURCE,V.fromList[" source"]),(KEYWDS,V.fromList[" keywds"]),(AUTHOR,V.fromList["  Masha"]),(REVDAT,V.fromList[" revdat"]),(SEQRES,V.fromList [" seqres"]),
+                                                            (CRYST1,V.fromList [" cryst1"]),(ORIGX1,V.fromList[" origx1 n=1"]),(SCALE2,V.fromList [" sclaen n=2"]),(MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                   }
+
+manyModelsSpecP :: Spec
+manyModelsSpecP = describe "Some models." $
+        it "correctly parses pdb with many models - they have strings \"MODEL\" & \"ENDMDL\" and text has disordered strings" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "HEADER header\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "COMPND compnd\n" ++
+                                        "SOURCE source\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "REMARK 2   Reference 2_1/1\n" ++
+                                        "CRYST1 cryst1\n" ++
+                                        "ORIGX1 origx1 n=1\n" ++
+                                        "SCALE2 sclaen n=2\n" ++
+                                        "MODEL  4  \n" ++
+                                        "ATOM   2033  H   CYS A 214      -6.124 -27.225  26.558  1.00 15.00           H  \n" ++
+                                        "TER    2034      CYS A 214                                                      \n" ++
+                                        "ANISOU anisou\n" ++
+                                        "ENDMDL \n" ++
+                                        "MODEL  5 \n" ++
+                                        "ATOM   2035  N   GLU B   1      18.637-691.583  66.852  1.0 118.48           N  \n" ++
+                                        "ATOM  12531 HH12 ARG D 474      45.558 -39.551 -49.936  1.00 15.00           H  \n" ++
+                                        "ENDMDL \n" ++
+                                        "MODEL  6 \n" ++
+                                        "ATOM  12532 HH21 ARG D 474      47.457 -38.007 -47.445  1.00 15.00           H  \n" ++
+                                        "TER   12534      ARG D 474                                                      \n" ++
+                                        "ATOM  12533 HH22 ARG D 474      47.405 -39.268 -48.629  1.00 15.00           H  \n" ++
+                                        "HETATM12535  C1  NAG B 475       5.791 -20.194  -7.051  1.00 34.66           C  \n" ++
+                                        "HETATM12538  C4  NAG B 475       6.943 -19.507  -9.597  1.00 25.87           C  \n" ++
+                                        "CONECT conect conect\n" ++
+                                        "CONECT conect\n" ++
+                                        "ENDMDL\n" ++
+                                        "SEQRES seqres\n" ++
+                                        "KEYWDS keywds\n" ++
+                                        "EXPDTA expdta\n" ++
+                                        "AUTHOR  Masha\n" ++
+                                        "REVDAT revdat\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n"
+                                      )
+        mt `shouldBe` Right ([], Right manyModelsPDB)
+
+manyModelsPDB :: PDB
+manyModelsPDB = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                    , remarks = Data.Map.Strict.fromList [(Just 1, V.singleton "REFERENCE 1"), (Just 2, V.singleton "Reference 2_1/1")]
+                    , models = V.fromList [V.fromList [V.fromList [Atom {atomSerial = 2033, atomName = " H  ", atomAltLoc = ' ', atomResName = "CYS",
+                                                                                                  atomChainID = 'A', atomResSeq = 214, atomICode = ' ', atomX = -6.124, atomY = -27.225,
+                                                                                                  atomZ = 26.558, atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                          ],
+                                                    V.fromList [V.fromList [Atom {atomSerial = 2035, atomName = " N  ", atomAltLoc = ' ', atomResName = "GLU",
+                                                                                                 atomChainID = 'B', atomResSeq = 1, atomICode = ' ', atomX = 18.637, atomY = -691.583,
+                                                                                                 atomZ = 66.852, atomOccupancy = 1.0, atomTempFactor = 118.48, atomElement = " N", atomCharge = "  "}],
+                                                                          V.fromList [Atom {atomSerial = 12531, atomName = "HH12", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                 atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 45.558, atomY = -39.551, atomZ = -49.936,
+                                                                                                 atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                         ],
+                                                    V.fromList [V.fromList [Atom {atomSerial = 12532, atomName = "HH21", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                 atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 47.457, atomY = -38.007, atomZ = -47.445,
+                                                                                                 atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "},
+                                                                                                Atom {atomSerial = 12533, atomName = "HH22", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                 atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 47.405, atomY = -39.268, atomZ = -48.629,
+                                                                                                 atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                          ]
+                                                      ]
+                    , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(COMPND,V.fromList[" compnd"]),(SOURCE,V.fromList[" source"]),(KEYWDS,V.fromList[" keywds"]),(EXPDTA,V.fromList[" expdta"]),(AUTHOR,V.fromList["  Masha"]),(REVDAT,V.fromList[" revdat"]),(SEQRES,V.fromList [" seqres"]),
+                                                              (CRYST1,V.fromList [" cryst1"]),(ORIGX1,V.fromList[" origx1 n=1"]),(SCALE2,V.fromList [" sclaen n=2"]),(MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                    }
+
+noModelsSpecP :: Spec
+noModelsSpecP = describe "No models." $
+        it "correctly parses pdb without models (no ATOM, TER, HETATM strings)" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "HEADER header\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "COMPND compnd\n" ++
+                                        "SOURCE source\n" ++
+                                        "KEYWDS keywds\n" ++
+                                        "EXPDTA expdta\n" ++
+                                        "AUTHOR  Masha\n" ++
+                                        "REVDAT revdat\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "SEQRES seqres\n" ++
+                                        "CRYST1 cryst1\n" ++
+                                        "ORIGX1 origx1 n=1\n" ++
+                                        "SCALE2 sclaen n=2\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n"
+                                      )
+        mt `shouldBe` Right ([], Right noModelsPDB)
+
+noModelsPDB :: PDB
+noModelsPDB = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                  , remarks = Data.Map.Strict.singleton (Just 1) (V.singleton "REFERENCE 1")
+                  , models = V.empty
+                  , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(COMPND,V.fromList[" compnd"]),(SOURCE,V.fromList[" source"]),(KEYWDS,V.fromList[" keywds"]),(EXPDTA,V.fromList[" expdta"]),(AUTHOR,V.fromList["  Masha"]),(REVDAT,V.fromList[" revdat"]),(SEQRES,V.fromList [" seqres"]),
+                                                            (CRYST1,V.fromList [" cryst1"]),(ORIGX1,V.fromList[" origx1 n=1"]),(SCALE2,V.fromList [" sclaen n=2"]),(MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                  }
+
+allFieldsModelSpecP :: Spec
+allFieldsModelSpecP = describe "PDB with all strings." $
+        it "correctly parses pdb with all types of string" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "HEADER header\n" ++
+                                        "OBSLTE obslte\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "SPLIT split\n" ++
+                                        "CAVEAT caveat\n" ++
+                                        "COMPND compnd\n" ++
+                                        "SOURCE source\n" ++
+                                        "KEYWDS keywds\n" ++
+                                        "EXPDTA expdta1\n" ++
+                                        "EXPDTA expdta2\n" ++
+                                        "NUMMDL nummdl\n" ++
+                                        "MDLTYP mdltyp mdltyp\n" ++
+                                        "AUTHOR  Masha\n" ++
+                                        "REVDAT revdat\n" ++
+                                        "SPRSDE sprsde\n" ++
+                                        "JRNL   jrnl\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "DBREF dbref\n" ++
+                                        "DBREF1 dbref1\n" ++
+                                        "DBREF2 dbref2_1\n" ++
+                                        "DBREF2 dbref2_2\n" ++
+                                        "SEQADV seqadv\n" ++
+                                        "SEQRES seqres\n" ++
+                                        "MODRES modres\n" ++
+                                        "HET    het\n" ++
+                                        "HETNAM hetnam\n" ++
+                                        "HETSYN hetsyn\n" ++
+                                        "FORMUL of love\n" ++
+                                        "HELIX helix\n" ++
+                                        "SHEET sheet\n" ++
+                                        "SSBOND ssbond\n" ++
+                                        "LINK   link\n" ++
+                                        "CISPEP cispep\n" ++
+                                        "SITE   site\n" ++
+                                        "CRYST1 cryst1\n" ++
+                                        "ORIGX1 origx1 n=1\n" ++
+                                        "SCALE2 sclaen n=2\n" ++
+                                        "MTRIX3 matrixn n=3\n" ++
+                                        "MODEL 1\n" ++
+                                        "ATOM  12532 HH21 ARG D 474      47.457 -38.007 -47.445  1.00 15.00           H  \n" ++
+                                        "TER   12534      ARG D 474                                                      \n" ++
+                                        "HETATM12535  C1  NAG B 475       5.791 -20.194  -7.051  1.00 34.66           C  \n" ++
+                                        "CONECT conect\n" ++
+                                        "CONECT conect conect\n" ++
+                                        "ENDMDL\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n" ++
+                                        "END"
+                                      )
+        mt `shouldBe` Right ([], Right pdbWithAllFields)
+
+pdbWithAllFields :: PDB
+pdbWithAllFields = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                       , models = V.fromList [V.fromList [V.singleton Atom {atomSerial = 12532, atomName = "HH21", atomAltLoc = ' ', atomResName = "ARG",
+                                     atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 47.457, atomY = -38.007, atomZ = -47.445,
+                                     atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]]
+                       , remarks = Data.Map.Strict.singleton (Just 1) (V.singleton "REFERENCE 1")
+                       , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(OBSLTE, V.fromList [" obslte"]), (SPLIT, V.fromList ["split"]), (CAVEAT, V.fromList [" caveat"]),
+                                                                 (COMPND, V.fromList [" compnd"]),(SOURCE, V.fromList [" source"]),(KEYWDS, V.fromList [" keywds"]),
+                                                                 (EXPDTA, V.fromList [" expdta1"," expdta2"]),(NUMMDL, V.fromList [" nummdl"]),(MDLTYP, V.fromList [" mdltyp mdltyp"]),
+                                                                 (AUTHOR, V.fromList ["  Masha"]),(REVDAT, V.fromList [" revdat"]),(SPRSDE, V.fromList [" sprsde"]),
+                                                                 (JRNL, V.fromList [" jrnl"]),(DBREF, V.fromList ["dbref"]), (DBREF1, V.fromList [" dbref1"]), (DBREF2, V.fromList [" dbref2_1"," dbref2_2"]),
+                                                                 (SEQADV, V.fromList [" seqadv"]),(SEQRES, V.fromList [" seqres"]),(MODRES, V.fromList [" modres"]),
+                                                                 (HET, V.fromList [" het"]), (HETNAM, V.fromList [" hetnam"]), (HETSYN, V.fromList [" hetsyn"]),(FORMUL, V.fromList [" of love"]),(HELIX, V.fromList ["helix"]),
+                                                                 (SHEET, V.fromList ["sheet"]),(SSBOND, V.fromList [" ssbond"]),(LINK, V.fromList [" link"]),
+                                                                 (CISPEP, V.fromList [" cispep"]),(SITE,V.fromList [" site"]),(CRYST1, V.fromList [" cryst1"]),(MTRIX3, V.fromList [" matrixn n=3"]),
+                                                                 (ORIGX1, V.fromList [" origx1 n=1"]),(SCALE2, V.fromList [" sclaen n=2"]),(MASTER, V.fromList [" 1 2 3 4 5 6 7 8"])]
+                       }
+
+
+emptySpecP :: Spec
+emptySpecP = describe "empty PDB." $
+        it "correctly parses empty pdb" $ do
+        let mt = fromTextPDB ""
+        mt `shouldBe` Right ([], Right emptyPdb)
+
+emptyPdb :: PDB
+emptyPdb = PDB { title = ""
+               , models = V.empty
+               , remarks = Data.Map.Strict.empty
+               , otherFields = Data.Map.Strict.empty
+               }
+
+trashBetweenModelsSpecP :: Spec
+trashBetweenModelsSpecP = describe "PDB has trash." $
+        it "correctly parses pdb with trash string between models and other field strings" $ do
+        let mt = fromTextPDB  . lenghtenLines $ T.pack ( "trash strings 1\n" ++
+                                        "HEADER header\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "trash strings 2\n" ++
+                                        "REMARK 2   Reference 2_1/1\n" ++
+                                        "MODEL  4  \n" ++
+                                        "ATOM   2033  H   CYS A 214      -6.124 -27.225  26.558  1.00 15.00           H  \n" ++
+                                        "TER    2034      CYS A 214                                                      \n" ++
+                                        "ANISOU anisou\n" ++
+                                        "ENDMDL \n" ++
+                                        "CRYST1 cryst1\n" ++
+                                        "trash strings 3\n" ++
+                                        "SEQRES seqres\n" ++
+                                        "MODEL  5 \n" ++
+                                        "ATOM   2035  N   GLU B   1      18.637-691.583  66.852  1.0 118.48           N  \n" ++
+                                        "ATOM  12531 HH12 ARG D 474      45.558 -39.551 -49.936  1.00 15.00           H  \n" ++
+                                        "ENDMDL \n" ++
+                                        "trash strings 4\n" ++
+                                        "MODEL  6 \n" ++
+                                        "ATOM  12532 HH21 ARG D 474      47.457 -38.007 -47.445  1.00 15.00           H  \n" ++
+                                        "TER   12534      ARG D 474                                                      \n" ++
+                                        "ATOM  12533 HH22 ARG D 474      47.405 -39.268 -48.629  1.00 15.00           H  \n" ++
+                                        "HETATM12535  C1  NAG B 475       5.791 -20.194  -7.051  1.00 34.66           C  \n" ++
+                                        "HETATM12538  C4  NAG B 475       6.943 -19.507  -9.597  1.00 25.87           C  \n" ++
+                                        "CONECT conect conect\n" ++
+                                        "ENDMDL\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n" ++
+                                        "trash strings 5\n"
+                                       )
+        mt `shouldBe` Left "There are trash strings between model strings"
+
+pdbWithoutTrash :: PDB
+pdbWithoutTrash = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                      , remarks = Data.Map.Strict.fromList [(Just 1, V.singleton "REFERENCE 1"), (Just 2, V.singleton "Reference 2_1/1")]
+                      , models = V.fromList [V.fromList [V.fromList [Atom {atomSerial = 2033, atomName = " H  ", atomAltLoc = ' ', atomResName = "CYS",
+                                                                                                    atomChainID = 'A', atomResSeq = 214, atomICode = ' ', atomX = -6.124, atomY = -27.225,
+                                                                                                    atomZ = 26.558, atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                            ],
+                                                      V.fromList [V.fromList [Atom {atomSerial = 2035, atomName = " N  ", atomAltLoc = ' ', atomResName = "GLU",
+                                                                                                   atomChainID = 'B', atomResSeq = 1, atomICode = ' ', atomX = 18.637, atomY = -691.583,
+                                                                                                   atomZ = 66.852, atomOccupancy = 1.0, atomTempFactor = 118.48, atomElement = " N", atomCharge = "  "}],
+                                                                            V.fromList [Atom {atomSerial = 12531, atomName = "HH12", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                   atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 45.558, atomY = -39.551, atomZ = -49.936,
+                                                                                                   atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                           ],
+                                                      V.fromList [V.fromList [Atom {atomSerial = 12532, atomName = "HH21", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                   atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 47.457, atomY = -38.007, atomZ = -47.445,
+                                                                                                   atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "},
+                                                                                                  Atom {atomSerial = 12533, atomName = "HH22", atomAltLoc = ' ', atomResName = "ARG",
+                                                                                                   atomChainID = 'D', atomResSeq = 474, atomICode = ' ', atomX = 47.405, atomY = -39.268, atomZ = -48.629,
+                                                                                                   atomOccupancy = 1.0, atomTempFactor = 15.0, atomElement = " H", atomCharge = "  "}]
+                                                                            ]
+                                                        ]
+                      , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(SEQRES,V.fromList [" seqres"]),
+                                                                (CRYST1,V.fromList [" cryst1"]),(MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                      }
+
+onlyOneModelSpecP :: Spec
+onlyOneModelSpecP = describe "Only One model." $
+        it "correctly parses pdb with only one model without other field/title/trash/remarks strings" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "ATOM   2032  OXT CYS A 214      -4.546 -29.673  26.796  1.0 143.51           O  \n" ++
+                                         "ATOM   2033  H   CYS A 214      -6.124 -27.225  26.558  1.00 15.00           H  \n" ++
+                                         "TER    2034      CYS A 214                                                      \n" ++
+                                         "ATOM   2035  N   GLU B   1      18.637 -61.583  66.852  1.0 118.48           N  \n" ++
+                                         "TER   12534      ARG D 474                                                      \n" ++
+                                         "HETATM12535  C1  NAG B 475       5.791 -20.194  -7.051  1.00 34.66           C  \n" ++
+                                         "HETATM12538  C4  NAG B 475       6.943 -19.507  -9.597  1.00 25.87           C  \n" ++
+                                         "ATOM   2036  CA  GLU B   1      19.722 -62.606  66.868  1.00 19.77           C  \n"
+                                        )
+        mt `shouldBe` Right ([], Right onlyOneModelPDB)
+
+onlyOneModelPDB :: PDB
+onlyOneModelPDB = PDB { title = ""
+                      , remarks = Data.Map.Strict.empty
+                      , models = V.singleton $ V.fromList [V.fromList [Atom {atomSerial = 2032, atomName = " OXT", atomAltLoc = ' ', atomResName = "CYS", atomChainID = 'A', atomResSeq = 214, atomICode = ' ',
+                                                                              atomX = -4.546, atomY = -29.673, atomZ = 26.796, atomOccupancy = 1.0, atomTempFactor = 143.51, atomElement = " O",
+                                                                              atomCharge = "  "},
+                                                                              Atom {atomSerial = 2033, atomName = " H  ", atomAltLoc = ' ', atomResName = "CYS", atomChainID = 'A',
+                                                                              atomResSeq = 214, atomICode = ' ', atomX = -6.124, atomY = -27.225, atomZ = 26.558, atomOccupancy = 1.0, atomTempFactor = 15.0,
+                                                                              atomElement = " H", atomCharge = "  "}],
+                                                                              V.fromList [Atom {atomSerial = 2035, atomName = " N  ", atomAltLoc = ' ', atomResName = "GLU", atomChainID = 'B', atomResSeq = 1, atomICode = ' ',
+                                                                              atomX = 18.637, atomY = -61.583, atomZ = 66.852, atomOccupancy = 1.0, atomTempFactor = 118.48, atomElement = " N", atomCharge = "  "},
+                                                                              Atom {atomSerial = 2036, atomName = " CA ", atomAltLoc = ' ', atomResName = "GLU", atomChainID = 'B', atomResSeq = 1, atomICode = ' ',
+                                                                              atomX = 19.722, atomY = -62.606, atomZ = 66.868, atomOccupancy = 1.0, atomTempFactor = 19.77, atomElement = " C", atomCharge = "  "}]
+                                                                              ]
+                      , otherFields = Data.Map.Strict.empty
+                      }
+
+repeatedStringsSpecP :: Spec
+repeatedStringsSpecP = describe "PDB with repeated other field strings." $
+        it "correctly parses pdb with repeated other field strings (SOURCE)" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "HEADER header\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "COMPND compnd\n" ++
+                                        "EXPDTA expdta\n" ++
+                                        "AUTHOR  Masha\n" ++
+                                        "SOURCE source1\n" ++
+                                        "KEYWDS keywds\n" ++
+                                        "REVDAT revdat\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "SEQRES seqres\n" ++
+                                        "CRYST1 cryst1\n" ++
+                                        "ORIGX1 origx1 n=1\n" ++
+                                        "SOURCE source2\n" ++
+                                        "SCALE2 sclaen n=2\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n" ++
+                                        "SOURCE source3\n" ++
+                                        "END"
+                                      )
+        mt `shouldBe` Right ([], Right repeatedStringsPDB)
+
+repeatedStringsPDB :: PDB
+repeatedStringsPDB = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                         , remarks = Data.Map.Strict.singleton (Just 1) (V.singleton "REFERENCE 1")
+                         , models = V.empty
+                         , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),(COMPND,V.fromList[" compnd"]),(SOURCE,V.fromList[" source1", " source2", " source3"]),(KEYWDS,V.fromList[" keywds"]),(EXPDTA,V.fromList[" expdta"]),(AUTHOR,V.fromList["  Masha"]),(REVDAT,V.fromList[" revdat"]),(SEQRES,V.fromList [" seqres"]),
+                                                                   (CRYST1,V.fromList [" cryst1"]),(ORIGX1,V.fromList[" origx1 n=1"]),(SCALE2,V.fromList [" sclaen n=2"]),(MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                         }
+
+emptyRemarkSpecP :: Spec
+emptyRemarkSpecP = describe "PDB with repeated remark strings without code." $
+        it "correctly parses pdb with repeated remark strings without code" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "REMARK 111 remark111_1/2\n" ++
+                                        "COMPND compnd\n" ++
+                                        "SOURCE source1\n" ++
+                                        "KEYWDS keywds\n" ++
+                                        "REMARK 111 remark111_2/2\n" ++
+                                        "REVDAT revdat\n" ++
+                                        "REMARK 2   remark2_1/1\n" ++
+                                        "SOURCE source2\n" ++
+                                        "REMARK     empty remark 1/2\n" ++
+                                        "END    \n" ++
+                                        "REMARK     empty remark 2/2\n" ++
+                                        "SCALE2 sclaen n=2\n"
+                                      )
+        mt `shouldBe` Right ([], Right pdbWithEmptyRemarks)
+
+pdbWithEmptyRemarks :: PDB
+pdbWithEmptyRemarks = PDB { title = ""
+                         , remarks = Data.Map.Strict.fromList [(Just 2, V.fromList ["remark2_1/1"]), (Just 111, V.fromList ["remark111_1/2", "remark111_2/2"]), (Nothing, V.fromList ["empty remark 1/2", "empty remark 2/2"])]
+                         , models = V.empty
+                         , otherFields = Data.Map.Strict.fromList [(COMPND,V.fromList[" compnd"]),(SOURCE,V.fromList[" source1", " source2"]),
+                                                                    (KEYWDS,V.fromList[" keywds"]), (REVDAT,V.fromList[" revdat"]), (SCALE2,V.fromList [" sclaen n=2"])]
+                         }
+
+emptyModelSpecP :: Spec
+emptyModelSpecP = describe "PDB with one empty model." $
+        it "correctly parses pdb with one model without strings inside" $ do
+        let mt = fromTextPDB . lenghtenLines $ T.pack ( "trash strings 1\n" ++
+                                        "HEADER header\n" ++
+                                        "TITLE STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME\n" ++
+                                        "REMARK 1   REFERENCE 1\n" ++
+                                        "trash strings 2\n" ++
+                                        "REMARK 2   Reference 2_1/1\n" ++
+                                        "MODEL  4  \n" ++
+                                        "ENDMDL\n" ++
+                                        "MASTER 1 2 3 4 5 6 7 8\n" ++
+                                        "trash strings 5\n"
+                                      )
+        mt `shouldBe` Right ([], Right pdbEmptyModel)
+
+
+pdbEmptyModel :: PDB
+pdbEmptyModel = PDB { title = "STRUCTURE OF THE TRANSFORMED MONOCLINIC  LYSOZYME"
+                    , remarks = Data.Map.Strict.fromList [(Just 1, V.singleton "REFERENCE 1"), (Just 2, V.singleton "Reference 2_1/1")]
+                    , models = V.empty
+                    , otherFields = Data.Map.Strict.fromList [(HEADER, V.fromList [" header"]),
+                                                              (MASTER,V.fromList[" 1 2 3 4 5 6 7 8"])]
+                    }
+
+lenghtenLines :: Text -> Text
+lenghtenLines text = longLinedText
+   where
+       textLines = T.lines text
+       longTextLines = changeLine <$> textLines
+       desiredLength = 80  -- cause it is max length in standart pdb file
+       longLinedText = T.intercalate "\n" longTextLines
+
+       changeLine :: Text -> Text
+       changeLine line | T.length line > desiredLength = T.take desiredLength line
+                       | T.length line < desiredLength = line <> T.replicate spacesCount " "
+                       | otherwise = line
+            where
+                    spacesCount = desiredLength - T.length line
+
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -11,6 +11,7 @@
 import           System.IO
 import           Test.Hspec
 import           UniprotSpec
+import           PDBSpec
 
 main :: IO ()
 main = do
@@ -40,3 +41,14 @@
          -- Mae
          maeParserSpec
          maeSpec
+         -- PDB
+         oneModelSpecP
+         manyModelsSpecP
+         noModelsSpecP
+         allFieldsModelSpecP
+         emptySpecP
+         trashBetweenModelsSpecP
+         onlyOneModelSpecP
+         repeatedStringsSpecP
+         emptyRemarkSpecP
+         emptyModelSpecP
