diff --git a/pybamm/discretisations/base_discretisation.py b/pybamm/discretisations/base_discretisation.py
index fb66ed60..e5326af3 100644
--- a/pybamm/discretisations/base_discretisation.py
+++ b/pybamm/discretisations/base_discretisation.py
@@ -5,6 +5,7 @@ from __future__ import absolute_import, division
 from __future__ import print_function, unicode_literals
 import pybamm
 
+import copy
 import numpy as np
 
 
@@ -262,22 +263,10 @@ class BaseDiscretisation(object):
 
             return new_symbol
 
-        elif isinstance(symbol, pybamm.Scalar):
-            return pybamm.Scalar(symbol.value, domain=symbol.domain)
-
-        elif isinstance(symbol, pybamm.Array):
-            return symbol.__class__(symbol.entries, domain=symbol.domain)
-
         else:
-            raise NotImplementedError
-            # hack to copy the symbol but without a parent
-            # (building tree from bottom up)
-            # simply setting new_symbol.parent = None, after copying, raises a TreeError
-            # parent = symbol.parent
-            # symbol.parent = None
-            # new_symbol = copy.copy(symbol)
-            # symbol.parent = parent
-            # return new_symbol
+            new_symbol = copy.deepcopy(symbol)
+            new_symbol.parent = None
+            return new_symbol
 
     def process_binary_operators(self, bin_op, y_slices, boundary_conditions):
         """Discretise binary operators in model equations.  Performs appropriate
diff --git a/pybamm/expression_tree/symbol.py b/pybamm/expression_tree/symbol.py
index d88662bb..78d4ef01 100644
--- a/pybamm/expression_tree/symbol.py
+++ b/pybamm/expression_tree/symbol.py
@@ -36,7 +36,6 @@ class Symbol(anytree.NodeMixin):
             # copy child before adding
             # this also adds copy.copy(child) to self.children
             copy.copy(child).parent = self
-
         self.domain = domain
 
     @property
@@ -101,6 +100,19 @@ class Symbol(anytree.NodeMixin):
             + tuple(self.domain)
         )
 
+    @property
+    def orphans(self):
+        """
+        Returning deepcopies of the children, with parents removed to avoid corrupting
+        the expression tree internal data
+        """
+        orp = []
+        for child in self.children:
+            new_child = copy.deepcopy(child)
+            new_child.parent = None
+            orp.append(new_child)
+        return tuple(orp)
+
     def render(self):
         """print out a visual representation of the tree (this node and its
         children)
diff --git a/pybamm/parameters/parameter_values.py b/pybamm/parameters/parameter_values.py
index 5a9535f4..eeb60a94 100644
--- a/pybamm/parameters/parameter_values.py
+++ b/pybamm/parameters/parameter_values.py
@@ -168,11 +168,6 @@ class ParameterValues(dict):
             return pybamm.Concatenation(*new_children)
 
         else:
-            # hack to copy the symbol but without a parent
-            # (building tree from bottom up)
-            # simply setting new_symbol.parent = None, after copying, raises a TreeError
-            parent = symbol.parent
-            symbol.parent = None
-            new_symbol = copy.copy(symbol)
-            symbol.parent = parent
+            new_symbol = copy.deepcopy(symbol)
+            new_symbol.parent = None
             return new_symbol

Unpack a concatenation of variables (overwrite Symbol.__copy__ to remove parent)
## Problem

In some cases, we want to unpack a concatenation (usually of variables). The natural way would be 
```python3
# make concatenation
var_n = Variable("var", ["negative electrode"])
var_s = Variable("var", ["separator"])
var_p = Variable("var", ["positive electrode"])
var = Concatenation(var_n, var_s, var_p)
# unpack
newvar_n, newvar_s, newvar_p = var.children
```
However, manipulating the `newvar` objects then causes issues with the expression tree (tree internal data is corrupt)

## Suggested change

Write an `unpack_concatenation` function that unpacks a Concatenation object by creating new `Variable` objects with the same `name` and `domain` but no `parent` (and no `children` - `Variable` never has children anyway)

diff --git a/tests/test_discretisations/test_base_discretisations.py b/tests/test_discretisations/test_base_discretisations.py
index d24f0c94..e23d5bc3 100644
--- a/tests/test_discretisations/test_base_discretisations.py
+++ b/tests/test_discretisations/test_base_discretisations.py
@@ -129,10 +129,6 @@ class TestDiscretise(unittest.TestCase):
         self.assertIsInstance(un2_disc, pybamm.AbsoluteValue)
         self.assertIsInstance(un2_disc.children[0], pybamm.Scalar)
 
-        # parameter should fail
-        with self.assertRaises(NotImplementedError):
-            disc.process_symbol(pybamm.Parameter("par"))
-
     def test_process_complex_expression(self):
         var1 = pybamm.Variable("var1")
         var2 = pybamm.Variable("var2")
@@ -229,11 +225,7 @@ class TestDiscretise(unittest.TestCase):
 
     def test_core_NotImplementedErrors(self):
         # create discretisation
