diff --git a/doc/profiler.rst b/doc/profiler.rst
index bafc6ab79305781aae60d19666dc4f0c370208c5..afe9248f8e45203d6e44f5eed746b227df56147b 100644
--- a/doc/profiler.rst
+++ b/doc/profiler.rst
@@ -2,7 +2,8 @@ Profiler
 ========
 
 The Arbor library has a built-in profiler for fine-grained timings of regions of interest in the code.
-The time stepping code in ``arb::model`` has been instrumented, so by enabling profiler support at compile time, users of the library can generate profile reports from calls to ``arb::model::run()``.
+The time stepping code in ``arb::simulation`` has been instrumented, so by enabling profiler support at
+compile time, users of the library can generate profile reports from calls to ``arb::simulation::run()``.
 
 Compilation
 -----------
@@ -184,7 +185,7 @@ and the profiler regions can be reset.
         }
 
 After a call to ``util::profiler_clear``, all counters and timers are set to zero.
-This could be used, for example, to generate seperate profiler reports for model building and model executation phases of a simulation.
+This could be used, for example, to generate seperate profiler reports for model building and model executation phases.
 
 Profiler Output
 ~~~~~~~~~~~~~~~
diff --git a/doc/sampling_api.rst b/doc/sampling_api.rst
index 71984fea560cfede4ac019fd1ca58cc238105368..5da0f46919adc8c367138b8f49c57fe5e5ae4c68 100644
--- a/doc/sampling_api.rst
+++ b/doc/sampling_api.rst
@@ -27,7 +27,7 @@ Probes
 ------
 
 Probes are specified in the recipe objects that are used to initialize a
-model; the specification of the item or value that is subjected to a
+simulation; the specification of the item or value that is subjected to a
 probe will be specific to a particular cell type.
 
 .. container:: api-code
@@ -134,7 +134,7 @@ Model and cell group interface
 ------------------------------
 
 Polling rates, policies and sampler functions are set through the
-``model`` interface, after construction from a recipe.
+``simulation`` interface, after construction from a recipe.
 
 .. container:: api-code
 
@@ -143,15 +143,15 @@ Polling rates, policies and sampler functions are set through the
             using sampler_association_handle = std::size_t;
             using cell_member_predicate = std::function<bool (cell_member_type)>;
 
