diff --git a/main.cpp b/main.cpp
index c66983d48ee620d879e46f7b06fa462798404f10..f5be00a6630acaaac22b66b6a24f8f5ccb46d7f5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,7 @@
 #include <iostream>
+#include <fstream>
 #include <vector>
+#include <string>
 #include <cstring>
 #include "sound_column.h"
 #include <execution>
@@ -11,30 +13,41 @@
 #define DEFAULT_MAX_FREQ    12'500.0f
 #define WATER_SPEED         1'500.f
 
-std::complex<float> gaussian_init(float, float);
-float media(float, float);
-int run_simulation(float, float, float, float);
+void gaussian_init(sound_column&);
+bool step_r(sound_column&);
+void _step_r_(sound_column&, size_t);
+float media(float, float, float);
+std::vector<sound_column*>* run_simulation(float, float, float, float);
+int save_results(std::string&, std::vector<sound_column*>&);
 
 int main(int argc, char **argv) {
     float r_max = DEFAULT_DISTANCE, z_max = DEFAULT_DEPTH, f_min = DEFAULT_MIN_FREQ, f_max = DEFAULT_MAX_FREQ;
+    bool dry_run = false;
+    std::string save_path = "";
 
     int i=1;
 
     while (i < argc){
-        if (strcmp(argv[i], "--d_max") != 0 || strcmp(argv[i], "-d") != 0)
+        if (strcmp(argv[i], "--r_max") == 0 || strcmp(argv[i], "-r") == 0)
             r_max = atof(argv[++i]);
-        else if (strcmp(argv[i], "--f_max") != 0 || strcmp(argv[i], "-F") != 0)
+        else if (strcmp(argv[i], "--f_max") == 0 || strcmp(argv[i], "-F") == 0)
             f_max = atof(argv[++i]);
-        else if (strcmp(argv[i], "--f_min") != 0 || strcmp(argv[i], "-f") != 0)
+        else if (strcmp(argv[i], "--f_min") == 0 || strcmp(argv[i], "-f") == 0)
             f_min = atof(argv[++i]);
-        else if (strcmp(argv[i], "--z_max") != 0 || strcmp(argv[i], "-z") != 0)
+        else if (strcmp(argv[i], "--z_max") == 0 || strcmp(argv[i], "-z") == 0)
             z_max = atof(argv[++i]);
-        else if (strcmp(argv[i], "--help") != 0 || strcmp(argv[i], "-h") != 0){
+        else if (strcmp(argv[i], "--save_path") == 0 || strcmp(argv[i], "-s") == 0)
+            save_path = argv[++i];
+        else if (strcmp(argv[i], "--dry_run") == 0)
+            dry_run = true;
+        else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0){
             std::cout << "Simulation of wave propagation using the parabolic equation." << std::endl
             << "--r_max, -r : Set the maximum range of the simulation. Default :" << DEFAULT_DISTANCE << std::endl
             << "--f_max, -F : Set the maximum frequency of the simulation. Default :" << DEFAULT_MAX_FREQ << std::endl
-            << "--f_min, -f : Set the minimum frequency of the simulation. Default :" << DEFAULT_MIN_FREQ << std::endl
-            << "--z_max, -z : Set the maximum depth of the simulation. Default :" << DEFAULT_DEPTH << std::endl;
+            << "--f_min, -f : Set the minimum frequency and the frequency step of the simulation. Default :" << DEFAULT_MIN_FREQ << std::endl
+            << "--z_max, -z : Set the maximum depth of the simulation. Default :" << DEFAULT_DEPTH << std::endl
+            << "--save_path, -s : Set the path to the output file. Default will not save anything" << std::endl
+            << "--dry_run : Run the simulation but does not save anything, even if save_path is set" << std::endl;
             return 1;
         }
         else {
@@ -43,40 +56,109 @@ int main(int argc, char **argv) {
 
     i++;
     }
+    std::vector<sound_column*>* results(run_simulation(r_max, z_max, f_min, f_max));
 
-    return run_simulation(r_max, z_max, f_min, f_max);
+    if (not dry_run && save_path.length()){
+        std::cout << "Saving results to " << save_path << std::endl;
+        return save_results(save_path, *results);
+    }
+    else
+        return 0;
+}
+
+
+std::vector<sound_column*>* run_simulation(float r_max, float z_max, float f_min, float f_max){
+    auto nf = size_t(f_max / f_min);
+    float delta_r = r_max/10'000;
+
+    static std::vector<sound_column*> column(nf, nullptr);
+
+    //std::ranges::iota_view indexes((size_t) 0, nf);
+    std::cout << "Initializing " << nf << " pressure columns" << std::endl;
+    std::for_each(std::execution::par, column.begin(), column.end(),      //par_unseq does not compile
+                  [&](sound_column*& c) {int i = &c - &column[0];
+                  c = new sound_column(delta_r, (size_t) 1.10 * z_max*(4*(i+1)*f_min)/WATER_SPEED, 7, r_max, z_max, (i+1)*f_min, WATER_SPEED);
+                      gaussian_init(*c);});
+    std::cout << "Running the simulation" << std::endl;
+    std::for_each(std::execution::par, column.begin(), column.end(),
+                  [&](sound_column*& c) {while (not step_r(*c));std::cout << '.' << std::flush;});
+    std::cout << std::endl << "Done" << std::endl;
+    return &column;
 }
 
 
-std::complex<float> gaussian_init(float depth, float k0){
-    return sqrtf(k0 / 0.6f) * expf(-powf((k0 / 0.6f) * (depth - 1'000.f), 2));
+void gaussian_init(sound_column& column){
+    float k0 = 2*M_1_PIf32 * column.freq / column.c0;
+    std::for_each(std::execution::par_unseq, column.pressures.begin(), column.pressures.end(),
+                  [&, k0](std::complex<float>& p) {int i = &p - &column.pressures[0];
+                      p = sqrtf(k0 / 0.6f) * expf(-powf((k0 / 0.6f) * (column.z_max/column.n_z*i - 1'000.f), 2));});
 }
 
-float media(float r, float depth){
-    static const float slope = -0.009f;
+bool step_r(sound_column& column) {
+    if (column.r >= column.d_max)
+        return true;
+    //std::ranges::iota_view z_ind((size_t) 0, n_z);
+    column.r += column.delta_r;
+    std::for_each(std::execution::par_unseq, column.n_next.begin(), column.n_next.end(),      //par_unseq does not compile
+                  [&](float& n) {int i = &n - &column.n_next[0]; n = media(column.r, column.z_max/column.n_z*i, column.c0);});
+    for(size_t i=0; i < column.n_p;i++){
+        _step_r_(column, i);
+    }
+    // Hank
+    std::for_each(std::execution::par_unseq, column.pressures.begin(), column.pressures.end(),
+                  [&](std::complex<float>& p) {p *=  std::complex<float>(2.f / (M_1_PIf32 * M_1_PIf32 * column.freq / column.c0 * column.r), 0.0f) *
+                                                     std::exp(std::complex<float>(0.0f, 2.f* M_1_PIf32 * column.freq / column.c0 * column.r - M_1_PIf32 / 4));});
+    return false;
+}
+
+void _step_r_(sound_column& column, size_t ip) {
+//    std::ranges::iota_view z_ind((size_t) 0, n_z);
+    //tri diag init
+    std::fill(std::execution::par_unseq, column._u_.begin(), column._u_.end(), column.fbmaj[ip]/column.h2);
+    std::fill(std::execution::par_unseq, column._l_.begin(), column._l_.end(), column.fbmaj[ip]/column.h2);
+
+    float k02 = powf(2*M_1_PIf32 * column.freq / column.c0, 2);
+    std::for_each(std::execution::par_unseq, column._d_.begin(), column._d_.end(),
+                  [&, k02, ip](std::complex<float>& d) {int i = &d - &column._d_[0];
+                  d = std::complex<float>(2 * k02, 0.0f) + column.fbmaj[ip] /
+                          std::complex<float>(-2.f/column.h2 + k02 * (powf(column.n_next[i], 2) - 1.f), 0.0f);});
+
+    //  first matmul
+
+    // Inv tri matmul
+    column._u_[0] /= column._d_[0];
+    column.pressures[0] /= column._d_[0];
+    for(size_t i=1; i < column.n_z-1; i++){
+        column._u_[i] /= column._d_[i] - column._l_[i-1] * column._u_[i-1];
+        column.pressures[i] = (column.pressures[i] - column._l_[i-1] * column.pressures[i-1]) / (column._d_[i] - column._l_[i-1] * column._u_[i-1]);
+    }
+    column.pressures[column.n_z-1] = (column.pressures[column.n_z-1] - column._l_[column.n_z-2] * column.pressures[column.n_z-2]) / (column._d_[column.n_z-1] - column._l_[column.n_z-2] * column._u_[column.n_z-2]);
+    for(ssize_t i=column.n_z-2; i >= 0; i--) {
+        column.pressures[i] -= column._u_[i]*column.pressures[i+1];
+    }
+}
+
+float media(float r, float depth, float speed){
+    const float slope = -0.009f;
     if ( depth > slope * r + 2531.f)
-        return WATER_SPEED / 1650.f;
+        return speed / 1650.f;
     else if ( depth > slope/2 * r + 3042.f)
-        return WATER_SPEED / 1700.f;
+        return speed / 1700.f;
     else if ( depth > slope/3 * r + 4111.f)
-        return WATER_SPEED / 1800.f;
+        return speed / 1800.f;
     else
-        return WATER_SPEED / (1500.f*(1.f+0.00737f*(depth-1.f+expf(-depth))));
+        return speed / (1500.f*(1.f+0.00737f*(depth-1.f+expf(-depth))));
 }
 
-int run_simulation(float r_max, float z_max, float f_min, float f_max){
-    auto nf = size_t(f_max / f_min);
-    float delta_r = r_max/10'000;
-
-    std::vector<sound_column*> column(nf, nullptr);
-
-    //std::ranges::iota_view indexes((size_t) 0, nf);
+int save_results(std::string& path, std::vector<sound_column*>& results){
+    std::fstream file;
+    file.open(path, std::fstream::out | std::fstream::trunc);
+    for(auto c:results){
+        for(auto val:c->pressures){
+            file << val << ',';
+        }
+        file << std::endl;
+    }
 
-    std::for_each(std::execution::par_unseq, column.begin(), column.end(),
-                  [&](sound_column*& c) {int i = &c - &column[0];
-                  c = new sound_column(delta_r, (size_t) 1.10 * z_max*(4*(i+1)*f_min)/WATER_SPEED, 7, r_max, z_max, (i+1)*f_min, WATER_SPEED);
-                      c->init_source(gaussian_init);});
-    std::for_each(std::execution::par_unseq, column.begin(), column.end(),
-                  [&](sound_column*& c) {while (c->step_r(media));});
     return 0;
 }
diff --git a/sound_column.cpp b/sound_column.cpp
index 03724ad53080fb73db9de52c5dedbaabe84f91ec..ded23b1b256f3370adf3383877ccafa85015d880 100644
--- a/sound_column.cpp
+++ b/sound_column.cpp
@@ -21,7 +21,7 @@ sound_column::sound_column(float dr, size_t nz, size_t np, float dm, float zm, f
     n_next.resize(nz);
     fapbj.resize(np);
     fbmaj.resize(np);
-    for(int i=0; i < np; i++) {
+    for(size_t i=0; i < np; i++) {
         faj = std::complex<float>(0, 4* M_1_PIf32 * freq / c0)  / float((2.f * n_p + 1.f) *
                                     powf(sinf(float(i+1) * M_1_PIf32 / (2.f * n_p + 1.f)), 2) * delta_r);
         fbj = 2 * powf(cosf(float(i+1) * M_1_PIf32 / (2.f * n_p + 1.f)),2);
@@ -31,41 +31,28 @@ sound_column::sound_column(float dr, size_t nz, size_t np, float dm, float zm, f
     }
 }
 
+sound_column::sound_column() = default;
+
 sound_column::~sound_column() = default;
 
-bool sound_column::step_r(float (*fun)(float, float)) {
-    if (r >= d_max)
-        return true;
-    //std::ranges::iota_view z_ind((size_t) 0, n_z);
-    r += delta_r;
-    std::for_each(std::execution::par_unseq, n_next.begin(), n_next.end(),
-                   [&](float& n) {int i = &n - &n_next[0]; n = (*fun)(r, z_max/n_z*i);});
-    for(int i=0; i < n_p;i++){
-        _step_r_(i);
-    }
-    // Hank
-    std::for_each(std::execution::par_unseq, pressures.begin(), pressures.end(),
-                  [&](std::complex<float>& p) {p *=  static_cast<std::complex<float>>(2.f / (M_1_PIf32 * M_1_PIf32 * freq / c0 * r)) *
-                  std::exp(std::complex<float>(0, 2.f* M_1_PIf32 * freq / c0 * r - M_1_PIf32 / 4));});
-    return false;
-}
 
-void sound_column::init_source(std::complex<float> (*fun)(float, float)) {
-//    std::ranges::iota_view z_ind((size_t) 0, n_z);
-    std::for_each(std::execution::par_unseq, pressures.begin(), pressures.end(),
-                  [&](std::complex<float>& p) {int i = &p - &pressures[0];
-                  p = (*fun)(z_max/n_z*i, 2*M_1_PIf32 * freq / c0);});
-}
+//void sound_column::init_source(std::complex<float> (*fun)(float, float)) {
+////    std::ranges::iota_view z_ind((size_t) 0, n_z);
+//    std::for_each(std::execution::par_unseq, pressures.begin(), pressures.end(),
+//                  [&](std::complex<float>& p) {int i = &p - &pressures[0];
+//                  p = (*fun)(z_max/n_z*i, 2*M_1_PIf32 * freq / c0);});
+//}
 
-void sound_column::_step_r_(int ip) {
+/*void sound_column::_step_r_(size_t ip) {
 //    std::ranges::iota_view z_ind((size_t) 0, n_z);
     //tri diag init
     std::fill(std::execution::par_unseq, _u_.begin(), _u_.end(), fbmaj[ip]/h2);
     std::fill(std::execution::par_unseq, _l_.begin(), _l_.end(), fbmaj[ip]/h2);
 
+    float double_k0 = 4*M_1_PIf32 * freq / c0;
     std::for_each(std::execution::par_unseq, _d_.begin(), _d_.end(),
-                  [&](std::complex<float>& d) {int i = &d - &_d_[0];d =  static_cast<std::complex<float>>(4* M_1_PIf32 * freq / c0) + fbmaj[ip] /
-                  static_cast<std::complex<float>>(-2.f/h2 + powf(4* M_1_PIf32 * freq / c0, 2) * (powf(n_next[i], 2) - 1.f));});
+                  [&, double_k0, ip](std::complex<float>& d) {int i = &d - &_d_[0];d =  std::complex<float>(double_k0,0.0f) + fbmaj[ip] /
+                  std::complex<float>(-2.f/h2 + powf(double_k0, 2) * (powf(n_next[i], 2) - 1.f), 0.0f);});
 
     //  first matmul
 
@@ -80,4 +67,4 @@ void sound_column::_step_r_(int ip) {
     for(ssize_t i=n_z-2; i >= 0; i--) {
          pressures[i] -= _u_[i]*pressures[i+1];
     }
-}
+}*/
diff --git a/sound_column.h b/sound_column.h
index 23049d87a0b584eb9849c1306543cb1274c6a78a..76243a9ef00b82e3f0486f37e976ab04c26aa647 100644
--- a/sound_column.h
+++ b/sound_column.h
@@ -10,38 +10,36 @@
 #include <execution>
 #include <algorithm>
 
-# define M_1_PIf32	(0.318309886183790671537767526745028724)
+#ifndef M_1_PIf32
+#define M_1_PIf32	(0.318309886183790671537767526745028724)
+#endif
 
 class sound_column {
-private:
-    float delta_r;
-    size_t n_z;
-    size_t n_p;
+public:
+    float delta_r{};
+    size_t n_z{};
+    size_t n_p{};
     float r=0;
-    float d_max;
-    float z_max;
-    float h2;
-    float freq;
-    float c0;
-    std::vector<std::complex<float>> pressures;
-    std::complex<float> faj, fbj;
+    float d_max{};
+    float z_max{};
+    float h2{};
+    std::complex<float> faj{}, fbj{};
     std::vector<std::complex<float>> fapbj; // faj + fbj
     std::vector<std::complex<float>> fbmaj; // fbj - faj
     std::vector<std::complex<float>> _u_;
     std::vector<std::complex<float>> _l_;
     std::vector<std::complex<float>> _d_;
-    std::vector<float> n_next;
-    std::complex<float> (*fun)(float, float) source_fun;
-    void _step_r_(int ip);
-
+    std::vector<float> n_next{};
+//    void _step_r_(size_t ip);
 
-public:
     sound_column(float dr, size_t nz, size_t np, float dm, float zm, float f, float speed);
+    sound_column();
     ~sound_column();
-    bool step_r(float (*fun)(float, float));
-    void init_source(std::complex<float> (*fun)(float, float));
-    void init_source();
+//    void init_source(std::complex<float> (*fun)(float, float));
 
+    float freq{};
+    float c0{};
+    std::vector<std::complex<float>> pressures;
 };