diff --git a/doc/concepts/cable_cell.rst b/doc/concepts/cable_cell.rst
index 4c5d27a35785cc53edad8c6e06e62a369f88dcbe..6ce770812f847c8971bdcb1a30b03cb3131fc54b 100644
--- a/doc/concepts/cable_cell.rst
+++ b/doc/concepts/cable_cell.rst
@@ -10,11 +10,12 @@ Arbor cable cells are constructed from a morphology and a label dictionary,
 and provide a rich interface for specifying the cell's dynamics.
 
 .. note::
-    The cable cell does not have *one* dedicated page, it has a few more! This page describes how to build a full description of a cable cell, based on three components that are broken out into their own pages:
+    The cable cell has more than *one* dedicated page, it has a few more! This page describes how to build a full
+    description of a cable cell, based on three components that are broken out into their own pages:
 
-    * :ref:`morphology descriptions <morph-morphology>`;
-    * :ref:`label dictionary <labels-dictionary>` that are used to describe :ref:`locations <labels-locset>` and :ref:`regions <labels-region>` on a cell;
-    * :ref:`mechanisms <mechanisms>`.
+    * :ref:`Morphology descriptions <morph-morphology>`
+    * :ref:`Label dictionaries <labels-dictionary>`
+    * :ref:`Mechanisms <mechanisms>`
 
     It can be helpful to consult those pages for some of the sections of this page.
 
@@ -24,13 +25,13 @@ Decoration
 ----------------
 
 A cable cell is *decorated* by specifying the distribution and placement of dynamics
-on the cell to produce a full description
-of a cell morphology and its dynamics with all information required to build
-a standalone single-cell model, or as part of a larger network.
+on the cell. The decorations, coupled with a description of a cell morphology, are all
+that is required to build a standalone single-cell model, or a cell that is part of
+a larger network.
 
-Decoration uses region and locset descriptions, with
-their respective use for this purpose reflected in the two broad classes
-of dynamics in Arbor:
+Decorations use :ref:`region <labels-region>` and :ref:`locset <labels-locset>`
+descriptions, with their respective use for this purpose reflected in the two broad
+classes of dynamics in Arbor:
 
 * *Painted dynamics* are applied to regions of a cell, and are associated with
   an area of the membrane or volume of the cable.
@@ -163,7 +164,7 @@ Every mechanism is described by a string with its name, and
 an optional list of key-value pairs that define its range parameters.
 
 Because a global parameter is fixed over the entire spatial extent
-of a density mechanism, a new mechanism has to created for every
+of a density mechanism, a new mechanism has to be created for every
 combination of global parameter values.
 
 Take for example a mechanism passive leaky dynamics:
diff --git a/doc/concepts/cell.rst b/doc/concepts/cell.rst
index 20658f63c45428454f09f550a0e19e6c9a91a05a..5f9865bfd8d138b0d9976fd4e55af0c6f7c443e1 100644
--- a/doc/concepts/cell.rst
+++ b/doc/concepts/cell.rst
@@ -76,23 +76,28 @@ Cell kinds
    * **Gap Junction Sites**: These refer to the sites of :ref:`gap junctions <modelgapjunctions>`.
      They are declared by specifying a location on a branch of the cell.
 
-   Because cable cells are the main cell kind in Arbor and have more properties than listed here, they have a :ref:`dedicated page <cablecell>`.
+   Because cable cells are the main cell kind in Arbor and have more properties than listed here, they have a
+   :ref:`dedicated page <cablecell>`.
 
 2. **LIF Cells**
 
-   A single compartment leaky integrate and fire neuron with one **source** and one **target**.
-   LIF cells does not support adding additional **sources** or **targets** or gap junctions.
+   LIF cells are single compartment leaky integrate and fire neurons with one **source** and one **target**.
+   LIF cells do not support adding additional **sources** or **targets**. They do not support **gap junctions**.
+   They are typically used to simulate point-neuron networks.
 
 3. **Spiking Cells**
 
-   Spike source from values inserted via a `schedule description`. It is a point neuron with one built-in **source** and no **targets**.
-   It does not support adding additional **sources** or **targets**. It does not support gap junctions.
+   Spiking cells act as spike sources from values inserted via a `schedule description`.
+   They are point neurons with one built-in **source** and no **targets**.
+   They do not support adding additional **sources** or **targets**. They do not support **gap junctions**.
 
 4. **Benchmark Cells**
 
-   Proxy cell used for benchmarking, and used by developers to benchmark the spike exchange and event delivery infrastructure.
+   Benchmark cells are proxy cells used for benchmarking, and used by developers to benchmark the spike exchange and
+   event delivery infrastructure.
 
