diff --git a/arbor/backends/gpu/shared_state.cpp b/arbor/backends/gpu/shared_state.cpp
index bed738bc86b5d74e45105a932147621477d79ff7..b01cd663082d365c9e33afa82051ee06ce1d9262 100644
--- a/arbor/backends/gpu/shared_state.cpp
+++ b/arbor/backends/gpu/shared_state.cpp
@@ -57,11 +57,14 @@ ion_state::ion_state(
     const fvm_ion_config& ion_data,
     unsigned // alignment/padding ignored.
 ):
+    write_eX_(ion_data.revpot_written),
+    write_Xo_(ion_data.econc_written),
+    write_Xi_(ion_data.iconc_written),
     node_index_(make_const_view(ion_data.cv)),
     iX_(ion_data.cv.size(), NAN),
-    eX_(ion_data.cv.size(), NAN),
-    Xi_(ion_data.cv.size(), NAN),
-    Xo_(ion_data.cv.size(), NAN),
+    eX_(ion_data.init_revpot.begin(), ion_data.init_revpot.end()),
+    Xi_(ion_data.init_iconc.begin(), ion_data.init_iconc.end()),
+    Xo_(ion_data.init_econc.begin(), ion_data.init_econc.end()),
     init_Xi_(make_const_view(ion_data.init_iconc)),
     init_Xo_(make_const_view(ion_data.init_econc)),
     reset_Xi_(make_const_view(ion_data.reset_iconc)),
