diff --git a/apps/showcases/ChargedParticles/ChargedParticles.cpp b/apps/showcases/ChargedParticles/ChargedParticles.cpp
index 2b52936283a7d3c61e2f3d26fab767b2f74862e1..8bdf6d8770dab0314c78f8c978b00c665443a50a 100644
--- a/apps/showcases/ChargedParticles/ChargedParticles.cpp
+++ b/apps/showcases/ChargedParticles/ChargedParticles.cpp
@@ -1163,7 +1163,7 @@ int main(int argc, char** argv)
       // Compute electrostatic force field from electric potential (using finite differences)
       chargeForceUpdate();
       reduceProperty.operator()< mesa_pd::ElectrostaticForceNotification >(*ps);
-      WriteElectrostaticForces< ParticleAccessor_T >(accessor, timeStep);
+      //WriteElectrostaticForces< ParticleAccessor_T >(accessor, timeStep);
 
       if (timeStep == 0)
       {
diff --git a/apps/showcases/ChargedParticles/ErrorNorms.h b/apps/showcases/ChargedParticles/ErrorNorms.h
new file mode 100644
index 0000000000000000000000000000000000000000..103c79580c948c2ec5bf7d8e40834deca299ec78
--- /dev/null
+++ b/apps/showcases/ChargedParticles/ErrorNorms.h
@@ -0,0 +1,125 @@
+//
+// Created by avnss on 4/21/2023.
+//
+
+#ifndef WALBERLA_ERRORNORMS_H
+#define WALBERLA_ERRORNORMS_H
+
+namespace walberla
+{
+real_t computeErrorMax(const shared_ptr< StructuredBlockForest >& blocks, BlockDataID& NumericalSol,
+                       const math::AABB& domainAABB, const real_t radius, const real_t epsilon, const real_t charge,
+                       const BlockDataID& potentialErrorID)
+{
+   real_t error   = real_c(0);
+   real_t normmax = real_c(0);
+
+   for (auto block = blocks->begin(); block != blocks->end(); ++block)
+   {
+      ScalarField_T* solutionField = block->getData< ScalarField_T >(NumericalSol);
+
+      real_t blockResult            = real_t(0);
+      real_t blockResult_analytical = real_t(0);
+            WALBERLA_FOR_ALL_CELLS_XYZ_OMP(solutionField, omp parallel for schedule(static) reduction(max: blockResult, max: blockResult_analytical),
+                                           const auto cellAABB = blocks->getBlockLocalCellAABB(*block, Cell(x,y,z));
+                                                   auto cellCenter = cellAABB.center();
+
+                                                       real_t posX = cellCenter[0];
+                                                       real_t posY = cellCenter[1];
+                                                       real_t posZ = cellCenter[2];
+
+                                                       real_t analyticalSol;
+
+                                                       // analytical solution of problem with neumann/dirichlet boundaries
+
+                                                       real_t distance = real_c(
+                                                               sqrt(pow((domainAABB.center()[0] - posX), 2) +
+                                                                    pow((domainAABB.center()[1] - posY), 2) +
+                                                                    pow((domainAABB.center()[2] - posZ), 2)));
+                                                       if (distance >= radius) {
+         analyticalSol = (1 / (4 * math::pi * epsilon)) * (charge / distance);
+                                                       } else {
+         analyticalSol = (1 / (4 * math::pi * epsilon)) * (charge / (2 * radius)) * (3 - pow((distance / radius), 2));
+                                                       }
+
+                                                       real_t currErr = real_c(
+                                                               fabs(solutionField->get(x, y, z) - analyticalSol) /
+                                                               analyticalSol);
+                                                       blockResult = std::max(blockResult, currErr);
+                                                       blockResult_analytical = std::max(blockResult_analytical,
+                                                                                         analyticalSol);
+
+
+            )
+            error   = std::max(error, blockResult);
+            normmax = std::max(normmax, blockResult_analytical);
+   }
+
+   mpi::allReduceInplace(error, mpi::MAX);
+   mpi::allReduceInplace(normmax, mpi::MAX);
+
+   return error;
+}
+
+real_t computeErrorL2(const shared_ptr< StructuredBlockForest >& blocks, BlockDataID& NumericalSol,
+                      const math::AABB& domainAABB, const real_t radius, const real_t epsilon, const real_t charge,
+                      const BlockDataID& potentialErrorID)
+{
+   real_t error  = real_c(0);
+   real_t normL2 = real_c(0);
+   real_t cells  = real_t(0);
+
+   for (auto block = blocks->begin(); block != blocks->end(); ++block)
+   {
+            ScalarField_T* solutionField       = block->getData< ScalarField_T >(NumericalSol);
+            ScalarField_T* potentialErrorField = block->getData< ScalarField_T >(potentialErrorID);
+
+            real_t blockResult            = real_t(0);
+            real_t blockResult_analytical = real_t(0);
+            real_t block_local_cells      = real_t(0);
+            WALBERLA_FOR_ALL_CELLS_XYZ_OMP(solutionField, omp parallel for schedule(static) reduction(+: blockResult, +: blockResult_analytical, +: block_local_cells),
+                                           const auto cellAABB = blocks->getBlockLocalCellAABB(*block, Cell(x,y,z));
+                                                   auto cellCenter = cellAABB.center();
+
+                                                       real_t posX = cellCenter[0];
+                                                       real_t posY = cellCenter[1];
+                                                       real_t posZ = cellCenter[2];
+
+                                                       real_t analyticalSol;
+
+                                                       // analytical solution of problem with neumann/dirichlet boundaries
+
+                                                       real_t distance = real_c(
+                                                               sqrt(pow((domainAABB.center()[0] - posX), 2) +
+                                                                    pow((domainAABB.center()[1] - posY), 2) +
+                                                                    pow((domainAABB.center()[2] - posZ), 2)));
+                                                       if (distance >= radius) {
+         analyticalSol = (1 / (4 * math::pi * epsilon)) * (charge / distance);
+                                                       } else {
+         analyticalSol = (1 / (4 * math::pi * epsilon)) * (charge / (2 * radius)) * (3 - pow((distance / radius), 2));
+                                                       }
+
+                                                       //potentialAnalyticalField->get(x, y, z) = analyticalSol;
+                                                       real_t currErr = (solutionField->get(x, y, z) - analyticalSol);
+                                                       potentialErrorField ->get(x, y, z) = abs(currErr);
+                                                       blockResult += currErr * currErr;
+                                                       blockResult_analytical += analyticalSol * analyticalSol;
+                                                       block_local_cells += 1;
+
+
+            )
+            cells += block_local_cells;
+            error += blockResult;
+            normL2 += blockResult_analytical;
+   }
+   mpi::allReduceInplace(error, mpi::SUM);
+   mpi::allReduceInplace(normL2, mpi::SUM);
+   mpi::allReduceInplace(cells, mpi::SUM);
+
+   WALBERLA_LOG_INFO_ON_ROOT("number of cell is:"
+                             << " " << cells);
+   return (std::sqrt(error / (cells))); //(std::sqrt(error/(cells)))/(std::sqrt(normL2/(cells)));
+}
+} // namespace walberla
+
+#endif // WALBERLA_ERRORNORMS_H