-Most Arbor users will want to use the cable cell, because it's the only cell kind that supports complex morphologies and user-defined mechanisms. See cable cells :ref:`dedicated page <cablecell>`. The LIF cell can be used to build networks with point-neurons.
+Most Arbor users will want to use the cable cell, which is the only cell kind that supports complex morphologies
+and user-defined mechanisms. You can visit the :ref:`cable cell page <cablecell>` for more information.
 
 API
 ---
diff --git a/doc/concepts/index.rst b/doc/concepts/index.rst
index a848bd49744a271a1ee12b4d3eb11980fd8d51a8..8c4399749b5ffe30a9dc0a482806c948ddf8f7e3 100644
--- a/doc/concepts/index.rst
+++ b/doc/concepts/index.rst
@@ -3,7 +3,7 @@
 Concepts
 ====================
 
-To understand how to use Arbor, it is helpful if you understand some of its concepts.
+To learn how to use Arbor, it is helpful to understand some of its concepts.
 
 Arbor's design aims to enable scalability through abstraction.
 
@@ -17,6 +17,10 @@ To be able to simulate a model, three basic steps need to be considered:
 2. Define the computational resources available to execute the model;
 3. Initiate and execute a simulation of the recipe on the chosen hardware resources.
 
+The python front-end further abstracts away some of these steps for single cell models, where users only need to
+describe the cell and simulation; and the details of the recipe and computational resources construction are
+handled under the hood. Generally speaking though, these 3 steps are the building blocks of an Arbor application.
+
 :ref:`Recipes <modelrecipe>` represent a set of neuron constructions and connections with *mechanisms* specifying ion channel and synapse dynamics in a cell-oriented manner. This has the advantage that cell data can be initiated in parallel.
 
 A cell represents the smallest unit of computation and forms the smallest unit of work distributed across processes. Arbor has built-in support for different :ref:`cell types <modelcells>`, which can be extended by adding new cell types to the C++ cell group interface.
diff --git a/doc/concepts/interconnectivity.rst b/doc/concepts/interconnectivity.rst
index 189cb202c02cb03de34bd565c7a8365ad8fd1819..a45c8019b2fb6c155a937fb7057fec38dc374dba 100644
--- a/doc/concepts/interconnectivity.rst
+++ b/doc/concepts/interconnectivity.rst
@@ -5,8 +5,8 @@ Interconnectivity
 
 Networks can be regarded as a sort of graph, where the nodes are cells and the edges
 describe the communications between them. In Arbor, two sorts of edges are modelled: a
-connection abstracts the propagation of action potentials (spikes) through the network,
-while a gap junction is used to describe a direct electrical connection between two cells.
+**connection** abstracts the propagation of action potentials (spikes) through the network,
+while a **gap junction** is used to describe a direct electrical connection between two cells.
 Connections only capture the propagation delay and attenuation associated with spike
 connectivity: the biophysical modelling of the chemical synapses themselves is the
 responsibility of the target cell model.
diff --git a/doc/concepts/labels.rst b/doc/concepts/labels.rst
index ba81e4e2584cd8a9fab386775108713bfed59e27..12619b588c022330e2cba794b13783445c326fc8 100644
--- a/doc/concepts/labels.rst
+++ b/doc/concepts/labels.rst
@@ -236,7 +236,7 @@ Locset expressions
 
       The result of ``(location 1 0.5)``, which corresponds to the mid point of branch 1.
 
-.. label:: (terminal}
+.. label:: (terminal)
 
     The location of terminal points, which are the most distal locations on the morphology.
     These will typically correspond to the tips, or end points, of dendrites and axons.
diff --git a/doc/concepts/morphology.rst b/doc/concepts/morphology.rst
index ed4b1393f309bba0c11bcbbe8407cccba714fb23..6bcad30af67023f4ec651b3746d064d5fa3af878 100644
--- a/doc/concepts/morphology.rst
+++ b/doc/concepts/morphology.rst
@@ -90,9 +90,7 @@ tag 2 coloured grey for axon; tag 3 coloured blue for basal dendrites.
   :align: center
 
   Example Python code to generate this morphology is in the :class:`segment_tree<arbor.segment_tree>`
-  documentation :ref:`below <morph-label-seg-code>`.
-
-We can apply the following labels to the segments:
+  documentation :ref:`here <morph-label-seg-code>`.
 
 * The tree is composed of 11 segments (1 soma, 2 axon, 8 dendrite).
 * The proximal ends of segments 0 and 9 (the soma and axon hillock respectively) are attached to the root of the tree.