-            sampler_association_handle model::add_sampler(
+            sampler_association_handle simulation::add_sampler(
                 cell_member_predicate probe_ids,
                 schedule sched,
                 sampler_function fn,
                 sampling_policy policy = sampling_policy::lax);
 
-            void model::remove_sampler(sampler_association_handle);
+            void simulation::remove_sampler(sampler_association_handle);
 
-            void model::remove_all_samplers();
+            void simulation::remove_all_samplers();
 
 Multiple samplers can then be associated with the same probe locations.
 The handle returned is only used for managing the lifetime of the
@@ -179,7 +179,7 @@ minimizes sampling overhead and which will not change the numerical
 behaviour of the simulation. Other policies may be implemented in the
 future, e.g. ``interpolated`` or ``exact``.
 
-The model object will pass on the sampler setting request to the cell
+The simulation object will pass on the sampler setting request to the cell
 group that owns the given probe id. The ``cell_group`` interface will be
 correspondingly extended:
 
@@ -262,7 +262,7 @@ The ``schedule`` class and its implementations are found in ``schedule.hpp``.
 Helper classes for probe/sampler management
 -------------------------------------------
 
-The ``model`` and ``mc_cell_group`` classes use classes defined in ``scheduler_map.hpp`` to simplify
+The ``simulation`` and ``mc_cell_group`` classes use classes defined in ``scheduler_map.hpp`` to simplify
 the management of sampler--probe associations and probe metdata.
 
 ``sampler_association_map`` wraps an ``unordered_map`` between sampler assocation
diff --git a/example/brunel/brunel_miniapp.cpp b/example/brunel/brunel_miniapp.cpp
index ecde5053496c46e36b5d24313edde866e638e34f..545c29c12ff2ad37b5847ac7198c8e69355d9b8c 100644
--- a/example/brunel/brunel_miniapp.cpp
+++ b/example/brunel/brunel_miniapp.cpp
@@ -1,31 +1,32 @@
 #include <cmath>
 #include <exception>
-#include <event_generator.hpp>
-#include <iostream>
 #include <fstream>
+#include <iostream>
 #include <memory>
+#include <set>
 #include <vector>
-#include <json/json.hpp>
+
 #include <common_types.hpp>
 #include <communication/communicator.hpp>
 #include <communication/global_policy.hpp>
+#include <event_generator.hpp>
+#include <hardware/gpu.hpp>
+#include <hardware/node_info.hpp>
 #include <io/exporter_spike_file.hpp>
+#include <json/json.hpp>
 #include <lif_cell_description.hpp>
-#include <model.hpp>
-#include "partitioner.hpp"
 #include <profiling/profiler.hpp>
 #include <profiling/meter_manager.hpp>
 #include <recipe.hpp>
-#include <set>
+#include <simulation.hpp>
 #include <threading/threading.hpp>
 #include <util/config.hpp>
 #include <util/debug.hpp>
 #include <util/ioutil.hpp>
 #include <util/nop.hpp>
-#include <vector>
+
+#include "partitioner.hpp"
 #include "io.hpp"
-#include <hardware/gpu.hpp>
-#include <hardware/node_info.hpp>
 
 using namespace arb;
 
@@ -244,7 +245,7 @@ int main(int argc, char** argv) {
         };
 
         auto decomp = decompose(recipe, group_size);
-        model m(recipe, decomp);
+        simulation sim(recipe, decomp);
 
         // Initialize the spike exporting interface
         std::unique_ptr<file_export_type> file_exporter;
@@ -252,7 +253,7 @@ int main(int argc, char** argv) {
             if (options.single_file_per_rank) {
                 file_exporter = register_exporter(options);
 
-                m.set_local_spike_callback(
+                sim.set_local_spike_callback(
                     [&](const std::vector<spike>& spikes) {
                         file_exporter->output(spikes);
                     }
@@ -261,7 +262,7 @@ int main(int argc, char** argv) {
             else if(communication::global_policy::id()==0) {
                 file_exporter = register_exporter(options);
 
-                m.set_global_spike_callback(
+                sim.set_global_spike_callback(
                     [&](const std::vector<spike>& spikes) {
                         file_exporter->output(spikes);
                     }
@@ -270,14 +271,14 @@ int main(int argc, char** argv) {
         }
         meters.checkpoint("model-init");
 
-        // run model
-        m.run(options.tfinal, options.dt);
+        // run simulation
+        sim.run(options.tfinal, options.dt);
 
         meters.checkpoint("model-simulate");
 
         // output profile and diagnostic feedback
         std::cout << util::profiler_summary() << "\n";
-        std::cout << "\nThere were " << m.num_spikes() << " spikes\n";
+        std::cout << "\nThere were " << sim.num_spikes() << " spikes\n";
 
         auto report = util::make_meter_report(meters);
         std::cout << report;
diff --git a/example/generators/event_gen.cpp b/example/generators/event_gen.cpp
index 41293bea9f14951e3fa3cf728f52fb83a313268c..145802bd194375c194efc6e4b0aa3a5a58c937d9 100644
--- a/example/generators/event_gen.cpp
+++ b/example/generators/event_gen.cpp
@@ -17,7 +17,7 @@
 #include <event_generator.hpp>
 #include <hardware/node_info.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
 
@@ -133,7 +133,7 @@ int main() {
     auto decomp = arb::partition_load_balance(recipe, node);
 
     // Construct the model.
-    arb::model model(recipe, decomp);
+    arb::simulation sim(recipe, decomp);
 
     // Set up the probe that will measure voltage in the cell.
 
@@ -144,10 +144,10 @@ int main() {
     // This is where the voltage samples will be stored as (time, value) pairs
     arb::trace_data<double> voltage;
     // Now attach the sampler at probe_id, with sampling schedule sched, writing to voltage
-    model.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage));
+    sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage));
 
-    // Run the model for 1 s (1000 ms), with time steps of 0.01 ms.
-    model.run(50, 0.01);
+    // Run the simulation for 1 s (1000 ms), with time steps of 0.01 ms.
+    sim.run(50, 0.01);
 
     // Write the samples to a json file.
     write_trace_json(voltage);
diff --git a/example/generators/readme.md b/example/generators/readme.md
index a18a853ab09637ea739696be01e062ef97c680e2..c9146c1af6fbe1986f44906c9db327013d830d56 100644
--- a/example/generators/readme.md
+++ b/example/generators/readme.md
@@ -45,7 +45,8 @@ default `recipe::connections_on(gid)` method can use the default implementation,
 which returns an empty list of connections for a cell.
 
 Above you can see the definition of `recipe::num_cells()`, which is trivial for this model, which has only once cell.
-The `recipe::get_cell_description(gid)` and `recipe::get_cell_kind(gid)` methods are defined to return a single compartment cell with one synapse, and a `arb::cell_kind::cable1d_neuron` respectively:
+The `recipe::get_cell_description(gid)` and `recipe::get_cell_kind(gid)` methods are defined to return a single
+compartment cell with one synapse, and a `arb::cell_kind::cable1d_neuron` respectively:
 
 ```C++
     // Return an arb::cell that describes a single compartment cell with
@@ -139,8 +140,8 @@ To visualise the result of our experiment, we want to sample the voltage in our
 There are three parts to this process.
 
 1. Define the a `probe` in the recipe, which describes the location and variable to be sampled, i.e. the soma and voltage respectively for this example.
-2. Attach a sampler to this probe once the model has been created.
-3. Write the sampled values to a JSON file once the model has been run.
+2. Attach a sampler to this probe once the simulation has been created.
+3. Write the sampled values to a JSON file once the simulation has been run.
 
 #### 1. Define probe in recipe
 
@@ -166,9 +167,9 @@ In our case, the cell has one probe, which refers to the voltage at the soma.
     }
 ```
 
-#### 2. Attach sampler to model
+#### 2. Attach sampler to simulation
 
-Once the model has been created, the model has internal state that tracks the value of the voltage at the probe location described by the recipe.
+Once the simulation has been created, the simulation has internal state that tracks the value of the voltage at the probe location described by the recipe.
 We must attach a sampler to this probe to get sample values.
 
 The sampling interface is rich, and can be extended in many ways.
@@ -186,10 +187,10 @@ For our simple use case there are three bits of information that need to be prov
     // Where the voltage samples will be stored as (time, value) pairs
     arb::trace_data<double> voltage;
     // Now attach the sampler:
-    model.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage));
+    sim.add_sampler(arb::one_probe(probe_id), sched, arb::make_simple_sampler(voltage));
 ```
 
-When the model is run, the `simple_sampler` that we attached to the probe will store the sample values as (time, voltage) pairs in the `voltage` vector.
+When the simulation is run, the `simple_sampler` that we attached to the probe will store the sample values as (time, voltage) pairs in the `voltage` vector.
 
 #### 3. Output to JSON
 
diff --git a/example/miniapp/miniapp.cpp b/example/miniapp/miniapp.cpp
index 81cd3def73180acc833f078c56594c71b588dd49..969b6aedf9d6f3b8527ff24504029b1d1c6a64d9 100644
--- a/example/miniapp/miniapp.cpp
+++ b/example/miniapp/miniapp.cpp
@@ -16,7 +16,7 @@
 #include <hardware/node_info.hpp>
 #include <io/exporter_spike_file.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <profiling/profiler.hpp>
 #include <profiling/meter_manager.hpp>
 #include <sampling.hpp>
@@ -101,7 +101,7 @@ int main(int argc, char** argv) {
         };
 
         auto decomp = partition_load_balance(*recipe, nd);
-        model m(*recipe, decomp);
+        simulation sim(*recipe, decomp);
 
         // Set up samplers for probes on local cable cells, as requested
         // by command line options.
@@ -122,7 +122,7 @@ int main(int argc, char** argv) {
 
         auto ssched = regular_schedule(options.sample_dt);
         for (auto& trace: sample_traces) {
-            m.add_sampler(one_probe(trace.probe_id), ssched, make_simple_sampler(trace.samples));
+            sim.add_sampler(one_probe(trace.probe_id), ssched, make_simple_sampler(trace.samples));
         }
 
         // Specify event binning/coalescing.
@@ -131,21 +131,21 @@ int main(int argc, char** argv) {
             options.bin_regular? binning_kind::regular:
             binning_kind::following;
 
-        m.set_binning_policy(binning_policy, options.bin_dt);
+        sim.set_binning_policy(binning_policy, options.bin_dt);
 
         // Initialize the spike exporting interface
         std::unique_ptr<file_export_type> file_exporter;
         if (options.spike_file_output) {
             if (options.single_file_per_rank) {
                 file_exporter = register_exporter(options);
-                m.set_local_spike_callback(
+                sim.set_local_spike_callback(
                     [&](const std::vector<spike>& spikes) {
                         file_exporter->output(spikes);
                     });
             }
             else if(communication::global_policy::id()==0) {
                 file_exporter = register_exporter(options);
-                m.set_global_spike_callback(
+                sim.set_global_spike_callback(
                     [&](const std::vector<spike>& spikes) {
                        file_exporter->output(spikes);
                     });
@@ -155,14 +155,14 @@ int main(int argc, char** argv) {
         meters.checkpoint("model-init");
 
         // run model
-        m.run(options.tfinal, options.dt);
+        sim.run(options.tfinal, options.dt);
 
         meters.checkpoint("model-simulate");
 
         // output profile and diagnostic feedback
         auto profile = util::profiler_summary();
         std::cout << profile << "\n";
-        std::cout << "\nthere were " << m.num_spikes() << " spikes\n";
+        std::cout << "\nthere were " << sim.num_spikes() << " spikes\n";
 
         // save traces
         auto write_trace = options.trace_format=="json"? write_trace_json: write_trace_csv;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 348f47a57e8c9f5707dfbe9a998f42a20da2cce7..757fe245c5e7fbd81245f263cc7eb48defb8eacd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -11,7 +11,7 @@ set(BASE_SOURCES
     hardware/node_info.cpp
     hardware/power.cpp
     merge_events.cpp
-    model.cpp
+    simulation.cpp
     morphology.cpp
     partition_load_balance.cpp
     profiling/memory_meter.cpp
diff --git a/src/merge_events.cpp b/src/merge_events.cpp
index 8a26ccc056af1026179200e1db954e57e3909600..1fd116151559a81a585ffcbcf7eea5e15daefdba 100644
--- a/src/merge_events.cpp
+++ b/src/merge_events.cpp
@@ -6,7 +6,6 @@
 #include <cell_group_factory.hpp>
 #include <domain_decomposition.hpp>
 #include <merge_events.hpp>
-#include <model.hpp>
 #include <recipe.hpp>
 #include <util/filter.hpp>
 #include <util/span.hpp>
diff --git a/src/model.cpp b/src/simulation.cpp
similarity index 86%
rename from src/model.cpp
rename to src/simulation.cpp
index 59817ac652bdbde880df052dd8a0331bf357d541..d7b3b6f5a60ec572acd7c258580f9240d652f133 100644
--- a/src/model.cpp
+++ b/src/simulation.cpp
@@ -6,7 +6,7 @@
 #include <cell_group_factory.hpp>
 #include <domain_decomposition.hpp>
 #include <merge_events.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <util/filter.hpp>
 #include <util/span.hpp>
@@ -15,7 +15,7 @@
 
 namespace arb {
 
-model::model(const recipe& rec, const domain_decomposition& decomp):
+simulation::simulation(const recipe& rec, const domain_decomposition& decomp):
     communicator_(rec, decomp)
 {
     const auto num_local_cells = communicator_.num_local_cells();
@@ -65,7 +65,7 @@ model::model(const recipe& rec, const domain_decomposition& decomp):
     event_lanes_[1].resize(num_local_cells);
 }
 
-void model::reset() {
+void simulation::reset() {
     t_ = 0.;
 
     // Reset cell group state.
@@ -98,7 +98,7 @@ void model::reset() {
     previous_spikes().clear();
 }
 
-time_type model::run(time_type tfinal, time_type dt) {
+time_type simulation::run(time_type tfinal, time_type dt) {
     // Calculate the size of the largest possible time integration interval
     // before communication of spikes is required.
     // If spike exchange and cell update are serialized, this is the
@@ -186,7 +186,7 @@ time_type model::run(time_type tfinal, time_type dt) {
 //      event_lanes[epoch]: take all events ≥ t_from
 //      event_generators  : take all events < t_to
 //      pending_events    : take all events
-void model::setup_events(time_type t_from, time_type t_to, std::size_t epoch) {
+void simulation::setup_events(time_type t_from, time_type t_to, std::size_t epoch) {
     const auto n = communicator_.num_local_cells();
     threading::parallel_for::apply(0, n,
         [&](cell_size_type i) {
@@ -200,7 +200,12 @@ void model::setup_events(time_type t_from, time_type t_to, std::size_t epoch) {
         });
 }
 
-sampler_association_handle model::add_sampler(cell_member_predicate probe_ids, schedule sched, sampler_function f, sampling_policy policy) {
+sampler_association_handle simulation::add_sampler(
+        cell_member_predicate probe_ids,
+        schedule sched,
+        sampler_function f,
+        sampling_policy policy)
+{
     sampler_association_handle h = sassoc_handles_.acquire();
 
     threading::parallel_for::apply(0, cell_groups_.size(),
@@ -211,7 +216,7 @@ sampler_association_handle model::add_sampler(cell_member_predicate probe_ids, s
     return h;
 }
 
-void model::remove_sampler(sampler_association_handle h) {
+void simulation::remove_sampler(sampler_association_handle h) {
     threading::parallel_for::apply(0, cell_groups_.size(),
         [&](std::size_t i) {
             cell_groups_[i]->remove_sampler(h);
@@ -220,7 +225,7 @@ void model::remove_sampler(sampler_association_handle h) {
     sassoc_handles_.release(h);
 }
 
-void model::remove_all_samplers() {
+void simulation::remove_all_samplers() {
     threading::parallel_for::apply(0, cell_groups_.size(),
         [&](std::size_t i) {
             cell_groups_[i]->remove_all_samplers();
@@ -229,50 +234,50 @@ void model::remove_all_samplers() {
     sassoc_handles_.clear();
 }
 
-std::size_t model::num_spikes() const {
+std::size_t simulation::num_spikes() const {
     return communicator_.num_spikes();
 }
 
-std::size_t model::num_groups() const {
+std::size_t simulation::num_groups() const {
     return cell_groups_.size();
 }
 
-std::vector<pse_vector>& model::event_lanes(std::size_t epoch_id) {
+std::vector<pse_vector>& simulation::event_lanes(std::size_t epoch_id) {
     return event_lanes_[epoch_id%2];
 }
 
-void model::set_binning_policy(binning_kind policy, time_type bin_interval) {
+void simulation::set_binning_policy(binning_kind policy, time_type bin_interval) {
     for (auto& group: cell_groups_) {
         group->set_binning_policy(policy, bin_interval);
     }
 }
 
-void model::set_global_spike_callback(spike_export_function export_callback) {
+void simulation::set_global_spike_callback(spike_export_function export_callback) {
     global_export_callback_ = export_callback;
 }
 
-void model::set_local_spike_callback(spike_export_function export_callback) {
+void simulation::set_local_spike_callback(spike_export_function export_callback) {
     local_export_callback_ = export_callback;
 }
 
-util::optional<cell_size_type> model::local_cell_index(cell_gid_type gid) {
+util::optional<cell_size_type> simulation::local_cell_index(cell_gid_type gid) {
     auto it = gid_to_local_.find(gid);
     return it==gid_to_local_.end()?
         util::nullopt:
         util::optional<cell_size_type>(it->second);
 }
 
-void model::inject_events(const pse_vector& events) {
+void simulation::inject_events(const pse_vector& events) {
     // Push all events that are to be delivered to local cells into the
     // pending event list for the event's target cell.
     for (auto& e: events) {
         if (e.time<t_) {
             throw std::runtime_error(
-                "model::inject_events(): attempt to inject an event at time: "
+                "simulation::inject_events(): attempt to inject an event at time: "
                 + std::to_string(e.time)
-                + " ms, which is earlier than the current model time: "
+                + " ms, which is earlier than the current simulation time: "
                 + std::to_string(t_)
-                + " ms. Events must be injected on or after the current model time.");
+                + " ms. Events must be injected on or after the current simulation time.");
         }
         // local_cell_index returns an optional type that evaluates
         // to true iff the gid is a local cell.
diff --git a/src/model.hpp b/src/simulation.hpp
similarity index 94%
rename from src/model.hpp
rename to src/simulation.hpp
index 1ace8489034f2bab325a0b77a8d522efb50aaacd..441807335289afd5db700862be2d890335683b93 100644
--- a/src/model.hpp
+++ b/src/simulation.hpp
@@ -20,12 +20,12 @@
 
 namespace arb {
 
-class model {
+class simulation {
 public:
     using communicator_type = communication::communicator<communication::global_policy>;
     using spike_export_function = std::function<void(const std::vector<spike>&)>;
 
-    model(const recipe& rec, const domain_decomposition& decomp);
+    simulation(const recipe& rec, const domain_decomposition& decomp);
 
     void reset();
 
@@ -55,8 +55,8 @@ public:
     void set_local_spike_callback(spike_export_function export_callback);
 
     // Add events directly to targets.
-    // Must be called before calling model::run, and must contain events that
-    // are to be delivered at or after the current model time.
+    // Must be called before calling simulation::run, and must contain events that
+    // are to be delivered at or after the current simulation time.
     void inject_events(const pse_vector& events);
 
 private:
diff --git a/tests/unit/test_fvm_multi.cpp b/tests/unit/test_fvm_multi.cpp
index a82b78d16ecb4e25e5caaaada98e2386a61b7449..0245ae1e7af2f93ae99b723dab2d950fc83dad63 100644
--- a/tests/unit/test_fvm_multi.cpp
+++ b/tests/unit/test_fvm_multi.cpp
@@ -8,7 +8,7 @@
 #include <fvm_multicell.hpp>
 #include <load_balance.hpp>
 #include <math.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <sampler_map.hpp>
 #include <sampling.hpp>
@@ -584,7 +584,7 @@ TEST(fvm_multi, specialized_mechs) {
         float times[] = {10.f, 20.f};
 
         auto decomp = partition_load_balance(rec, hw::node_info{1u, 0u});
-        model sim(rec, decomp);
+        simulation sim(rec, decomp);
         sim.add_sampler(all_probes, explicit_schedule(times), sampler);
         sim.run(30.0, 1.f/1024);
 
diff --git a/tests/unit/test_lif_cell_group.cpp b/tests/unit/test_lif_cell_group.cpp
index 9793533031243974fe4db6a811474fa9b215d31f..44033c473122f635a7ead309b6a56b301bdf4bce 100644
--- a/tests/unit/test_lif_cell_group.cpp
+++ b/tests/unit/test_lif_cell_group.cpp
@@ -4,7 +4,7 @@
 #include <lif_cell_description.hpp>
 #include <lif_cell_group.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <rss_cell.hpp>
 #include <rss_cell_group.hpp>
@@ -161,7 +161,7 @@ TEST(lif_cell_group, spikes) {
     nd.num_cpu_cores = threading::num_threads();
 
     auto decomp = partition_load_balance(recipe, nd);
-    model m(recipe, decomp);
+    simulation sim(recipe, decomp);
 
     std::vector<postsynaptic_spike_event> events;
 
@@ -176,14 +176,14 @@ TEST(lif_cell_group, spikes) {
     // event, should thus trigger new spike (first neuron).
     events.push_back({{0, 0}, 50, 1000});
 
-    m.inject_events(events);
+    sim.inject_events(events);
 
     time_type tfinal = 100;
     time_type dt = 0.01;
-    m.run(tfinal, dt);
+    sim.run(tfinal, dt);
 
     // we expect 4 spikes: 2 by both neurons
-    EXPECT_EQ(4u, m.num_spikes());
+    EXPECT_EQ(4u, sim.num_spikes());
 }
 
 TEST(lif_cell_group, ring)
@@ -202,19 +202,19 @@ TEST(lif_cell_group, ring)
     auto recipe = ring_recipe(num_lif_cells, weight, delay);
     auto decomp = partition_load_balance(recipe, nd);
 
-    // Creates a model with a ring recipe of lif neurons
-    model mod(recipe, decomp);
+    // Creates a simulation with a ring recipe of lif neurons
+    simulation sim(recipe, decomp);
 
     std::vector<spike> spike_buffer;
 
-    mod.set_global_spike_callback(
+    sim.set_global_spike_callback(
         [&spike_buffer](const std::vector<spike>& spikes) {
             spike_buffer.insert(spike_buffer.end(), spikes.begin(), spikes.end());
         }
     );
 
     // Runs the simulation for simulation_time with given timestep
-    mod.run(simulation_time, 0.01);
+    sim.run(simulation_time, 0.01);
     // The total number of cells in all the cell groups.
     // There is one additional fake cell (regularly spiking cell).
     EXPECT_EQ(num_lif_cells + 1u, recipe.num_cells());
diff --git a/tests/unit/test_merge_events.cpp b/tests/unit/test_merge_events.cpp
index d7b8d0a24b60a302c5b1d39f64ece28e106dacaf..2afc38dfce5e9bfab900506a30b9ad0a7277605c 100644
--- a/tests/unit/test_merge_events.cpp
+++ b/tests/unit/test_merge_events.cpp
@@ -2,7 +2,6 @@
 
 #include <event_queue.hpp>
 #include <merge_events.hpp>
-#include <model.hpp>
 
 using namespace arb;
 
diff --git a/tests/validation/convergence_test.hpp b/tests/validation/convergence_test.hpp
index 9d25f1b4580a91a803af22bf88e4b7e48b97f4cd..6cbb945d0ba198da5bdd987eb614b1c3773bfe0d 100644
--- a/tests/validation/convergence_test.hpp
+++ b/tests/validation/convergence_test.hpp
@@ -2,7 +2,8 @@
 
 #include <vector>
 
-#include <model.hpp>
+#include <simulation.hpp>
+#include <schedule.hpp>
 #include <sampling.hpp>
 #include <simple_sampler.hpp>
 #include <util/filter.hpp>
@@ -72,7 +73,7 @@ public:
         }
     }
 
-    void run(model& m, Param p, float sample_dt, float t_end, float dt, const std::vector<float>& excl) {
+    void run(simulation& sim, Param p, float sample_dt, float t_end, float dt, const std::vector<float>& excl) {
         struct sampler_state {
             sampler_association_handle h; // Keep these for clean up at end.
             const char* label;
@@ -88,10 +89,10 @@ public:
             auto& entry = samplers.back();
 
             entry.label = pl.label;
-            entry.h = m.add_sampler(one_probe(pl.probe_id), regular_schedule(sample_dt), simple_sampler<double>(entry.trace));
+            entry.h = sim.add_sampler(one_probe(pl.probe_id), regular_schedule(sample_dt), simple_sampler<double>(entry.trace));
         }
 
-        m.run(t_end, dt);
+        sim.run(t_end, dt);
 
         for (auto& entry: samplers) {
             std::string label = entry.label;
@@ -114,7 +115,7 @@ public:
 
         // Remove added samplers.
         for (const auto& entry: samplers) {
-            m.remove_sampler(entry.h);
+            sim.remove_sampler(entry.h);
         }
     }
 
diff --git a/tests/validation/validate_ball_and_stick.cpp b/tests/validation/validate_ball_and_stick.cpp
index 7f8042686a22c15764a6b929d4d1ba601e4cf82c..2d6d429011cc2e8a4c92c49cabfc400644dda848 100644
--- a/tests/validation/validate_ball_and_stick.cpp
+++ b/tests/validation/validate_ball_and_stick.cpp
@@ -5,7 +5,7 @@
 #include <load_balance.hpp>
 #include <hardware/node_info.hpp>
 #include <hardware/gpu.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <segment.hpp>
 #include <simple_sampler.hpp>
@@ -77,9 +77,9 @@ void run_ncomp_convergence_test(
 
         hw::node_info nd(1, backend==backend_kind::gpu? 1: 0);
         auto decomp = partition_load_balance(rec, nd);
-        model m(rec, decomp);
+        simulation sim(rec, decomp);
 
-        runner.run(m, ncomp, sample_dt, t_end, dt, exclude);
+        runner.run(sim, ncomp, sample_dt, t_end, dt, exclude);
     }
     runner.report();
     runner.assert_all_convergence();
diff --git a/tests/validation/validate_compartment_policy.cpp b/tests/validation/validate_compartment_policy.cpp
index c9ee4d3643bf30ec0f41bb7641f1304449d5c3ff..27c944ed07eab92a0d3bcc8269208d5a95a9784e 100644
--- a/tests/validation/validate_compartment_policy.cpp
+++ b/tests/validation/validate_compartment_policy.cpp
@@ -5,7 +5,7 @@
 
 #include <common_types.hpp>
 #include <cell.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
 #include <util/rangeutil.hpp>
@@ -32,8 +32,8 @@ using namespace arb;
  */
 
 template <typename CompPolicy>
-std::vector<trace_data> run_model(const cell& c, float sample_dt, float t_end, float dt) {
-    model<fvm::fvm_multicell<double, cell_local_size_type, div_compartment_by_ends>> m{singleton_recipe(c)};
+std::vector<trace_data> run_simulation(const cell& c, float sample_dt, float t_end, float dt) {
+    simulation<fvm::fvm_multicell<double, cell_local_size_type, div_compartment_by_ends>> m{singleton_recipe(c)};
 
     const auto& probes = m.probes();
     std::size_t n_probes = probes.size();
@@ -59,9 +59,9 @@ void run_test(cell&& c) {
     float t_end = 100;
     float dt = 0.001;
 
-    auto traces_by_ends = run_model<div_compartment_by_ends>(c, sample_dt, t_end, dt);
-    auto traces_sampler = run_model<div_compartment_sampler>(c, sample_dt, t_end, dt);
-    auto traces_integrator = run_model<div_compartment_integrator>(c, sample_dt, t_end, dt);
+    auto traces_by_ends = run_simulation<div_compartment_by_ends>(c, sample_dt, t_end, dt);
+    auto traces_sampler = run_simulation<div_compartment_sampler>(c, sample_dt, t_end, dt);
+    auto traces_integrator = run_simulation<div_compartment_integrator>(c, sample_dt, t_end, dt);
 
     auto n_trace = traces_by_ends.size();
     ASSERT_GT(n_trace, 0);
diff --git a/tests/validation/validate_kinetic.cpp b/tests/validation/validate_kinetic.cpp
index 83cc8d18eeaa7bbd77d754381ac89aec686d06f5..f501f4fbd59ede1cbe3ecea22ae99abe4c1763f8 100644
--- a/tests/validation/validate_kinetic.cpp
+++ b/tests/validation/validate_kinetic.cpp
@@ -7,7 +7,7 @@
 #include <hardware/node_info.hpp>
 #include <hardware/gpu.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
 #include <util/rangeutil.hpp>
@@ -43,7 +43,7 @@ void run_kinetic_dt(
 
     hw::node_info nd(1, backend==backend_kind::gpu? 1: 0);
     auto decomp = partition_load_balance(rec, nd);
-    model model(rec, decomp);
+    simulation sim(rec, decomp);
 
     auto exclude = stimulus_ends(c);
 
@@ -54,9 +54,9 @@ void run_kinetic_dt(
             double oo_dt = base/multiple;
             if (oo_dt>max_oo_dt) goto end;
 
-            model.reset();
+            sim.reset();
             float dt = float(1./oo_dt);
-            runner.run(model, dt, sample_dt, t_end, dt, exclude);
+            runner.run(sim, dt, sample_dt, t_end, dt, exclude);
         }
     }
 
diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp
index 8d0e3e8e5fbae68f40d3f2c252caf9b9d7c2247e..a5a6f6a2c052ac6445d31230240e0c8f61c48c2b 100644
--- a/tests/validation/validate_soma.cpp
+++ b/tests/validation/validate_soma.cpp
@@ -5,7 +5,7 @@
 #include <hardware/gpu.hpp>
 #include <hardware/node_info.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
 #include <util/rangeutil.hpp>
@@ -32,7 +32,7 @@ void validate_soma(backend_kind backend) {
 
     hw::node_info nd(1, backend==backend_kind::gpu? 1: 0);
     auto decomp = partition_load_balance(rec, nd);
-    model m(rec, decomp);
+    simulation sim(rec, decomp);
 
     nlohmann::json meta = {
         {"name", "membrane voltage"},
@@ -54,9 +54,9 @@ void validate_soma(backend_kind backend) {
             double oo_dt = base/multiple;
             if (oo_dt>max_oo_dt) goto end;
 
-            m.reset();
+            sim.reset();
             float dt = float(1./oo_dt);
-            runner.run(m, dt, sample_dt, t_end, dt, {});
+            runner.run(sim, dt, sample_dt, t_end, dt, {});
         }
     }
 end:
diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp
index 31a7bf3fa022d430df6b52b6fc26288d5db6d281..527262ecd826d59eb2d341d4e3ba52fd333dc092 100644
--- a/tests/validation/validate_synapses.cpp
+++ b/tests/validation/validate_synapses.cpp
@@ -4,7 +4,7 @@
 #include <hardware/gpu.hpp>
 #include <json/json.hpp>
 #include <load_balance.hpp>
-#include <model.hpp>
+#include <simulation.hpp>
 #include <recipe.hpp>
 #include <simple_sampler.hpp>
 #include <util/path.hpp>
@@ -73,11 +73,11 @@ void run_synapse_test(
         rec.add_probe(0, 0, cell_probe_address{{1, 1.0}, cell_probe_address::membrane_voltage});
 
         auto decomp = partition_load_balance(rec, nd);
-        model m(rec, decomp);
+        simulation sim(rec, decomp);
 
-        m.inject_events(synthetic_events);
+        sim.inject_events(synthetic_events);
 
-        runner.run(m, ncomp, sample_dt, t_end, dt, exclude);
+        runner.run(sim, ncomp, sample_dt, t_end, dt, exclude);
     }
     runner.report();
     runner.assert_all_convergence();