diff -pruN 8-1/debian/changelog 9-1/debian/changelog
--- 8-1/debian/changelog	2022-07-14 07:22:20.000000000 +0000
+++ 9-1/debian/changelog	2022-08-03 11:21:55.000000000 +0000
@@ -1,3 +1,9 @@
+python-shelxfile (9-1) unstable; urgency=medium
+
+  * New upstream version 9
+
+ -- Andrius Merkys <merkys@debian.org>  Wed, 03 Aug 2022 07:21:55 -0400
+
 python-shelxfile (8-1) unstable; urgency=medium
 
   * New upstream version 8
diff -pruN 8-1/README.md 9-1/README.md
--- 8-1/README.md	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/README.md	2022-07-26 20:37:30.000000000 +0000
@@ -39,11 +39,14 @@ CELL 0.71073 10.5086 20.9035 20.5072 90
 
 # You can overwrite any parameter in a shelx file:
 >>> shx.plan
+PLAN 20
+
+>>> shx.plan.npeaks
 20
 
->>> shx.plan = 30
+>>> shx.plan.set('PLAN 30')
 >>> shx.plan
-30
+PLAN 30
 
 >>> shx.atoms
 O1     3    0.074835    0.238436    0.402457   -31.00000    0.01579    0.03095      0.01852   -0.00468   -0.00210    0.01153
@@ -52,6 +55,16 @@ C2     1    0.121540    0.194460    0.29
 F
 ...
 
+>>> shx.atoms.hydrogen_atoms
+[Atom ID: 81, Atom ID: 88, Atom ID: 95, ... ]
+
+>>> shx.atoms.n_hydrogen_atoms
+24
+
+# Atoms with a riding model e.g. hydrogen atom riding on a carbon atom:
+>>> shx.atoms.riding_atoms
+[Atom ID: 81, Atom ID: 88, Atom ID: 95, ... ]
+
 >>> a = shx.atoms.get_atom_by_name('F1_2')  # Atom F1 in residue 2
 >>> a
 Atom ID: 258  # <- The Atom ID is the index number in the Shelxfile._reslist list
diff -pruN 8-1/scripts/make_distribution.sh 9-1/scripts/make_distribution.sh
--- 8-1/scripts/make_distribution.sh	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/scripts/make_distribution.sh	2022-07-26 20:37:30.000000000 +0000
@@ -1,6 +1,8 @@
-cd ..
+# run from project root
+source venv/bin/activate
 rm -Rf dist
 rm -Rf shelxfile.egg-info
+pip install pip -U
 pip install --upgrade setuptools
 python3 -m build
 # python3 -m twine upload --repository pypi dist/*