diff --git a/doc/concepts/recipe.rst b/doc/concepts/recipe.rst
index be22cae55d0f34ae019485cad4ead66f06a19184..05ff1285c158b074a60ab83cac9853ab5f4a5650 100644
--- a/doc/concepts/recipe.rst
+++ b/doc/concepts/recipe.rst
@@ -14,6 +14,7 @@ building phase to provide information about cells in the model, such as:
   * the number of gap junction sites;
   * incoming network connections from other cells terminating on a cell;
   * gap junction connections on a cell.
+  * probes on a cell.
 
 Why recipes?
 --------------
@@ -22,7 +23,7 @@ The interface and design of Arbor recipes was motivated by the following aims:
 
     * Building a simulation from a recipe description must be possible in a
       distributed system efficiently with minimal communication.
-    * To minimise the amount of memory used in model building, to make it
+    * Minimising the amount of memory used in model building, making it
       possible to build and run simulations in one run.
 
 Recipe descriptions are cell-oriented, in order that the building phase can
diff --git a/doc/install/build_install.rst b/doc/install/build_install.rst
index 3f05513358e456efe99b16f4059c846694ae19f0..2202d29c4130da74b16cbee0bb95913b7c9069a9 100644
--- a/doc/install/build_install.rst
+++ b/doc/install/build_install.rst
@@ -84,7 +84,7 @@ We recommend using GCC or Clang, for which Arbor has been tested and optimised.
         ...
 
 .. Note::
-    Is is commonly assumed that to get the best performance one should use a vendor-specific
+    It is commonly assumed that to get the best performance one should use a vendor-specific
     compiler (e.g. the Intel, Cray or IBM compilers). These compilers are often better at
     auto-vectorizing loops, however for everything else GCC and Clang nearly always generate
     more efficient code.
@@ -92,7 +92,7 @@ We recommend using GCC or Clang, for which Arbor has been tested and optimised.
     The main computational loops in Arbor are generated from
     `NMODL <https://www.neuron.yale.edu/neuron/static/docs/help/neuron/nmodl/nmodl.html>`_.
     The generated code is explicitly vectorised, obviating the need for vendor compilers,
-    and we can take advantage of their benefits of GCC and Clang:
+    and we can take advantage of the benefits of GCC and Clang:
     faster compilation times; fewer compiler bugs; and better support for C++ standards.
 
 .. Note::
@@ -177,7 +177,7 @@ Building and installing Arbor
 Once the Arbor code has been checked out, first run CMake to configure the build, then run make.
 
 Below is a simple workflow for: **1)** getting the source; **2)** configuring the build;
-**3)** building; **4)** running tests; **5)** install.
+**3)** building; **4)** running tests; **5)** installing.
 
 For more detailed build configuration options, see the `quick start <quickstart_>`_ guide.
 
@@ -334,7 +334,8 @@ for the architecture, enabling ``ARB_VECTORIZE`` will lead to a compilation erro
 
 With this flag set, the library will use architecture-specific vectorization intrinsics
 to implement these kernels. Arbor currently has vectorization support for x86 architectures
-with AVX, AVX2 or AVX512 ISA extensions, and for ARM architectures with support for AArch64 NEON intrinsics (first available on ARMv8-A).
+with AVX, AVX2 or AVX512 ISA extensions; and for AArch64 ARM architectures with NEON and SVE
+(first available on ARMv8-A).
 
 .. _install-gpu:
 
diff --git a/doc/install/index.rst b/doc/install/index.rst
index 4feaa8300940fd710bea3d6ec29d41cf4b8686d7..509818e173063a550b16f36a1b64f3eb5ed6aa5f 100644
--- a/doc/install/index.rst
+++ b/doc/install/index.rst
@@ -3,12 +3,12 @@
 Get Arbor
 =========
 
-Currently we offer three ways to get Arbor.
+Currently we offer two ways to get Arbor.
 
 1. **Python Package**. To get started quickly with Arbor using its Python API on your personal machine, see the :ref:`Python installation guide <in_python>`.
 2. **Build and install from source**. To build and install Arbor, on your own machine or HPC environment, see :ref:`in_build_install`.
 
-If you wish to use the C++ API, you'll need to build Arbor from source. Note that you can build the Python bindings with both of those as well.
+If you wish to use the C++ API, you'll need to build Arbor from source. Note that you can also build the Python bindings using this method.
 
 .. toctree::
    :maxdepth: 2
diff --git a/doc/install/python.rst b/doc/install/python.rst
index d49b57d48c952e553864f1005efc67c2fac26deb..c08bf49273efc1996450d4f5d7d9bca78b618e7f 100644
--- a/doc/install/python.rst
+++ b/doc/install/python.rst
@@ -84,7 +84,7 @@ below demonstrate this for both pip and ``setup.py``.
     pip3 install --install-option='--mpi' ./arbor
     python3 ./arbor/setup.py install --mpi
 