@@ -75,8 +78,8 @@ ion_state::ion_state(
 }
 
 void ion_state::init_concentration() {
-    memory::copy(init_Xi_, Xi_);
-    memory::copy(init_Xo_, Xo_);
+    if (write_Xi_) memory::copy(init_Xi_, Xi_);
+    if (write_Xo_) memory::copy(init_Xo_, Xo_);
 }
 
 void ion_state::zero_current() {
@@ -85,9 +88,9 @@ void ion_state::zero_current() {
 
 void ion_state::reset() {
     zero_current();
-    memory::copy(reset_Xi_, Xi_);
-    memory::copy(reset_Xo_, Xo_);
-    memory::copy(init_eX_, eX_);
+    if (write_Xi_) memory::copy(reset_Xi_, Xi_);
+    if (write_Xo_) memory::copy(reset_Xo_, Xo_);
+    if (write_eX_) memory::copy(init_eX_, eX_);
 }
 
 // istim_state methods:
diff --git a/arbor/backends/gpu/shared_state.hpp b/arbor/backends/gpu/shared_state.hpp
index e0cacfc78d95acf1bf62d81d9d9cc01cf16d07a0..85f1ea0c451331d59338bebf0747567c0cc8a91c 100644
--- a/arbor/backends/gpu/shared_state.hpp
+++ b/arbor/backends/gpu/shared_state.hpp
@@ -27,8 +27,11 @@ namespace gpu {
  *     Xi_     cai              internal calcium concentration
  *     Xo_     cao              external calcium concentration
  */
+ struct ARB_ARBOR_API ion_state {
+    bool write_eX_;          // is eX written?
+    bool write_Xo_;          // is Xo written?
+    bool write_Xi_;          // is Xi written?
 
-struct ARB_ARBOR_API ion_state {
     iarray node_index_; // Instance to CV map.
     array iX_;          // (A/m²) current density
     array eX_;          // (mV) reversal potential
diff --git a/arbor/backends/multicore/shared_state.cpp b/arbor/backends/multicore/shared_state.cpp
index 538f7718d56db69592d5dc0bd76b86b42a7f12e6..f6c0b205714fa4cfacd7cabe575bd7373d04cac2 100644
--- a/arbor/backends/multicore/shared_state.cpp
+++ b/arbor/backends/multicore/shared_state.cpp
@@ -59,11 +59,14 @@ ion_state::ion_state(
     unsigned align
 ):
     alignment(min_alignment(align)),
+    write_eX_(ion_data.revpot_written),
+    write_Xo_(ion_data.econc_written),
+    write_Xi_(ion_data.iconc_written),
     node_index_(ion_data.cv.begin(), ion_data.cv.end(), pad(alignment)),
     iX_(ion_data.cv.size(), NAN, pad(alignment)),
     eX_(ion_data.init_revpot.begin(), ion_data.init_revpot.end(), pad(alignment)),
-    Xi_(ion_data.cv.size(), NAN, pad(alignment)),
-    Xo_(ion_data.cv.size(), NAN, pad(alignment)),
+    Xi_(ion_data.init_iconc.begin(), ion_data.init_iconc.end(), pad(alignment)),
+    Xo_(ion_data.init_econc.begin(), ion_data.init_econc.end(), pad(alignment)),
     init_Xi_(ion_data.init_iconc.begin(), ion_data.init_iconc.end(), pad(alignment)),
     init_Xo_(ion_data.init_econc.begin(), ion_data.init_econc.end(), pad(alignment)),
     reset_Xi_(ion_data.reset_iconc.begin(), ion_data.reset_iconc.end(), pad(alignment)),
@@ -78,8 +81,8 @@ ion_state::ion_state(
 }
 
 void ion_state::init_concentration() {
-    std::copy(init_Xi_.begin(), init_Xi_.end(), Xi_.begin());
-    std::copy(init_Xo_.begin(), init_Xo_.end(), Xo_.begin());
+    if (write_Xi_) std::copy(init_Xi_.begin(), init_Xi_.end(), Xi_.begin());
+    if (write_Xo_) std::copy(init_Xo_.begin(), init_Xo_.end(), Xo_.begin());
 }
 
 void ion_state::zero_current() {
@@ -88,9 +91,9 @@ void ion_state::zero_current() {
 
 void ion_state::reset() {
     zero_current();
-    std::copy(reset_Xi_.begin(), reset_Xi_.end(), Xi_.begin());
-    std::copy(reset_Xo_.begin(), reset_Xo_.end(), Xo_.begin());
-    std::copy(init_eX_.begin(), init_eX_.end(), eX_.begin());
+    if (write_Xi_) std::copy(reset_Xi_.begin(), reset_Xi_.end(), Xi_.begin());
+    if (write_Xo_) std::copy(reset_Xo_.begin(), reset_Xo_.end(), Xo_.begin());
+    if (write_eX_) std::copy(init_eX_.begin(), init_eX_.end(), eX_.begin());
 }
 
 // istim_state methods:
@@ -239,8 +242,7 @@ shared_state::shared_state(
 void shared_state::add_ion(
     const std::string& ion_name,
     int charge,
-    const fvm_ion_config& ion_info)
-{
+    const fvm_ion_config& ion_info) {
     ion_data.emplace(std::piecewise_construct,
         std::forward_as_tuple(ion_name),
         std::forward_as_tuple(charge, ion_info, alignment));
diff --git a/arbor/backends/multicore/shared_state.hpp b/arbor/backends/multicore/shared_state.hpp
index ab9fa7f5342bd463b5ec015dc695b73f641f4aab..8aa8d4155141efb78fae60a14d660eddc6565cd5 100644
--- a/arbor/backends/multicore/shared_state.hpp
+++ b/arbor/backends/multicore/shared_state.hpp
@@ -38,10 +38,13 @@ namespace multicore {
  *     Xi_     cai              internal calcium concentration
  *     Xo_     cao              external calcium concentration
  */
-
 struct ARB_ARBOR_API ion_state {
     unsigned alignment = 1; // Alignment and padding multiple.
 
+    bool write_eX_;          // is eX written?
+    bool write_Xo_;          // is Xo written?
+    bool write_Xi_;          // is Xi written?
+
     iarray node_index_;     // Instance to CV map.
     array iX_;              // (A/m²) current density
     array eX_;              // (mV) reversal potential
diff --git a/arbor/fvm_layout.cpp b/arbor/fvm_layout.cpp
index f231defdabf62d9678dba21a9730f34e566fc3f8..7ede9f7c8fe816da055c78e240b1a8c5c4761e29 100644
--- a/arbor/fvm_layout.cpp
+++ b/arbor/fvm_layout.cpp
@@ -595,9 +595,8 @@ fvm_mechanism_data& append(fvm_mechanism_data& left, const fvm_mechanism_data& r
 
     fvm_size_type target_offset = left.n_target;
 
-    for (const auto& kv: right.ions) {
-        fvm_ion_config& L = left.ions[kv.first];
-        const fvm_ion_config& R = kv.second;
+    for (const auto& [k, R]: right.ions) {
+        fvm_ion_config& L = left.ions[k];
 
         append(L.cv, R.cv);
         append(L.init_iconc, R.init_iconc);
@@ -605,6 +604,9 @@ fvm_mechanism_data& append(fvm_mechanism_data& left, const fvm_mechanism_data& r
         append(L.reset_iconc, R.reset_iconc);
         append(L.reset_econc, R.reset_econc);
         append(L.init_revpot, R.init_revpot);
+        L.econc_written  |= R.econc_written;
+        L.iconc_written  |= R.iconc_written;
+        L.revpot_written |= R.revpot_written;
     }
 
     for (const auto& kv: right.mechanisms) {
@@ -744,6 +746,9 @@ fvm_mechanism_data fvm_build_mechanism_data(
     const auto& global_dflt = gprop.default_parameters;
     const auto& dflt = cell.default_parameters();
 
+    std::unordered_set<std::string> write_xi;
+    std::unordered_set<std::string> write_xo;
+
     fvm_mechanism_data M;
 
     // Verify mechanism ion usage, parameter values.
@@ -867,18 +872,20 @@ fvm_mechanism_data fvm_build_mechanism_data(
             }
         }
 
-        for (const auto& iondep: info.ions) {
-            if (iondep.second.write_concentration_int) {
+        for (const auto& [ion, dep]: info.ions) {
+            if (dep.write_concentration_int) {
+                write_xi.insert(ion);
                 for (auto c: support) {
-                    bool ok = init_iconc_mask[iondep.first].insert(c.first, 0.);
+                    bool ok = init_iconc_mask[ion].insert(c.first, 0.);
                     if (!ok) {
                         throw cable_cell_error("overlapping ion concentration writing mechanism "+name);
                     }
                 }
             }
-            if (iondep.second.write_concentration_ext) {
+            if (dep.write_concentration_ext) {
+                write_xo.insert(ion);
                 for (auto c: support) {
-                    bool ok = init_econc_mask[iondep.first].insert(c.first, 0.);
+                    bool ok = init_econc_mask[ion].insert(c.first, 0.);
                     if (!ok) {
                         throw cable_cell_error("overlapping ion concentration writing mechanism "+name);
                     }
@@ -993,7 +1000,7 @@ fvm_mechanism_data fvm_build_mechanism_data(
             return a.target_index<b.target_index;
         });
 
-        bool coalesce = catalogue[name].linear && gprop.coalesce_synapses;
+        bool coalesce = info.linear && gprop.coalesce_synapses;
 
         fvm_mechanism_config config;
         config.kind = arb_mechanism_kind_point;
@@ -1029,6 +1036,15 @@ fvm_mechanism_data fvm_build_mechanism_data(
         // If synapse uses an ion, add to ion support.
         update_ion_support(info, config.cv);
 
+        for (const auto& [ion, dep]: info.ions) {
+            if (dep.write_concentration_int) {
+                write_xi.insert(ion);
+            }
+            if (dep.write_concentration_ext) {
+                write_xo.insert(ion);
+            }
+        }
+
         M.n_target += config.target.size();
         if (!config.cv.empty()) M.mechanisms[name] = std::move(config);
     }
@@ -1091,6 +1107,16 @@ fvm_mechanism_data fvm_build_mechanism_data(
             }
             lid_junction_desc.insert({pm.lid, std::move(per_lid)});
         }
+
+        for (const auto& [ion, dep]: info.ions) {
+            if (dep.write_concentration_int) {
+                write_xi.insert(ion);
+            }
+            if (dep.write_concentration_ext) {
+                write_xo.insert(ion);
+            }
+        }
+
         junction_configs[name] = std::move(config);
     }
 
@@ -1169,11 +1195,9 @@ fvm_mechanism_data fvm_build_mechanism_data(
     auto initial_econc_map = cell.region_assignments().get<init_ext_concentration>();
     auto initial_rvpot_map = cell.region_assignments().get<init_reversal_potential>();
 
-    for (const auto& ion_cvs: ion_support) {
-        const std::string& ion = ion_cvs.first;
-
+    for (const auto& [ion, cvs]: ion_support) {
         fvm_ion_config config;
-        config.cv = ion_cvs.second;
+        config.cv = cvs;
 
         auto n_cv = config.cv.size();
         config.init_iconc.resize(n_cv);
@@ -1229,6 +1253,8 @@ fvm_mechanism_data fvm_build_mechanism_data(
             config.init_econc[i] *= oo_cv_area;
         }
 
+        config.econc_written  = write_xo.count(ion);
+        config.iconc_written  = write_xi.count(ion);
         if (!config.cv.empty()) M.ions[ion] = std::move(config);
     }
 
@@ -1269,6 +1295,8 @@ fvm_mechanism_data fvm_build_mechanism_data(
                 throw cable_cell_error("revpot mechanism for ion "+ion+" does not write this reversal potential");
             }
 
+            M.ions[ion].revpot_written = true;
+
             // Only instantiate if the ion is used.
             if (M.ions.count(ion)) {
                 // Revpot mechanism already configured? Add cvs for this ion too.
diff --git a/arbor/fvm_layout.hpp b/arbor/fvm_layout.hpp
index 1ebe0827aa4dd06d0e5cfb043055b1a7075abbd4..b81debcd8111d2e0f8822ae554ec8fcaa0689aa1 100644
--- a/arbor/fvm_layout.hpp
+++ b/arbor/fvm_layout.hpp
@@ -224,6 +224,11 @@ struct fvm_ion_config {
     using value_type = fvm_value_type;
     using index_type = fvm_index_type;
 
+    // Keep track whether eX, Xi, Xo are actually to be reset.
+    bool revpot_written = false;
+    bool iconc_written = false;
+    bool econc_written = false;
+
     // Ordered CV indices where ion must be present.
     std::vector<index_type> cv;
 
diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp
index a548e4af16e75201b66676f07798a6cc8c51472b..ddfe104e4add2789aa2d7a80ddf331bcb2e128b8 100644
--- a/arbor/fvm_lowered_cell_impl.hpp
+++ b/arbor/fvm_lowered_cell_impl.hpp
@@ -503,14 +503,12 @@ fvm_initialization_data fvm_lowered_cell_impl<Backend>::initialize(
 
     // Instantiate mechanisms, ions, and stimuli.
 
-    for (auto& i: mech_data.ions) {
-        const std::string& ion_name = i.first;
-
-        if (auto charge = value_by_key(global_props.ion_species, ion_name)) {
-            state_->add_ion(ion_name, *charge, i.second);
+    for (const auto& [ion, data]: mech_data.ions) {
+        if (auto charge = value_by_key(global_props.ion_species, ion)) {
+            state_->add_ion(ion, *charge, data);
         }
         else {
-            throw cable_cell_error("unrecognized ion '"+ion_name+"' in mechanism");
+            throw cable_cell_error("unrecognized ion '"+ion+"' in mechanism");
         }
     }
 
diff --git a/arbor/version.cpp b/arbor/version.cpp
index 88b693891f53ae9cf31b4f03edc2a8dd959c5ba2..242a6fdde77fa978b434f1665e3026bdb8c6376d 100644
--- a/arbor/version.cpp
+++ b/arbor/version.cpp
@@ -1,4 +1,5 @@
 #include <arbor/version.hpp>
+#include <arbor/export.hpp>
 
 namespace arb {
 ARB_ARBOR_API const char* source_id = ARB_SOURCE_ID;
diff --git a/test/unit/test_fvm_lowered.cpp b/test/unit/test_fvm_lowered.cpp
index e1599b5d7f719f568a97c7cfdbdb4f691b28dd08..b07208fdcf85c9445239d685027621936b4274e4 100644
--- a/test/unit/test_fvm_lowered.cpp
+++ b/test/unit/test_fvm_lowered.cpp
@@ -591,6 +591,9 @@ TEST(fvm_lowered, ionic_concentrations) {
         layout.cv.push_back(i);
         ion_config.cv.push_back(i);
     }
+    ion_config.econc_written  = true;
+    ion_config.iconc_written  = true;
+    ion_config.revpot_written = true;
     ion_config.init_revpot.assign(ncv, 0.);
     ion_config.init_econc.assign(ncv, 0.);
     ion_config.init_iconc.assign(ncv, 0.);
diff --git a/test/unit/test_probe.cpp b/test/unit/test_probe.cpp
index 4608bb1d4c938e634dcf47517e212f5ddba7b162..bc9f41c374678bd4f2251c3072d58402fdfd38ed 100644
--- a/test/unit/test_probe.cpp
+++ b/test/unit/test_probe.cpp
@@ -549,7 +549,19 @@ void run_ion_density_probe_test(const context& ctx) {
     rec.add_probe(0, 0, cable_probe_ion_ext_concentration_cell{"ca"});
 
     fvm_cell lcell(*ctx);
+
     auto fvm_info = lcell.initialize({0}, rec);
+    // We skipped FVM layout here, so we need to set these manually
+    auto& state = backend_access<Backend>::state(lcell);
+    state.ion_data["ca"].write_Xi_ = true;
+    state.ion_data["ca"].write_Xo_ = true;
+    state.ion_data["ca"].init_concentration();
+    state.ion_data["na"].write_Xi_ = true;
+    state.ion_data["na"].write_Xo_ = true;
+    state.ion_data["na"].init_concentration();
+    // Now, re-init cell
+    lcell.reset();
+
     const auto& probe_map = fvm_info.probe_map;
 
     // Should be no sodium ion instantiated on CV 0, so probe (0, 6) should