-        defaults = shared.TestDefaults1DMacro()
-        disc = shared.DiscretisationForTesting(
-            defaults.mesh_type, defaults.submesh_pts, defaults.submesh_types
-        )
-        disc.mesh_geometry(defaults.geometry)
+        disc = pybamm.BaseDiscretisation(None, None, None)
 
         with self.assertRaises(NotImplementedError):
             disc.gradient(None, None, {})
diff --git a/tests/test_expression_tree/test_concatenations.py b/tests/test_expression_tree/test_concatenations.py
index 04225588..f6f14871 100644
--- a/tests/test_expression_tree/test_concatenations.py
+++ b/tests/test_expression_tree/test_concatenations.py
@@ -128,6 +128,24 @@ class TestConcatenations(unittest.TestCase):
             ),
         )
 
+    def test_concatenation_orphans(self):
+        a = pybamm.Variable("a")
+        b = pybamm.Variable("b")
+        c = pybamm.Variable("c")
+        conc = pybamm.Concatenation(a, b, c)
+        a_new, b_new, c_new = conc.orphans
+
+        # We should be able to manipulate the children without TreeErrors
+        self.assertIsInstance(2 * a_new, pybamm.Multiplication)
+        self.assertIsInstance(3 + b_new, pybamm.Addition)
+        self.assertIsInstance(4 - c_new, pybamm.Subtraction)
+
+        # ids should stay the same
+        self.assertEqual(a.id, a_new.id)
+        self.assertEqual(b.id, b_new.id)
+        self.assertEqual(c.id, c_new.id)
+        self.assertEqual(conc.id, pybamm.Concatenation(a_new, b_new, c_new).id)
+
 
 if __name__ == "__main__":
     print("Add -v for more debug output")
diff --git a/tests/test_expression_tree/test_symbol.py b/tests/test_expression_tree/test_symbol.py
index 98b593f3..85b145ed 100644
--- a/tests/test_expression_tree/test_symbol.py
+++ b/tests/test_expression_tree/test_symbol.py
@@ -231,6 +231,17 @@ class TestSymbol(unittest.TestCase):
         self.assertFalse(algebraic_eqn.has_gradient())
         self.assertFalse(algebraic_eqn.has_divergence())
 
+    def test_orphans(self):
+        a = pybamm.Symbol("a")
+        b = pybamm.Symbol("b")
+        sum = a + b
+
+        a_orp, b_orp = sum.orphans
+        self.assertIsNone(a_orp.parent)
+        self.assertIsNone(b_orp.parent)
+        self.assertEqual(a.id, a_orp.id)
+        self.assertEqual(b.id, b_orp.id)
+
 
 if __name__ == "__main__":
     print("Add -v for more debug output")

pip install -e .[dev,docs]
parse_log_pytest
requirements.txt
pytest
apt-get update apt-get install -y gcc gfortran libopenblas-dev liblapack-dev
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.13
anyio==3.6.2
anytree==2.8.0
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
async-generator==1.10
attrs==22.2.0
Babel==2.11.0
backcall==0.2.0
bleach==4.1.0
certifi==2021.5.30
cffi==1.15.1
charset-normalizer==2.0.12
comm==0.1.4
contextvars==2.4
cycler==0.11.0
dataclasses==0.8
decorator==5.1.1
defusedxml==0.7.1
docutils==0.17.1
entrypoints==0.4
flake8==5.0.4
guzzle-sphinx-theme==0.7.11
idna==3.10
imagesize==1.4.1
immutables==0.19
importlib-metadata==4.2.0
iniconfig==1.1.1
ipykernel==5.5.6
ipython==7.16.3
ipython-genutils==0.2.0
ipywidgets==7.8.5
jedi==0.17.2
Jinja2==3.0.3
json5==0.9.16
jsonschema==3.2.0
jupyter==1.1.1
jupyter-client==7.1.2
jupyter-console==6.4.3
jupyter-core==4.9.2
jupyter-server==1.13.1
jupyterlab==3.2.9
jupyterlab-pygments==0.1.2
jupyterlab-server==2.10.3
jupyterlab_widgets==1.1.11
kiwisolver==1.3.1
MarkupSafe==2.0.1
matplotlib==3.3.4
mccabe==0.7.0
mistune==0.8.4
nbclassic==0.3.5
nbclient==0.5.9
nbconvert==6.0.7
nbformat==5.1.3
nest-asyncio==1.6.0
notebook==6.4.10
numpy==1.19.5
packaging==21.3
pandas==1.1.5
pandocfilters==1.5.1
parso==0.7.1
pexpect==4.9.0
pickleshare==0.7.5
Pillow==8.4.0
pluggy==1.0.0
prometheus-client==0.17.1
prompt-toolkit==3.0.36
ptyprocess==0.7.0
py==1.11.0
-e git+https://github.com/tinosulzer/PyBaMM.git@0d2ee9977910b7a07c759b8bf9f3b0ff65bcb688#egg=pybamm
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.14.0
pyparsing==3.1.4
pyrsistent==0.18.0
pytest==7.0.1
python-dateutil==2.9.0.post0
pytz==2025.2
pyzmq==25.1.2
requests==2.27.1
scipy==1.5.4
Send2Trash==1.8.3
six==1.17.0
sniffio==1.2.0
snowballstemmer==2.2.0
Sphinx==4.3.2
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
terminado==0.12.1
testpath==0.6.0
tomli==1.2.3
tornado==6.1
traitlets==4.3.3
typing_extensions==4.1.1
urllib3==1.26.20
wcwidth==0.2.13
webencodings==0.5.1
websocket-client==1.3.1
widgetsnbextension==3.6.10
zipp==3.6.0