-**Compile with** :ref:`vectorization <install-vectorize>` on a system with SkyLake:
+**Compile with** :ref:`vectorization <install-vectorize>` on a system with a SkyLake
 :ref:`architecture <install-architecture>`:
 
 .. code-block:: bash
diff --git a/doc/tutorial/single_cell_model.rst b/doc/tutorial/single_cell_model.rst
index caadeac7c82dca79344316e56f2acd09ecdf0593..f0f8c56b1bad5062705492662fe4d76697f64984 100644
--- a/doc/tutorial/single_cell_model.rst
+++ b/doc/tutorial/single_cell_model.rst
@@ -12,7 +12,7 @@ This guide will walk through a series of single cell models of increasing comple
 Links are provided to separate documentation that covers relevant topics in more detail.
 
 In an interactive Python interpreter, you can use ``help()`` on any class or function to
-obtain some documentation.
+obtain some documentation. (Try, for example, ``help(arbor.simulation``).
 
 .. _single_soma:
 
@@ -21,8 +21,8 @@ Single segment cell with HH dynamics
 
 The most trivial representation of a cell in Arbor is to model the entire cell as a
 single cylinder. The following example shows the steps required to construct a model of a
-cylindrical cell with radius 3 μm, Hodgkin–Huxley dynamics and a current clamp stimulus,
-then run the model for 30 ms.
+cylindrical cell with a length of 6 μm and a radius of 3 μm; Hodgkin–Huxley dynamics
+and a current clamp stimulus, then run the model for 30 ms.
 
 The first step is to construct the cell. In Arbor, the abstract representation used to
 define a cell with branching "cable" morphology is a ``cable_cell``, which holds a
@@ -53,40 +53,43 @@ create the ``cable_cell`` that represents it are as follows:
 
 Let's unpack that.
 
-Step **(1)** above shows how the cell is represented using a :class:`arbor.segment_tree`
-to which a single segment is added. Arbor's cell morphologies are constructed from a
-:ref:`segment tree<morph-segment_tree>` which is a list of segments, which are tapered
-cones with a *tag*. :meth:`arbor.segment_tree.append` takes 4 arguments, starting with
-the parent segment. The first segment added has no parent, which is made clear by
-using :class:`arbor.mnpos`. Then two :class:`arbor.mpoint` s are supplied, the proximal
-and distal endpoints of the segment. Finally, an integer value is supplied to tag the
-segment for future reference.
+Step **(1)** constructs a :class:`arbor.segment_tree` (see also :ref:`segment tree<morph-segment_tree>`).
+The segment tree is the representation used to construct the morphology of a cell. A segment is
+a tapered cone with a tag; the tag can be used to classify the type of the segment (for example
+soma, dendrite etc). To create a segment tree representing our single-cylinder cell, we need to add
+one segment to our ``tree`` object. We use the :meth:`arbor.segment_tree.append` method, which takes
+4 arguments: the parent segment which does not exist for the first segment, so we use :class:`arbor.mnpos`;
+the proximal :class:`arbor.mpoint` (location and radius) of the segment; the distal :class:`arbor.mpoint`
+of the segment; and the tag.
 
-In step **(2)** a dictionary of labels is created using :class:`arbor.label_dict<arbor.label_dict>`.
-Cell builders need to refer to *regions* and *locations* on a cell morphology. Arbor uses a domain
-specific language (DSL) to describe regions and locations, which are given labels. We add two labels:
+Step **(2)** creates a dictionary of labels (:class:`arbor.label_dict<arbor.label_dict>`). Labels give
+names to :ref:`regions<labels-region>` and :ref:`location<labels-locset>` described using a DSL
+based on s-expressions. Labels from the dictionary can then be used to facilitate adding synapses,
+dynamics, stimulii and probes to the cell. We add two labels:
 
 * ``soma`` defines a *region* with ``(tag  1)``. Note that this corresponds to the
   ``tag`` parameter that was used to define the single segment in step (1).
 * ``center`` defines a *location* at ``(location 0 0.5)``, which is the mid point ``0.5``
   of branch ``0``, which corresponds to the center of the soma on the morphology defined in step (1).
 
-In step **(3)** a :class:`arbor.cable_cell` is constructed by combining the segment tree
-with the named regions and locations.
-
-* "Cell-wide" properties are set through :meth:`arbor.cable_cell.set_properties`. Here,
-  the initial membrane potential is set to -40 mV everywhere on the cell.
-* Properties can also be set to a region of the cell, which Arbor calls 'painting'. This
-  is meant to convey placement is not precise: we wouldn't want to manually place ion
-  channels all over the surface of the cell. :meth:`arbor.cable_cell.paint` lets us
-  instruct Arbor to use HH dynamics on the region we've labelled soma and sort the details
-  out for us.
-* Other properties should be added to the cell on a precise :class:`arbor.location`. This is
-  done using the :meth:`arbor.cable_cell.place<arbor.cable_cell.place>` method.
-  We place a current stimulus :class:`arbor.iclamp<arbor.iclamp>` with a duration of 2 ms
-  and a current of 0.8 nA, starting at 10 ms on the location we've labelled 'center'. We also
-  place a :class:`arbor.spike_detector<arbor.spike_detector>` with a threshold of -10 mV on the
-  same location.
+Step **(3)** constructs the :class:`arbor.cable_cell` from the segment tree and dictionary of labeled
+regions and locations. The resulting cell's default properties can be modified, and we can use
+:meth:`arbor.cable_cell.paint` and :meth:`arbor.cable_cell.place` to further customise it in the
+following way:
+
+* :meth:`arbor.cable_cell.set_properties` is used to set some default properties on the entire cell.
+  In the above example we set the initial membrane potential to -40 mV.
+* :meth:`arbor.cable_cell.paint` is used to set properties or add dynamics to a region of the cell.
+  We call this method 'painting' to convey that we are working on sections of a cell, as opposed to
+  precise locations: for example, we might want to ``paint`` an ion channel on all dendrites, and then
+  ``place`` a synapse at the tip of the axon. In the above example we :meth:`arbor.cable_cell.paint`
+  HH dynamics on the region we previously named 'soma' in our label dictionary.
+* :meth:`arbor.cable_cell.place<arbor.cable_cell.place>` is used to add objects on a precise
+  :class:`arbor.location` on a cell. Examples of objects that are ``placed`` are synapses,
+  spike detectors, current stimulii, and probes. In the above example we place a current stimulus
+  :class:`arbor.iclamp<arbor.iclamp>` with a duration of 2 ms and a current of 0.8 nA, starting at 10 ms
+  on the location we previously labelled 'center'. We also place a :class:`arbor.spike_detector<arbor.spike_detector>`
+  with a threshold of -10 mV on the same location.
 
 Single cell model
 ----------------------------------------------------
@@ -112,12 +115,12 @@ recording potentials and running the simulation more easily.
 Step **(4)** instantiates the :class:`arbor.single_cell_model<arbor.single_cell_model>`
 with our single-compartment cell.
 
-In step **(5)** a :meth:`arbor.single_cell_model.probe()<arbor.single_cell_model.probe>`
-is used to record variables from the model. Three pieces of information are
+Step **(5)** adds a :meth:`arbor.single_cell_model.probe()<arbor.single_cell_model.probe>`
+used to record variables from the model. Three pieces of information are
 provided: the type of quantity we want probed (voltage), the location where we want to
 probe ('"center"'), and the frequency at which we want to sample (10kHz).
 
-Finally, step **(6)** starts the actual simulation for a duration of 30 ms.
+Step **(6)** runs the actual simulation for a duration of 30 ms.
 
 Results
 ----------------------------------------------------
@@ -141,13 +144,13 @@ results! Let's take a look at what the spike detector and a voltage probes from
     df = pandas.DataFrame({'t/ms': m.traces[0].time, 'U/mV': m.traces[0].value})
     seaborn.relplot(data=df, kind="line", x="t/ms", y="U/mV").savefig('single_cell_model_result.svg')
 
-In step **(7)** we access :meth:`arbor.single_cell_model.spikes<arbor.single_cell_model.spikes>`
-to access the spike time. A single spike at a little over 10 ms should be printed,
-which matches the stimulus we have provided in step (3).
+Step **(7)** accesses :meth:`arbor.single_cell_model.spikes<arbor.single_cell_model.spikes>`
+to print the spike times. A single spike should be generated at around the same time the stimulus
+we provided in step (3) gets activated (10ms).
 
-The other measurement we have is that of the potential, which we plot in step **(8)**.
-Arbor stores sampled quantities under :meth:`arbor.single_cell_model.traces<arbor.single_cell_model.traces>`.
-You should be seeing something like this:
+Step **(8)** plots the measured potentials during the runtime of the simulation. The sampled quantities
+can be accessed through :meth:`arbor.single_cell_model.traces<arbor.single_cell_model.traces>`.
+We should be seeing something like this:
 
 .. figure:: single_cell_model_result.svg
     :width: 400