\ No newline at end of file
diff -pruN 8-1/scripts/upload_to_pypi.bat 9-1/scripts/upload_to_pypi.bat
--- 8-1/scripts/upload_to_pypi.bat	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/scripts/upload_to_pypi.bat	2022-07-26 20:37:30.000000000 +0000
@@ -1,2 +1,4 @@
-cd ..
-python3 -m twine upload --repository pypi dist\*
\ No newline at end of file
+call venv\Scripts\activate.bat
+venv\Scripts\pip install twine
+
+venv\Scripts\python -m twine upload --repository pypi dist\*
\ No newline at end of file
diff -pruN 8-1/scripts/upload_to_pypi.sh 9-1/scripts/upload_to_pypi.sh
--- 8-1/scripts/upload_to_pypi.sh	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/scripts/upload_to_pypi.sh	2022-07-26 20:37:30.000000000 +0000
@@ -1,2 +1,2 @@
-cd ..
+
 python3 -m twine upload --repository pypi dist/*
\ No newline at end of file
diff -pruN 8-1/scripts/upload_to_test-pypi.sh 9-1/scripts/upload_to_test-pypi.sh
--- 8-1/scripts/upload_to_test-pypi.sh	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/scripts/upload_to_test-pypi.sh	2022-07-26 20:37:30.000000000 +0000
@@ -1,2 +1,2 @@
-cd ..
+
 python3 -m twine upload --repository testpypi dist/*
\ No newline at end of file
diff -pruN 8-1/setup.cfg 9-1/setup.cfg
--- 8-1/setup.cfg	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/setup.cfg	2022-07-26 20:37:30.000000000 +0000
@@ -1,6 +1,6 @@
 [metadata]
 name = shelxfile
-version = 8
+version = 9
 author = Daniel Kratzert
 author_email = dkratzert@gmx.de
 license = Beerware License
diff -pruN 8-1/shelxfile/atoms/atom.py 9-1/shelxfile/atoms/atom.py
--- 8-1/shelxfile/atoms/atom.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/atoms/atom.py	2022-07-26 20:37:30.000000000 +0000
@@ -1,7 +1,12 @@
+from contextlib import suppress
+from typing import Union, List
+
+with suppress(Exception):
+    from shelxfile import Shelxfile
 from shelxfile.misc.dsrmath import atomic_distance
 from shelxfile.misc.elements import get_atomic_number, get_radius_from_element
 from shelxfile.misc.misc import split_fvar_and_parameter, DEBUG, ParseSyntaxError, frac_to_cart, ParseUnknownParam
-from shelxfile.shelx.cards import PART, AFIX, RESI
+from shelxfile.shelx.cards import PART, AFIX, RESI, CELL, Restraints
 
 
 class Atom():
@@ -19,35 +24,35 @@ class Atom():
     _qpeakstr = '{:<5s} {:<2}{:>8.4f}  {:>8.4f}  {:>8.4f}  {:>9.5f}  {:<9.2f} {:<9.2f}'
     _fragatomstr = '{:<5s} {:>10.6f}  {:>10.6f}  {:>9.6f}'
 
-    def __init__(self, shx) -> None:
+    def __init__(self, shx: 'Shelxfile') -> None:
         self.shx = shx
-        self.cell = shx.cell
-        self.sfac_num = None
-        self.resi = None
-        self.part = None
-        self.afix = None
+        self.cell: CELL = shx.cell
+        self.sfac_num: int = 1
+        self.resi: Union[RESI, None] = None
+        self.part: Union[PART, None] = None
+        self.afix: Union[AFIX, None] = None
         self.name = 'name'  # Name without residue number like "C1"
         # Site occupation factor including free variable like 31.0
         self.sof = 11.0
         # fractional coordinates:
-        self.x = None
-        self.y = None
-        self.z = None
+        self.x: float = 0.0
+        self.y: float = 0.0
+        self.z: float = 0.0
         # cartesian coordinates:
-        self.xc = None
-        self.yc = None
-        self.zc = None
-        self.qpeak = False
-        self.peak_height = 0.0
-        self.uvals = [0.04, 0.0, 0.0, 0.0, 0.0]  # [U] or [U11 U22 U33 U23 U13 U12]
-        self.uvals_orig = [0.04, 0.0, 0.0, 0.0, 0.0]
-        self.frag_atom = False
-        self.restraints = []
+        self.xc: float = 0.0
+        self.yc: float = 0.0
+        self.zc: float = 0.0
+        self.qpeak: bool = False
+        self.peak_height: float = 0.0
+        self.uvals: List[float] = [0.04, 0.0, 0.0, 0.0, 0.0]  # [U] or [U11 U22 U33 U23 U13 U12]
+        self.uvals_orig: List[float] = [0.04, 0.0, 0.0, 0.0, 0.0]
+        self.frag_atom: bool = False
+        self.restraints: List[Restraints] = []
         self._line_numbers = None
-        self._occupancy = 1.0
-        self.molindex = 0
+        self._occupancy: float = 1.0
+        self.molindex: int = 0
         # Indicates if this atom is generated by symmetry:
-        self.symmgen = False
+        self.symmgen: bool = False
 
     def __eq__(self, other):
         return self.__str__() == other.__str__()
@@ -144,7 +149,7 @@ class Atom():
         self.sfac_num = sfac_num
         self.frac_coords = coords
         self.x, self.y, self.z = coords[0], coords[1], coords[2]
-        self.xc, self.yc, self.zc = frac_to_cart(self.frac_coords, self.cell)
+        self.xc, self.yc, self.zc = frac_to_cart(self.frac_coords, list(self.cell))
         self.part = part
         self.afix = afix
         self.resi = resi
@@ -152,7 +157,7 @@ class Atom():
         self.uvals = uvals
         self.symmgen = symmgen
 
-    def set_uvals(self, uvals: list):
+    def set_uvals(self, uvals: List):
         """
         Sets u values and checks if a free variable was used.
         """
@@ -168,7 +173,7 @@ class Atom():
                 fvar, uval = split_fvar_and_parameter(uvals[0])
                 self.shx.fvars.set_fvar_usage(fvar)
 
-    def parse_line(self, atline: list, list_of_lines: list, part: PART, afix: AFIX, resi: RESI):
+    def parse_line(self, atline: List, list_of_lines: List, part: PART, afix: AFIX, resi: RESI):
         """
         Parsers the text line of an atom from SHELXL to initialize the atom parameters.
         """
@@ -215,7 +220,7 @@ class Atom():
         self.x = x
         self.y = y
         self.z = z
-        self.xc, self.yc, self.zc = frac_to_cart(self.frac_coords, self.cell)
+        self.xc, self.yc, self.zc = frac_to_cart(self.frac_coords, list(self.cell))
         if abs(self.uvals[1]) > 0.0 and self.uvals[2] == 0.0 and self.shx.hklf:  # qpeaks are always behind hklf
             self.peak_height = uvals.pop()
             self.qpeak = True
@@ -308,7 +313,7 @@ class Atom():
             return (self.x, self.y, self.z)
 
     @frac_coords.setter
-    def frac_coords(self, coords: list):
+    def frac_coords(self, coords: List):
         self.x, self.y, self.z = coords
 
     @property
@@ -327,7 +332,7 @@ class Atom():
         """
         self.uvals = [0.04, 0.0, 0.0, 0.0, 0.0, 0.0]
 
-    def find_atoms_around(self, dist=1.2, only_part=0) -> list:
+    def find_atoms_around(self, dist=1.2, only_part=0) -> List['Atom']:
         """
         Finds atoms around the current atom.
         """
@@ -338,3 +343,13 @@ class Atom():
                 # only in special part and no q-peaks:
                 found.append(at)
         return found
+
+    def get_pivot_atom(self) -> Union['Atom', None]:
+        """
+        Returns the pivot atom (C1) of a riding hydrogen atom e.g. (H1, H2, or H3).
+           /H1
+        -C1--H2
+           \H3
+        """
+        pivots = self.find_atoms_around(dist=1.2)
+        return pivots[0] if pivots and self.afix.mn else None
diff -pruN 8-1/shelxfile/atoms/atoms.py 9-1/shelxfile/atoms/atoms.py
--- 8-1/shelxfile/atoms/atoms.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/atoms/atoms.py	2022-07-26 20:37:30.000000000 +0000
@@ -149,6 +149,34 @@ class Atoms():
         return atoms
 
     @property
+    def hydrogen_atoms(self) -> List[Atom]:
+        return [x for x in self.shx.atoms.all_atoms if x.is_hydrogen]
+
+    @property
+    def n_hydrogen_atoms(self) -> int:
+        return len(self.hydrogen_atoms)
+
+    @property
+    def n_anisotropic_atoms(self) -> int:
+        return len([x for x in self.all_atoms if sum(x.uvals[1:]) > 0.00001])
+
+    @property
+    def n_isotropic_atoms(self) -> int:
+        return len([x for x in self.all_atoms if sum(x.uvals[1:]) == 0.0])
+
+    @property
+    def n_anisotropic_hydrogen_atoms(self) -> int:
+        return len([x for x in self.hydrogen_atoms if sum(x.uvals[1:]) > 0.0001])
+
+    @property
+    def n_hydrogen_atoms_with_constr_u_val(self) -> int:
+        return len([x for x in self.hydrogen_atoms if x.uvals[0] < -1.0])
+
+    @property
+    def riding_atoms(self) -> List[Atom]:
+        return [x for x in self.hydrogen_atoms if x.afix]
+
+    @property
     def residues(self) -> list:
         """
         Returns a list of the residue numbers in the shelx file.
diff -pruN 8-1/shelxfile/fit/quatfit.py 9-1/shelxfile/fit/quatfit.py
--- 8-1/shelxfile/fit/quatfit.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/fit/quatfit.py	2022-07-26 20:37:30.000000000 +0000
@@ -353,16 +353,16 @@ def fit_fragment(fragment_atoms, source_
 
     Parameters
     ----------
-    fragment_atoms: list
+    fragment_atoms: List
         complete set of atoms of a fragment
-    source_atoms: list
+    source_atoms: List
         subsection of fragment atoms
-    target_atoms: list
+    target_atoms: List
         target position for source_atoms
 
     Returns
     -------
-    rotated_fragment: list
+    rotated_fragment: List
         list of coordinates from the fitted fragment
     rmsd: float
         RMSD (root mean square deviation)
diff -pruN 8-1/shelxfile/misc/dsrmath.py 9-1/shelxfile/misc/dsrmath.py
--- 8-1/shelxfile/misc/dsrmath.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/misc/dsrmath.py	2022-07-26 20:37:30.000000000 +0000
@@ -634,7 +634,7 @@ def id_generator(size=6, chars=string.as
     return ''.join(random.choice(chars) for _ in range(size))
 
 
-def atomic_distance(p1: list, p2: list, cell=None, shortest_dist=False):
+def atomic_distance(p1: List, p2: List, cell=None, shortest_dist=False):
     """
     p1 and p2 are x, y , z coordinates as list ['x', 'y', 'z']
     cell are the cell parameters as list: ['a', 'b', 'c', 'alpha', 'beta', 'gamma']
diff -pruN 8-1/shelxfile/misc/misc.py 9-1/shelxfile/misc/misc.py
--- 8-1/shelxfile/misc/misc.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/misc/misc.py	2022-07-26 20:37:30.000000000 +0000
@@ -15,10 +15,8 @@ import textwrap
 from math import radians, cos, sin, sqrt
 from shutil import get_terminal_size
 
-# TODO: Add verbose mode that doesn't fail but gives output like debug mode.
-# Without DEBUG, the parser should only fail if the file is realy damaged. With DEBUG enabled, the parser
-# fails even in harmless cases.
 from time import time, perf_counter
+from typing import List
 
 DEBUG = False
 PROFILE = False
@@ -86,7 +84,7 @@ def remove_file(filename, exit_dsr=False
         return True
 
 
-def find_line(inputlist: list, regex: str, start: int = None) -> int:
+def find_line(inputlist: List, regex: str, start: int = None) -> int:
     """
     returns the index number of the line where regex is found in the inputlist
     if stop is true, stop searching with first line found
@@ -97,14 +95,6 @@ def find_line(inputlist: list, regex: st
     :param start: line number where to start the search
     :param start: start searching at line start
     :type start: string or int
-    >>> inp = ['Hallo blub', 'foo bar blub', '123', '1 blub 2 3 4']
-    >>> find_line(inp, '.*blub.*')
-    0
-    >>> inp = [['foo'],['bar']]
-    >>> find_line(inp, '.*blub.*') #doctest: +REPORT_NDIFF +NORMALIZE_WHITESPACE +ELLIPSIS
-    Traceback (most recent call last):
-        ...
-    TypeError: expected string or ...
     """
     if start:
         start = int(start)
diff -pruN 8-1/shelxfile/refine/refine.py 9-1/shelxfile/refine/refine.py
--- 8-1/shelxfile/refine/refine.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/refine/refine.py	2022-07-26 20:37:30.000000000 +0000
@@ -123,7 +123,7 @@ class ShelxlRefine():
             return
         acta = ACTA(self.shx, self._acta_card.split())
         self.shx._reslist.insert(self.shx.unit.index + 1, ' ')
-        self.shx.acta = self.shx.assign_card(acta, self.shx.unit.index + 1)
+        self.shx.acta = self.shx._assign_card(acta, self.shx.unit.index + 1)
 
     def backup_shx_file(self):
         """
diff -pruN 8-1/shelxfile/shelx/cards.py 9-1/shelxfile/shelx/cards.py
--- 8-1/shelxfile/shelx/cards.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/shelx/cards.py	2022-07-26 20:37:30.000000000 +0000
@@ -1,6 +1,6 @@
 import re
 from math import cos, radians, sqrt
-from typing import List
+from typing import List, Union
 
 from shelxfile.misc.dsrmath import my_isnumeric, SymmetryElement
 from shelxfile.misc.misc import chunks, ParseParamError, ParseNumError, \
@@ -245,6 +245,9 @@ class Command():
                 words.append(x)
         return numparams, words
 
+    def set(self, value):
+        self.__init__(self._shx, value.split())
+
     @property
     def index(self):
         return self._shx.index_of(self)
@@ -303,7 +306,7 @@ class ANIS(Command):
 
 class MPLA(Command):
 
-    def __init__(self, shx, spline: list):
+    def __init__(self, shx, spline: List):
         """
         MPLA na atomnames
         """
@@ -315,7 +318,7 @@ class MPLA(Command):
 
 class MORE(Command):
 
-    def __init__(self, shx, spline: list):
+    def __init__(self, shx, spline: List):
         """
         MORE m[1]
         """
@@ -327,7 +330,7 @@ class MORE(Command):
 
 class CELL(Command):
 
-    def __init__(self, shx, spline: list):
+    def __init__(self, shx, spline: List):
         """
         CELL λ a b c α β γ
         """
@@ -376,7 +379,7 @@ class CELL(Command):
 
 class ZERR(Command):
 
-    def __init__(self, shx, spline: list):
+    def __init__(self, shx, spline: List):
         """
         ZERR Z esd(a) esd(b) esd(c) esd(α) esd(β) esd(γ)
         """
@@ -405,6 +408,8 @@ class AFIX(Command):
         p, _ = self._parse_line(spline)
         self.U = 10.08
         self.sof = 11.0
+        self.mn = None
+        self.d = None
         if len(p) > 0:
             self.mn = int(p[0])
         if len(p) > 1:
@@ -415,7 +420,7 @@ class AFIX(Command):
             self.U = p[3]
 
     def __bool__(self):
-        if self.mn > 0:
+        if self.mn and self.mn > 0:
             return True
         else:
             return False
@@ -634,6 +639,8 @@ class SHEL(Command):
         """
         super(SHEL, self).__init__(shx, spline)
         params, _ = self._parse_line(spline)
+        self.lowres = None
+        self.highres = None
         if len(params) > 0:
             self.lowres = params[0]
         if len(params) > 1:
@@ -676,6 +683,7 @@ class SPEC(Command):
         SPEC d[0.2]
         """
         super(SPEC, self).__init__(shx, spline)
+        self.d = None
         p, _ = self._parse_line(spline)
         if len(p) > 0:
             self.d = p[0]
@@ -690,6 +698,7 @@ class STIR(Command):
         super(STIR, self).__init__(shx, spline)
         p, _ = self._parse_line(spline)
         self.step = 0.01
+        self.sres = None
         if len(p) > 0:
             self.sres = p[0]
         if len(p) > 1:
@@ -745,15 +754,23 @@ class PLAN(Command):
         """
         PLAN npeaks[20] d1[#] d2[#]
         """
+        self.shx = shx
         super(PLAN, self).__init__(shx, spline)
+        self.npeaks = 20
+        self.d1 = None
+        self.d2 = None
         params, _ = self._parse_line(spline)
         if len(params) > 0:
-            self.npeaks = params[0]
+            self.npeaks = int(params[0])
         if len(params) > 1:
             self.d1 = params[1]
         if len(params) > 2:
             self.d2 = params[2]
 
+    def __repr__(self):
+        return f'PLAN {self.npeaks:,g}{" " if self.d1 else ""}{self.d1 if self.d1 is not None else ""}' \
+               f'{" " if self.d2 else ""}{self.d2 if self.d2 is not None else ""}'
+
 
 class FRAG(Command):
 
@@ -775,6 +792,8 @@ class FREE(Command):
         """
         super(FREE, self).__init__(shx, spline)
         _, atoms = self._parse_line(spline)
+        self.atom1 = None
+        self.atom2 = None
         try:
             self.atom1 = atoms[0]
             self.atom2 = atoms[1]
@@ -790,12 +809,15 @@ class FMAP(Command):
     def __init__(self, shx, spline: list):
         super(FMAP, self).__init__(shx, spline)
         params, _ = self._parse_line(spline)
+        self.code = None
+        self.axis = None
+        self.nl = None
         if len(params) > 0:
             self.code = params[0]
         if len(params) > 1:
             self.axis = params[1]
         if len(params) > 2:
-            self.axis = params[2]
+            self.nl = params[2]
 
 
 class MOVE(Command):
@@ -806,6 +828,8 @@ class MOVE(Command):
         """
         super(MOVE, self).__init__(shx, spline)
         params, _ = self._parse_line(spline)
+        self.dxdydz = None
+        self.sign = None
         if len(params) > 2:
             self.dxdydz = params[:3]
         if len(params) > 3:
@@ -834,6 +858,8 @@ class HTAB(Command):
         """
         super(HTAB, self).__init__(shx, spline)
         self.dh = None
+        self.donor = None
+        self.acceptor = None
         dh, atoms = self._parse_line(spline)
         if dh:
             self.dh = dh[0]
@@ -876,7 +902,7 @@ class ACTA(Command):
 
     def _as_str(self):
         if self.twotheta:
-            return "ACTA {:,g}".format(self.twotheta[0])
+            return f"ACTA {self.twotheta[0]:,g}"
         else:
             return "ACTA"
 
@@ -895,10 +921,12 @@ class BLOC(Command):
         """
         super(BLOC, self).__init__(shx, spline)
         params, self.atoms = self._parse_line(spline)
-        if len(params) > 1:
-            self.n2 = params[1]
+        self.n1 = None
+        self.n2 = None
         if len(params) > 0:
             self.n1 = params[0]
+        if len(params) > 1:
+            self.n2 = params[1]
         self.shx = shx
 
 
@@ -1406,8 +1434,8 @@ class HFIX(Command):
         self.params, self.atoms = self._parse_line(spline, intnums=True)
 
     def __repr__(self):
-        return "HFIX {} {}".format(" ".join([str(x) for x in self.params]) if self.params else '',
-                                   " ".join(self.atoms) if self.atoms else '')
+        return f"HFIX {' '.join([str(x) for x in self.params]) if self.params else ''} " \
+               f"{' '.join(self.atoms) if self.atoms else ''}"
 
 
 class HKLF(Command):
@@ -1741,7 +1769,9 @@ class SFACTable():
 
 class UNIT(Command):
 
-    def __init__(self, shx, spline: list):
+    values: List[Union[int, float]]
+
+    def __init__(self, shx, spline: List):
         """
         UNIT n1 n2 ...
         """
@@ -1775,6 +1805,7 @@ class BASF(Command):
     BASF scale factors
     BASF can occour in multiple lines.
     """
+    scale_factors: List[Union[int, float]]
 
     def __init__(self, shx, spline):
         super(BASF, self).__init__(shx, spline)
@@ -1786,7 +1817,7 @@ class BASF(Command):
 
 class TWIN(Command):
 
-    def __init__(self, shx, spline: list):
+    def __init__(self, shx, spline: List):
         """
         TWIN 3x3 matrix [-1 0 0 0 -1 0 0 0 -1] N[2]
         +N     -N  m = |N|
@@ -1821,7 +1852,7 @@ class WGHT(Command):
         w = q / [ σ²(Fo²) + (a*P)² + b*P + d + e*sin(θ)/$lambda; ]
 
         WGHT a[0.1] b[0] c[0] d[0] e[0] f[.33333]
-        Usually only WGHT a b
+        Usually only 'WGHT a b' is used
         """
         super(WGHT, self).__init__(shx, spline)
         self.shx = shx
diff -pruN 8-1/shelxfile/shelx/shelx.py 9-1/shelxfile/shelx/shelx.py
--- 8-1/shelxfile/shelx/shelx.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/shelxfile/shelx/shelx.py	2022-07-26 20:37:30.000000000 +0000
@@ -351,7 +351,7 @@ class Shelxfile():
                 # continue
             if line.startswith('RESI'):
                 self.resi = RESI(self, spline)
-                self.assign_card(self.resi, line_num)
+                self._assign_card(self.resi, line_num)
                 if self.resi.residue_number > 0:
                     self.residues.append(self.resi)
                 continue
@@ -364,7 +364,7 @@ class Shelxfile():
                 # continue
             if line.startswith('PART'):
                 self.part = PART(self, spline)
-                self.assign_card(self.part, line_num)
+                self._assign_card(self.part, line_num)
                 continue
             # collect AFIX:
             if line.startswith(('END', 'HKLF')) and self.afix:
@@ -373,48 +373,48 @@ class Shelxfile():
                     print('AFIX in line {} was not closed'.format(line_num + 1))
             elif line.startswith('AFIX'):
                 self.afix = AFIX(self, spline)
-                self.assign_card(self.afix, line_num)
+                self._assign_card(self.afix, line_num)
             elif self.is_atom(line):
                 # A SHELXL atom:
                 # F9    4    0.395366   0.177026   0.601546  21.00000   0.03231  ( 0.03248 =
                 #            0.03649  -0.00522  -0.01212   0.00157 )
                 a = Atom(self)
                 a.parse_line(spline, list_of_lines, part=self.part, afix=self.afix, resi=self.resi)
-                self.append_card(self.atoms, a, line_num)
+                self._append_card(self.atoms, a, line_num)
             elif word == 'SADI':
                 # SADI s[0.02] pairs of atoms
                 # or SADI
                 if len(spline) == 1:
                     self.global_sadi = line_num
-                self.append_card(self.restraints, SADI(self, spline), line_num)
+                self._append_card(self.restraints, SADI(self, spline), line_num)
             elif word == 'DFIX':
                 # DFIX d s[0.02] atom pairs
-                self.append_card(self.restraints, DFIX(self, spline), line_num)
+                self._append_card(self.restraints, DFIX(self, spline), line_num)
             elif word == 'SIMU':
                 # SIMU s[0.04] st[0.08] dmax[2.0] atomnames
-                self.append_card(self.restraints, SIMU(self, spline), line_num)
+                self._append_card(self.restraints, SIMU(self, spline), line_num)
             elif word == 'DELU':
                 # DELU s1[0.01] s2[0.01] atomnames
-                self.append_card(self.restraints, DELU(self, spline), line_num)
+                self._append_card(self.restraints, DELU(self, spline), line_num)
             elif word == 'RIGU':
                 # RIGU s1[0.004] s2[0.004] atomnames
-                self.append_card(self.restraints, RIGU(self, spline), line_num)
+                self._append_card(self.restraints, RIGU(self, spline), line_num)
             elif word == 'BASF':
                 # BASF scale factors
-                self.assign_card(BASF(self, spline), line_num)
+                self._assign_card(BASF(self, spline), line_num)
             elif word == 'HFIX':
                 # HFIX mn U[#] d[#] atomnames
-                self.append_card(self.hfixes, HFIX(self, spline), line_num)
+                self._append_card(self.hfixes, HFIX(self, spline), line_num)
             elif word == 'DANG':
                 # DANG d s[0.04] atom pairs
-                self.append_card(self.restraints, DANG(self, spline), line_num)
+                self._append_card(self.restraints, DANG(self, spline), line_num)
             elif word == 'EADP':
-                self.append_card(self.restraints, EADP(self, spline), line_num)
+                self._append_card(self.restraints, EADP(self, spline), line_num)
             elif line[:3] == 'REM':
                 if dsr_regex.match(line):
                     self.dsrlines.append(" ".join(spline))
                     self.dsrline_nums.extend(list_of_lines)
-                self.append_card(self.rem, REM(self, spline), line_num)
+                self._append_card(self.rem, REM(self, spline), line_num)
                 self._get_residuals(spline, line)
             elif word == 'AFIX':
                 # nothing to do
@@ -424,7 +424,7 @@ class Shelxfile():
                 if not lastcard == 'TITL' and DEBUG:
                     print('TITL is missing.')
                 self.cell = CELL(self, spline)
-                self.assign_card(self.cell, line_num)
+                self._assign_card(self.cell, line_num)
                 self._a, self._b, self._c, self._alpha, self._beta, self._gamma = self.cell
                 self.orthogonal_matrix = OrthogonalMatrix(*self.cell)
                 self.wavelen = self.cell.wavelen
@@ -444,14 +444,14 @@ class Shelxfile():
                         self.Z = 1
                         if DEBUG:
                             print('Z value is zero.')
-                    self.assign_card(self.zerr, line_num)
+                    self._assign_card(self.zerr, line_num)
                 lastcard = 'ZERR'
             elif word == "LATT":
                 # LATT N[1]
                 # 1=P, 2=I, 3=rhombohedral obverse on hexagonal axes, 4=F, 5=A, 6=B, 7=C.
                 # negative is non-centrosymmetric
                 self.latt = LATT(self, spline)
-                self.assign_card(self.latt, line_num)
+                self._assign_card(self.latt, line_num)
                 if not lastcard == 'ZERR' and DEBUG:
                     print('*** ZERR instruction is missing! ***')
                 if self.latt.centric:
@@ -501,7 +501,7 @@ class Shelxfile():
                     raise ParseOrderError
                 if self.sfac_table:
                     try:
-                        self.unit = self.assign_card(UNIT(self, spline), line_num)
+                        self.unit = self._assign_card(UNIT(self, spline), line_num)
                     except ValueError:
                         if DEBUG:
                             print('*** Non-numeric value in SFAC instruction! ***')
@@ -515,7 +515,7 @@ class Shelxfile():
             elif word in ['L.S.', 'CGLS']:
                 # CGLS nls[0] nrf[0] nextra[0]
                 # L.S. nls[0] nrf[0] nextra[0]
-                self.cycles = self.assign_card(LSCycles(self, spline), line_num)
+                self.cycles = self._assign_card(LSCycles(self, spline), line_num)
             elif word == "LIST":
                 # LIST m[#] mult[1] (mult is for list 4 only)
                 self.list = int(spline[1])
@@ -523,7 +523,7 @@ class Shelxfile():
                 # FVAR osf[1] free variables
                 for fvvalue in spline[1:]:
                     fvarnum += 1
-                    self.append_card(self.fvars, FVAR(fvarnum, float(fvvalue)), line_num)
+                    self._append_card(self.fvars, FVAR(fvarnum, float(fvvalue)), line_num)
                     if self.fvars not in self._reslist:
                         self._reslist[line_num] = self.fvars
                     else:
@@ -532,25 +532,25 @@ class Shelxfile():
                 # ANIS n or ANIS names
                 # Must be before Atom(), to know which atom is anis.
                 self.anis = ANIS(self, spline)
-                self.assign_card(self.anis, line_num)
+                self._assign_card(self.anis, line_num)
             elif word == 'WGHT':
                 # WGHT a[0.1] b[0] c[0] d[0] e[0] f[.33333]
                 if self.end:
-                    self.wght_suggested = self.assign_card(WGHT(self, spline), line_num)
+                    self.wght_suggested = self._assign_card(WGHT(self, spline), line_num)
                     continue
-                self.wght = self.assign_card(WGHT(self, spline), line_num)
+                self.wght = self._assign_card(WGHT(self, spline), line_num)
             elif word == 'ACTA':
                 # ACTA 2θfull[#] -> optional parameter NOHKL
                 self.acta = ACTA(self, spline)
-                self.assign_card(self.acta, line_num)
+                self._assign_card(self.acta, line_num)
             elif word == 'DAMP':
                 # DAMP damp[0.7] limse[15]
                 self.damp = DAMP(self, spline)
-                self.assign_card(self.damp, line_num)
+                self._assign_card(self.damp, line_num)
             elif word == 'ABIN':
                 # ABIN n1 n2
                 self.abin = ABIN(self, spline)
-                self.assign_card(self.abin, line_num)
+                self._assign_card(self.abin, line_num)
             elif word == 'ANSC':
                 # ANSC six coefficients
                 if len(spline) == 7:
@@ -562,37 +562,37 @@ class Shelxfile():
             elif word == 'BIND':
                 # BIND atom1 atom2
                 if len(spline) == 3:
-                    self.append_card(self.bind, BIND(self, spline), line_num)
+                    self._append_card(self.bind, BIND(self, spline), line_num)
             elif word == 'BLOC':
                 # BLOC n1 n2 atomnames
-                self.append_card(self.bloc, BLOC(self, spline), line_num)
+                self._append_card(self.bloc, BLOC(self, spline), line_num)
             elif word == 'BOND':
                 # BOND atomnames
-                self.append_card(self.bonds, BOND(self, spline), line_num)
+                self._append_card(self.bonds, BOND(self, spline), line_num)
             elif word == 'BUMP':
                 # BUMP s [0.02]
-                self.append_card(self.restraints, BUMP(self, spline), line_num)
+                self._append_card(self.restraints, BUMP(self, spline), line_num)
             elif word == 'CHIV':
                 # CHIV V[0] s[0.1] atomnames
-                self.append_card(self.restraints, CHIV(self, spline), line_num)
+                self._append_card(self.restraints, CHIV(self, spline), line_num)
             elif word == 'CONF':
                 # CONF atomnames max_d[1.9] max_a[170]
                 self.conf = CONF(self, spline)
-                self.assign_card(self.conf, line_num)
+                self._assign_card(self.conf, line_num)
             elif word == 'CONN':
                 # CONN bmax[12] r[#] atomnames or CONN bmax[12]
                 # bonded are d < (r1 + r2 + 0.5) Å
                 self.conn = CONN(self, spline)
-                self.assign_card(self.conn, line_num)
+                self._assign_card(self.conn, line_num)
             elif word == 'DEFS':
                 # DEFS sd[0.02] sf[0.1] su[0.01] ss[0.04] maxsof[1]
                 self.defs = DEFS(self, spline)
-                self.assign_card(self.defs, line_num)
+                self._assign_card(self.defs, line_num)
             elif word == 'DISP':
                 # DISP E f' f"[#] mu[#]
                 if not lastcard == 'SFAC':
                     raise ParseOrderError
-                self.append_card(self.disp, DISP(self, spline), line_num)
+                self._append_card(self.disp, DISP(self, spline), line_num)
             elif word == 'EQIV':
                 # EQIV $n symmetry operation
                 # TODO: implement EQUIV class
@@ -603,12 +603,12 @@ class Shelxfile():
                 self.exti = float(spline[1])
             elif word == 'EXYZ':
                 # EXYZ atomnames
-                self.append_card(self.restraints, EXYZ(self, spline), line_num)
+                self._append_card(self.restraints, EXYZ(self, spline), line_num)
             elif word == 'FRAG':
                 # FRAG code[17] a[1] b[1] c[1] α[90] β[90] γ[90]
                 if len(spline) == 8:
                     self.frag = FRAG(self, spline)
-                    self.assign_card(self.frag, line_num)
+                    self._assign_card(self.frag, line_num)
             elif word == 'FEND':
                 # FEND (must follow FRAG)
                 if not self.frag:
@@ -616,28 +616,28 @@ class Shelxfile():
                 self.frag = None  # Turns frag mode off.
             elif word == 'FLAT':
                 # FLAT s[0.1] four or more atoms
-                self.append_card(self.restraints, FLAT(self, spline), line_num)
+                self._append_card(self.restraints, FLAT(self, spline), line_num)
             elif word == 'FREE':
                 # FREE atom1 atom2
-                self.append_card(self.free, FREE(self, spline), line_num)
+                self._append_card(self.free, FREE(self, spline), line_num)
             elif word == 'GRID':
                 # GRID sl[#] sa[#] sd[#] dl[#] da[#] dd[#]
                 self.grid = GRID(self, spline)
-                self.assign_card(self.grid, line_num)
+                self._assign_card(self.grid, line_num)
             elif word == 'HKLF':
                 # HKLF N[0] S[1] r11...r33[1 0 0 0 1 0 0 0 1] sm[1] m[0]
                 self.hklf = HKLF(self, spline)
-                self.assign_card(self.hklf, line_num)
+                self._assign_card(self.hklf, line_num)
             elif line.startswith('END'):
                 # END (after HKLF or ends an include file)
                 self.end = True
             elif word == 'HTAB':
                 # HTAB dh[2.0]  or  HTAB donor-atom acceptor-atom
                 self.htab = HTAB(self, spline)
-                self.assign_card(self.htab, line_num)
+                self._assign_card(self.htab, line_num)
             elif word == 'ISOR':
                 # ISOR s[0.1] st[0.2] atomnames
-                self.append_card(self.restraints, ISOR(self, spline), line_num)
+                self._append_card(self.restraints, ISOR(self, spline), line_num)
             elif word == 'LAUE':
                 # LAUE E
                 # I completely do not understand the LAUE instruction description in the manual!
@@ -645,26 +645,26 @@ class Shelxfile():
             elif word == 'MERG':
                 # MERG n[2]
                 self.merg = MERG(self, spline)
-                self.assign_card(self.merg, line_num)
+                self._assign_card(self.merg, line_num)
             elif word == 'MORE':
                 # MORE m[1]
                 self.more = MORE(self, spline)
-                self.assign_card(self.more, line_num)
+                self._assign_card(self.more, line_num)
             elif word == 'FMAP':
                 # FMAP code[2] axis[#] nl[53]
                 self.fmap = FMAP(self, spline)
-                self.assign_card(self.fmap, line_num)
+                self._assign_card(self.fmap, line_num)
             elif word == 'MOVE':
                 # MOVE dx[0] dy[0] dz[0] sign[1]
                 self.move = MOVE(self, spline)
-                self.assign_card(self.move, line_num)
+                self._assign_card(self.move, line_num)
             elif word == 'MPLA':
                 # MPLA na atomnames
                 self.mpla = MPLA(self, spline)
-                self.assign_card(self.mpla, line_num)
+                self._assign_card(self.mpla, line_num)
             elif word == 'NCSY':
                 # NCSY DN sd[0.1] su[0.05] atoms
-                self.append_card(self.restraints, NCSY(self, spline), line_num)
+                self._append_card(self.restraints, NCSY(self, spline), line_num)
             elif word == 'NEUT':
                 # NEUT
                 if not lastcard == 'SYMM':
@@ -676,37 +676,37 @@ class Shelxfile():
             elif word == 'PLAN':
                 # PLAN npeaks[20] d1[#] d2[#]
                 self.plan = PLAN(self, spline)
-                self.assign_card(self.plan, line_num)
+                self._assign_card(self.plan, line_num)
             elif word == 'PRIG':
                 # PRIG p[#]
                 self.prig = PRIG(self, spline)
-                self.assign_card(self.prig, line_num)
+                self._assign_card(self.prig, line_num)
             elif word == 'RTAB':
                 # RTAB codename atomnames  -->  codename: e.g. 'omeg' gets tabualted in the lst
-                self.append_card(self.rtab, RTAB(self, spline), line_num)
+                self._append_card(self.rtab, RTAB(self, spline), line_num)
             elif word == 'SAME':
                 # SAME s1[0.02] s2[0.04] atomnames
-                self.append_card(self.restraints, SAME(self, spline), line_num)
+                self._append_card(self.restraints, SAME(self, spline), line_num)
             elif word == 'SHEL':
                 # SHEL lowres[infinite] highres[0]
                 self.shel = SHEL(self, spline)
-                self.assign_card(self.shel, line_num)
+                self._assign_card(self.shel, line_num)
             elif word == 'SIZE':
                 # SIZE dx dy dz
                 self.size = SIZE(self, spline)
-                self.assign_card(self.size, line_num)
+                self._assign_card(self.size, line_num)
             elif word == 'SPEC':
                 # SPEC del[0.2]
                 if len(spline) > 1:
                     self.spec = SPEC(self, spline)
-                    self.assign_card(self.spec, line_num)
+                    self._assign_card(self.spec, line_num)
             elif word == 'STIR':
                 # STIR sres step[0.01]   -> stepwise improvement in the resolution sres
                 self.stir = STIR(self, spline)
-                self.assign_card(self.stir, line_num)
+                self._assign_card(self.stir, line_num)
             elif word == 'SUMP':
                 # SUMP c sigma c1 m1 c2 m2 ...
-                self.append_card(self.sump, SUMP(self, spline), line_num)
+                self._append_card(self.sump, SUMP(self, spline), line_num)
             elif word == 'SWAT':
                 # SWAT g[0] U[2]
                 self.swat = spline[1:]
@@ -717,24 +717,24 @@ class Shelxfile():
             elif word == 'TWIN':
                 # TWIN 3x3 matrix [-1 0 0 0 -1 0 0 0 -1] N[2]
                 self.twin = TWIN(self, spline)
-                self.assign_card(self.twin, line_num)
+                self._assign_card(self.twin, line_num)
             elif word == 'TWST':
                 # TWST N[0] (N[1] after SHELXL-2018/3)
                 if len(spline) > 1:
                     self.twst = TWST(self, spline)
-                    self.assign_card(self.twst, line_num)
+                    self._assign_card(self.twst, line_num)
             elif word == 'WIGL':
                 # WIGL del[0.2] dU[0.2]
                 self.wigl = WIGL(self, spline)
-                self.assign_card(self.wigl, line_num)
+                self._assign_card(self.wigl, line_num)
             elif word == 'WPDB':
                 # WPDB n[1]
                 self.wpdb = WPDB(self, spline)
-                self.assign_card(self.wpdb, line_num)
+                self._assign_card(self.wpdb, line_num)
             elif word == 'XNPD':
                 # XNPD Umin[-0.001]
                 self.xnpd = XNPD(self, spline)
-                self.assign_card(self.xnpd, line_num)
+                self._assign_card(self.xnpd, line_num)
             elif word == 'BEDE':
                 # Later...
                 continue
@@ -770,7 +770,7 @@ class Shelxfile():
         sfac_num = self.elem2sfac(element)
         a.set_atom_parameters(name=name, sfac_num=sfac_num, coords=coordinates,
                               part=part, afix=afix, resi=resi, site_occupation=sof, uvals=uvals)
-        self.append_card(self.atoms, a, 0)
+        self._append_card(self.atoms, a, 0)
 
     def frac_to_cart(self, coordinates: list) -> Array:
         """
@@ -841,7 +841,7 @@ class Shelxfile():
     def _weight_converged(self, diff):
         return diff == [0.0, 0.0]
 
-    def append_card(self, obj, card, line_num):
+    def _append_card(self, obj, card, line_num):
         """
         Appends SHELX card to an object list, e.g. self.restraints and
         assigns the line_num in reslist with the card instance.
@@ -850,7 +850,7 @@ class Shelxfile():
         self._reslist[line_num] = card
         return card
 
-    def assign_card(self, card, line_num):
+    def _assign_card(self, card, line_num):
         self._reslist[line_num] = card
         return card
 
@@ -900,11 +900,12 @@ class Shelxfile():
             return ''
         return elem
 
-    def add_line(self, linenum: int, obj):
+    def add_line(self, linenum: int, line: str):
         """
         Adds a new SHELX card to the reslist after linenum.
+        e.g. shx.add_line(shx.unit.position, 'ANIS')
         """
-        self._reslist.insert(linenum + 1, obj)
+        self._reslist.insert(linenum + 1, line)
 
     def replace_line(self, obj, new_line: str):
         """
diff -pruN 8-1/tests/test_atoms.py 9-1/tests/test_atoms.py
--- 8-1/tests/test_atoms.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/tests/test_atoms.py	2022-07-26 20:37:30.000000000 +0000
@@ -141,8 +141,9 @@ class TestAtoms(TestCase):
                          self.shx.atoms.get_atom_by_id(40).cart_coords)
 
     def test_cartesian_from_method(self):
-        self.assertEqual([round(x, 14) for x in frac_to_cart(self.shx.atoms.get_atom_by_id(40).frac_coords, list(self.shx.cell))],
-                          self.shx.atoms.get_atom_by_id(40).cart_coords)
+        self.assertEqual(
+            [round(x, 14) for x in frac_to_cart(self.shx.atoms.get_atom_by_id(40).frac_coords, list(self.shx.cell))],
+            self.shx.atoms.get_atom_by_id(40).cart_coords)
 
     def test_frac_coords(self):
         self.assertEqual((0.028576, 0.234542, 0.337234), self.shx.atoms.get_atom_by_id(40).frac_coords)
@@ -176,3 +177,46 @@ class TestAtoms(TestCase):
 
     def test_part_sof(self):
         self.assertEqual(-31.0, self.shx.atoms.get_atom_by_id(40).part.sof)
+
+    def test_get_pivot_atom(self):
+        self.assertEqual('C34', self.shx.atoms.all_atoms[45].get_pivot_atom().name)
+
+    def test_get_pivot_atom_of_fluorine(self):
+        # This atom should not have a pivot atom, because it is heavy and not in an AFIX:
+        self.assertEqual('F2', self.shx.atoms.all_atoms[4].name)
+        self.assertEqual(None, self.shx.atoms.all_atoms[4].get_pivot_atom())
+
+    def test_hydrogen_atoms(self):
+        self.assertEqual('[Atom ID: 134, Atom ID: 141, Atom ID: 148]', str(self.shx.atoms.hydrogen_atoms[:3]))
+
+    def test_riding_atoms(self):
+        self.assertEqual('[Atom ID: 134, Atom ID: 141, Atom ID: 148]', str(self.shx.atoms.riding_atoms[:3]))
+
+
+class TestRidingAtoms(TestCase):
+    def setUp(self) -> None:
+        self.shx = Shelxfile()
+        self.shx.read_file('tests/resources/sad-final.res')
+
+    def test_hydrogen_atoms(self):
+        # Returns the list of hydrogen atoms, regardless of their model
+        self.assertEqual('[Atom ID: 71, Atom ID: 75, Atom ID: 76]', str(self.shx.atoms.hydrogen_atoms[3:6]))
+
+    def test_riding_atoms(self):
+        # Returns only riding atoms, therefore different IDs than above
+        self.assertEqual('[Atom ID: 75, Atom ID: 76, Atom ID: 77]', str(self.shx.atoms.riding_atoms[3:6]))
+
+    def test_number_of_anisotropic_atoms(self):
+        self.assertEqual(79, self.shx.atoms.n_anisotropic_atoms)
+
+    def test_number_of_isotropic_atoms(self):
+        self.assertEqual(49, self.shx.atoms.n_isotropic_atoms)
+
+    def test_number_of_hydrogen_atoms(self):
+        self.assertEqual(49, self.shx.atoms.n_hydrogen_atoms)
+
+    def test_number_of_anisotropic_hydrogen_atoms(self):
+        self.assertEqual(0, self.shx.atoms.n_anisotropic_hydrogen_atoms)
+
+    def test_number_of_hydrogen_adtoms_with_constrained_u_values(self):
+        self.assertEqual(49, self.shx.atoms.n_hydrogen_atoms_with_constr_u_val)
\ No newline at end of file
diff -pruN 8-1/tests/test_cards.py 9-1/tests/test_cards.py
--- 8-1/tests/test_cards.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/tests/test_cards.py	2022-07-26 20:37:30.000000000 +0000
@@ -2,7 +2,7 @@ from pathlib import Path
 from unittest import TestCase
 
 from shelxfile.refine.refine import ShelxlRefine
-from shelxfile.shelx.cards import RESI, ANIS, ABIN, SADI, DFIX
+from shelxfile.shelx.cards import RESI, ANIS, ABIN, SADI, DFIX, AFIX
 from shelxfile.shelx.shelx import Shelxfile
 
 
@@ -118,6 +118,12 @@ class TestWGHT(TestCase):
     def test_wght_differene(self):
         self.assertEqual([0.0, 0.0], self.shx.wght.difference())
 
+    def test_wght_set(self):
+        self.shx.wght.set('WGHT 0.1 99')
+        self.assertEqual('WGHT   0.1 99.0', str(self.shx.wght))
+        self.assertEqual(0.1, self.shx.wght.a)
+        self.assertEqual(99.0, self.shx.wght.b)
+
 
 class TestANIS(TestCase):
 
@@ -202,4 +208,42 @@ class TestwithDEFS(TestCase):
     def test_DFIX_with_s(self):
         a = DFIX(self.shx, 'DFIX 1.45 0.022 C1 C2 C2 C3 C3 C4'.split())
         self.assertEqual(1.45, a.d)
-        self.assertEqual(0.022, a.s)
\ No newline at end of file
+        self.assertEqual(0.022, a.s)
+
+
+class TestPLAN(TestCase):
+    def setUp(self) -> None:
+        self.shx = Shelxfile()
+        self.shx.read_file('tests/resources/p21c.res')
+
+    def test_plan__repr__(self):
+        self.assertEqual('PLAN 20', self.shx.plan.__repr__())
+
+    def test_set_plan_value(self):
+        self.shx.plan.set('PLAN 23')
+        self.assertEqual('PLAN 23', self.shx.plan.__repr__())
+
+    def test_set_plan_all_values(self):
+        self.shx.plan.set('PLAN 23 1.34 1.1')
+        self.assertEqual('PLAN 23 1.34 1.1', self.shx.plan.__repr__())
+
+
+class TestAFIX(TestCase):
+
+    def test_afix_n(self):
+        a = AFIX(Shelxfile(), 'AFIX 33'.split())
+        self.assertEqual(33, a.mn)
+        self.assertEqual(None, a.d)
+        self.assertEqual(10.08, a.U)
+        self.assertEqual(11.0, a.sof)
+        self.assertEqual(True, a.__bool__())
+
+    def test_afix_zero(self):
+        a = AFIX(Shelxfile(), 'AFIX 0'.split())
+        self.assertEqual(0, a.mn)
+        self.assertEqual(False, a.__bool__())
+
+    def test_afix_empty(self):
+        a = AFIX(Shelxfile(), 'AFIX'.split())
+        self.assertEqual(None, a.mn)
+        self.assertEqual(False, a.__bool__())
diff -pruN 8-1/tests/test_misc.py 9-1/tests/test_misc.py
--- 8-1/tests/test_misc.py	2022-07-08 13:40:34.000000000 +0000
+++ 9-1/tests/test_misc.py	2022-07-26 20:37:30.000000000 +0000
@@ -1,6 +1,6 @@
 from unittest import TestCase
 
-from shelxfile.misc.misc import range_resolver, wrap_line, multiline_test, chunks
+from shelxfile.misc.misc import range_resolver, wrap_line, multiline_test, chunks, find_line
 
 
 class Test(TestCase):
@@ -39,3 +39,15 @@ class Test(TestCase):
         self.assertEqual([[1], [2], [3], [4], [5], [6], [7], [8], [9], [0], ['a'], ['b'], ['c'], ['d'], ['e'], ['f']],
                          chunks(l, 1))
         self.assertEqual([[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 'a', 'b', 'c', 'd', 'e', 'f']], chunks(l, 50))
+
+
+class Testfind_line(TestCase):
+    def test_find_line_found_something(self):
+        inp = ['Hallo blub', 'foo bar blub', '123', '1 blub 2 3 4']
+        self.assertEqual(0, find_line(inp, '.*blub.*'))
+
+    def test_dont_find_something(self):
+        inp = [['foo'], ['bar']]
+
+        with self.assertRaises(TypeError) as e:
+            find_line(inp, '.*blub.*')