name: PyBaMM
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.13
      - anyio==3.6.2
      - anytree==2.8.0
      - argon2-cffi==21.3.0
      - argon2-cffi-bindings==21.2.0
      - async-generator==1.10
      - attrs==22.2.0
      - babel==2.11.0
      - backcall==0.2.0
      - bleach==4.1.0
      - cffi==1.15.1
      - charset-normalizer==2.0.12
      - comm==0.1.4
      - contextvars==2.4
      - cycler==0.11.0
      - dataclasses==0.8
      - decorator==5.1.1
      - defusedxml==0.7.1
      - docutils==0.17.1
      - entrypoints==0.4
      - flake8==5.0.4
      - guzzle-sphinx-theme==0.7.11
      - idna==3.10
      - imagesize==1.4.1
      - immutables==0.19
      - importlib-metadata==4.2.0
      - iniconfig==1.1.1
      - ipykernel==5.5.6
      - ipython==7.16.3
      - ipython-genutils==0.2.0
      - ipywidgets==7.8.5
      - jedi==0.17.2
      - jinja2==3.0.3
      - json5==0.9.16
      - jsonschema==3.2.0
      - jupyter==1.1.1
      - jupyter-client==7.1.2
      - jupyter-console==6.4.3
      - jupyter-core==4.9.2
      - jupyter-server==1.13.1
      - jupyterlab==3.2.9
      - jupyterlab-pygments==0.1.2
      - jupyterlab-server==2.10.3
      - jupyterlab-widgets==1.1.11
      - kiwisolver==1.3.1
      - markupsafe==2.0.1
      - matplotlib==3.3.4
      - mccabe==0.7.0
      - mistune==0.8.4
      - nbclassic==0.3.5
      - nbclient==0.5.9
      - nbconvert==6.0.7
      - nbformat==5.1.3
      - nest-asyncio==1.6.0
      - notebook==6.4.10
      - numpy==1.19.5
      - packaging==21.3
      - pandas==1.1.5
      - pandocfilters==1.5.1
      - parso==0.7.1
      - pexpect==4.9.0
      - pickleshare==0.7.5
      - pillow==8.4.0
      - pluggy==1.0.0
      - prometheus-client==0.17.1
      - prompt-toolkit==3.0.36
      - ptyprocess==0.7.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pyrsistent==0.18.0
      - pytest==7.0.1
      - python-dateutil==2.9.0.post0
      - pytz==2025.2
      - pyzmq==25.1.2
      - requests==2.27.1
      - scipy==1.5.4
      - send2trash==1.8.3
      - six==1.17.0
      - sniffio==1.2.0
      - snowballstemmer==2.2.0
      - sphinx==4.3.2
      - sphinxcontrib-applehelp==1.0.2
      - sphinxcontrib-devhelp==1.0.2
      - sphinxcontrib-htmlhelp==2.0.0
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==1.0.3
      - sphinxcontrib-serializinghtml==1.1.5
      - terminado==0.12.1
      - testpath==0.6.0
      - tomli==1.2.3
      - tornado==6.1
      - traitlets==4.3.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - wcwidth==0.2.13
      - webencodings==0.5.1
      - websocket-client==1.3.1
      - widgetsnbextension==3.6.10
      - zipp==3.6.0
prefix: /opt/conda/envs/PyBaMM

tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_concatenation_orphans tests/test_expression_tree/test_symbol.py::TestSymbol::test_orphans
tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_broadcast tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_concatenate_init tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_concatenation tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_concatenation_of_scalars tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_core_NotImplementedErrors tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_discretise_slicing tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_discretise_space tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_discretise_spatial_operator tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_process_complex_expression tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_process_dict tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_process_model_dae tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_process_model_ode tests/test_discretisations/test_base_discretisations.py::TestDiscretise::test_process_symbol_base tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_base_concatenation tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_concatenation_domains tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_numpy_domain_concatenation tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_numpy_model_concatenation_vector_scalar tests/test_expression_tree/test_concatenations.py::TestConcatenations::test_numpy_model_concatenation_vectors tests/test_expression_tree/test_symbol.py::TestSymbol::test_has_spatial_derivatives tests/test_expression_tree/test_symbol.py::TestSymbol::test_multiple_symbols tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_domains tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_evaluates_to_number tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_evaluation tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_init tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_is_constant tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_methods tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_repr tests/test_expression_tree/test_symbol.py::TestSymbol::test_symbol_visualise
pybamm/parameters/parameter_values.py pybamm/discretisations/base_discretisation.py pybamm/expression_tree/symbol.py
pybamm/parameters/parameter_values.py pybamm/discretisations/base_discretisation.py pybamm/expression_tree/symbol.py