diff --git a/experiment/fit_diagnosis/split_curve.py b/experiment/fit_diagnosis/split_curve.py
deleted file mode 100644
index 8dfebf30931573b25bd6db470fc6d28ddc7ece8d..0000000000000000000000000000000000000000
--- a/experiment/fit_diagnosis/split_curve.py
+++ /dev/null
@@ -1,120 +0,0 @@
-import numpy as np
-import matplotlib.cm as cm
-
-import matplotlib.pyplot as plt
-import seaborn as sns
-
-from typing import Union, List
-
-from extreme_estimator.estimator.full_estimator import AbstractFullEstimator
-from extreme_estimator.estimator.margin_estimator import AbstractMarginEstimator
-from extreme_estimator.extreme_models.margin_model.margin_function.combined_margin_function import \
-    CombinedMarginFunction
-from extreme_estimator.extreme_models.margin_model.margin_function.utils import error_dict_between_margin_functions
-from extreme_estimator.gev_params import GevParams
-from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
-from spatio_temporal_dataset.slicer.split import Split, ALL_SPLITS_EXCEPT_ALL
-
-
-class SplitCurve(object):
-
-    def __init__(self, nb_fit: int = 1):
-        self.nb_fit = nb_fit
-        self.margin_function_fitted_all = None
-
-    def fit(self, show=True):
-        self.margin_function_fitted_all = []
-
-        for i in range(self.nb_fit):
-            # A new dataset with the same margin, but just the observations are resampled
-            self.dataset = self.load_dataset()
-            # Both split must be defined
-            assert not self.dataset.slicer.some_required_ind_are_not_defined
-            self.margin_function_sample = self.dataset.margin_model.margin_function_sample
-
-            print('Fitting {}/{}...'.format(i + 1, self.nb_fit))
-            self.estimator = self.load_estimator(self.dataset)
-            # Fit the estimator and get the margin_function
-            self.estimator.fit()
-            self.margin_function_fitted_all.append(self.estimator.margin_function_fitted)
-
-        # Individual error dict
-        self.error_dict_all = [error_dict_between_margin_functions(self.margin_function_sample, m)
-                               for m in self.margin_function_fitted_all]
-
-        # Mean margin
-        self.mean_margin_function_fitted = CombinedMarginFunction.from_margin_functions(self.margin_function_fitted_all)
-        self.mean_error_dict = error_dict_between_margin_functions(self.margin_function_sample,
-                                                                   self.mean_margin_function_fitted)
-
-        if show:
-            self.visualize()
-
-    def load_dataset(self):
-        pass
-
-    def load_estimator(self, dataset):
-        pass
-
-    @property
-    def main_title(self):
-        return self.dataset.slicer.summary(show=False)
-
-    def visualize(self):
-        fig, axes = plt.subplots(len(GevParams.GEV_VALUE_NAMES), 2)
-        fig.subplots_adjust(hspace=0.4, wspace=0.4, )
-        for i, gev_value_name in enumerate(GevParams.GEV_VALUE_NAMES):
-            self.margin_graph(axes[i, 0], gev_value_name)
-            self.score_graph(axes[i, 1], gev_value_name)
-        fig.suptitle(self.main_title)
-        plt.show()
-
-    def margin_graph(self, ax, gev_value_name):
-        # Create bins of data, each with an associated color corresponding to its error
-
-        data = self.mean_error_dict[gev_value_name].values
-        data_min, data_max = data.min(), data.max()
-        nb_bins = 10
-        limits = np.linspace(data_min, data_max, num=nb_bins + 1)
-        limits[-1] += 0.01
-        # Binary color should
-        colors = cm.binary((limits - data_min/ (data_max - data_min)))
-
-        # Display train/test points
-        for split, marker in [(self.dataset.train_split, 'o'), (self.dataset.test_split, 'x')]:
-            for left_limit, right_limit, color in zip(limits[:-1], limits[1:], colors):
-                # Find for the split the index
-                data_ind = self.mean_error_dict[gev_value_name].loc[
-                    self.dataset.coordinates.coordinates_index(split)].values
-                data_filter = np.logical_and(left_limit <= data_ind, data_ind < right_limit)
-
-                self.margin_function_sample.set_datapoint_display_parameters(split, datapoint_marker=marker,
-                                                                             filter=data_filter, color=color)
-                self.margin_function_sample.visualize_single_param(gev_value_name, ax, show=False)
-
-        # Display the individual fitted curve
-        self.mean_margin_function_fitted.color = 'lightskyblue'
-        for m in self.margin_function_fitted_all:
-            m.visualize_single_param(gev_value_name, ax, show=False)
-        # Display the mean fitted curve
-        self.mean_margin_function_fitted.color = 'blue'
-        self.mean_margin_function_fitted.visualize_single_param(gev_value_name, ax, show=False)
-
-    def score_graph(self, ax, gev_value_name):
-        # todo: for the moment only the train/test are interresting (the spatio temporal isn"t working yet)
-
-        sns.set_style('whitegrid')
-        s = self.mean_error_dict[gev_value_name]
-        for split in self.dataset.splits:
-            ind = self.dataset.coordinates_index(split)
-            data = s.loc[ind].values
-            sns.kdeplot(data, bw=0.5, ax=ax, label=split.name).set(xlim=0)
-        ax.legend()
-        # X axis
-        ax.set_xlabel('Absolute error in percentage')
-        plt.setp(ax.get_xticklabels(), visible=True)
-        ax.xaxis.set_tick_params(labelbottom=True)
-        # Y axis
-        ax.set_ylabel(gev_value_name)
-        plt.setp(ax.get_yticklabels(), visible=True)
-        ax.yaxis.set_tick_params(labelbottom=True)
diff --git a/experiment/fit_diagnosis/split_curve_alps.py b/experiment/fit_diagnosis/split_curve_alps.py
deleted file mode 100644
index 13fbd82839d9de213a71d4be5008c4d24b372610..0000000000000000000000000000000000000000
--- a/experiment/fit_diagnosis/split_curve_alps.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from experiment.fit_diagnosis.split_curve import SplitCurve
-from extreme_estimator.estimator.full_estimator import FullEstimatorInASingleStepWithSmoothMargin
-from extreme_estimator.estimator.margin_estimator import SmoothMarginEstimator
-from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel, \
-    LinearAllParametersAllDimsMarginModel
-from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
-from extreme_estimator.gev_params import GevParams
-from spatio_temporal_dataset.coordinates.spatial_coordinates.alps_station_2D_coordinates import \
-    AlpsStation2DCoordinates, AlpsStation2DCoordinatesBetweenZeroAndOne
-from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import LinSpaceSpatialCoordinates
-from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
-
-
-class SplitCurveAlps(SplitCurve):
-
-    def __init__(self, nb_fit: int = 1):
-        super().__init__(nb_fit)
-        self.nb_obs = 2
-        # nb_points = len(AlpsStation2DCoordinates.from_csv())
-        nb_points = 10
-        self.coordinates = AlpsStation2DCoordinatesBetweenZeroAndOne.from_nb_points(nb_points, train_split_ratio=0.8)
-        # MarginModel Linear with respect to the shape (from 0.01 to 0.02)
-        params_sample = {
-            (GevParams.GEV_LOC, 0): 10,
-            (GevParams.GEV_SHAPE, 0): 1.0,
-            (GevParams.GEV_SCALE, 0): 10,
-        }
-        self.margin_model = ConstantMarginModel(coordinates=self.coordinates, params_sample=params_sample)
-        self.max_stable_model = Smith()
-
-    def load_dataset(self):
-        return FullSimulatedDataset.from_double_sampling(nb_obs=self.nb_obs, margin_model=self.margin_model,
-                                                         coordinates=self.coordinates,
-                                                         max_stable_model=self.max_stable_model)
-
-    def load_estimator(self, dataset):
-        max_stable_model = Smith()
-        margin_model_for_estimator = LinearAllParametersAllDimsMarginModel(dataset.coordinates)
-        # estimator = FullEstimatorInASingleStepWithSmoothMargin(dataset, margin_model_for_estimator, max_stable_model)
-        estimator = SmoothMarginEstimator(dataset, margin_model_for_estimator)
-        return estimator
-
-
-if __name__ == '__main__':
-    curve = SplitCurveAlps(nb_fit=2)
-    curve.fit()
diff --git a/experiment/fit_diagnosis/split_curve_example.py b/experiment/fit_diagnosis/split_curve_example.py
deleted file mode 100644
index 59732de5c62eca2987e12b234b9eb3ab1e740907..0000000000000000000000000000000000000000
--- a/experiment/fit_diagnosis/split_curve_example.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from experiment.fit_diagnosis.split_curve import SplitCurve
-from extreme_estimator.estimator.full_estimator import FullEstimatorInASingleStepWithSmoothMargin
-from extreme_estimator.estimator.margin_estimator import SmoothMarginEstimator
-from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel, \
-    LinearAllParametersAllDimsMarginModel
-from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
-from extreme_estimator.gev_params import GevParams
-from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import LinSpaceSpatialCoordinates
-from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
-
-
-class SplitCurveExample(SplitCurve):
-
-    def __init__(self, nb_fit: int = 1):
-        super().__init__(nb_fit)
-        self.nb_points = 50
-        self.nb_obs = 60
-        self.coordinates = LinSpaceSpatialCoordinates.from_nb_points(nb_points=self.nb_points, train_split_ratio=0.8)
-        # MarginModel Linear with respect to the shape (from 0.01 to 0.02)
-        params_sample = {
-            (GevParams.GEV_LOC, 0): 10,
-            (GevParams.GEV_SHAPE, 0): 1.0,
-            (GevParams.GEV_SCALE, 0): 1.0,
-        }
-        self.margin_model = ConstantMarginModel(coordinates=self.coordinates, params_sample=params_sample)
-        self.max_stable_model = Smith()
-
-    def load_dataset(self):
-        return FullSimulatedDataset.from_double_sampling(nb_obs=self.nb_obs, margin_model=self.margin_model,
-                                                         coordinates=self.coordinates,
-                                                         max_stable_model=self.max_stable_model)
-
-    def load_estimator(self, dataset):
-        max_stable_model = Smith()
-        margin_model_for_estimator = LinearAllParametersAllDimsMarginModel(dataset.coordinates)
-        # estimator = FullEstimatorInASingleStepWithSmoothMargin(dataset, margin_model_for_estimator, max_stable_model)
-        estimator = SmoothMarginEstimator(dataset, margin_model_for_estimator)
-        return estimator
-
-
-if __name__ == '__main__':
-    curve = SplitCurveExample(nb_fit=2)
-    curve.fit()
diff --git a/experiment/regression_margin/regression_margin.py b/experiment/regression_margin/regression_margin.py
index 2a878abe7fc5fb1cb54846497c96eb041bd4d6bc..86fb73f22b0ba1ba33dfad41231e509fbe5a2a86 100644
--- a/experiment/regression_margin/regression_margin.py
+++ b/experiment/regression_margin/regression_margin.py
@@ -1,6 +1,6 @@
 import numpy as np
 
-from extreme_estimator.estimator.full_estimator import FullEstimatorInASingleStepWithSmoothMargin
+from extreme_estimator.estimator.full_estimator.abstract_full_estimator import FullEstimatorInASingleStepWithSmoothMargin
 from extreme_estimator.extreme_models.margin_model.margin_function.linear_margin_function import LinearMarginFunction
 from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearAllParametersAllDimsMarginModel, \
     ConstantMarginModel
diff --git a/experiment/robustness_plot/estimation_robustness/max_stable_process_plot.py b/experiment/robustness_plot/estimation_robustness/max_stable_process_plot.py
index 479a67e069c3a0736b83077dc7cac9e1103a17fa..b98a7b44b733c9c3bd66c6ae25218063ed7e458f 100644
--- a/experiment/robustness_plot/estimation_robustness/max_stable_process_plot.py
+++ b/experiment/robustness_plot/estimation_robustness/max_stable_process_plot.py
@@ -1,4 +1,4 @@
-from extreme_estimator.estimator.max_stable_estimator import MaxStableEstimator
+from extreme_estimator.estimator.max_stable_estimator.abstract_max_stable_estimator import MaxStableEstimator
 from extreme_estimator.extreme_models.max_stable_model.abstract_max_stable_model import AbstractMaxStableModel
 from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
 from experiment.robustness_plot.display_item import DisplayItem
diff --git a/experiment/simulation/abstract_simulation.py b/experiment/simulation/abstract_simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..92d16edcd2649d8631a0a1e25463474558903307
--- /dev/null
+++ b/experiment/simulation/abstract_simulation.py
@@ -0,0 +1,219 @@
+import os
+import os.path as op
+import pickle
+
+import matplotlib.cm as cm
+import matplotlib.pyplot as plt
+import numpy as np
+import seaborn as sns
+
+from extreme_estimator.estimator.abstract_estimator import AbstractEstimator
+from extreme_estimator.extreme_models.margin_model.margin_function.combined_margin_function import \
+    CombinedMarginFunction
+from extreme_estimator.extreme_models.margin_model.margin_function.utils import error_dict_between_margin_functions
+from extreme_estimator.gev_params import GevParams
+from spatio_temporal_dataset.dataset.abstract_dataset import get_subset_dataset
+from spatio_temporal_dataset.dataset.simulation_dataset import SimulatedDataset
+from utils import get_full_path, get_display_name_from_object_type
+
+SIMULATION_RELATIVE_PATH = op.join('local', 'simulation')
+
+
+class AbstractSimulation(object):
+
+    def __init__(self):
+        self.nb_fit = 1
+        self.margin_function_fitted_list = None
+        self.full_dataset = None
+        self.error_dict_all = None
+        self.margin_function_sample = None
+        self.mean_error_dict = None
+        self.mean_margin_function_fitted = None
+
+    def fit(self, estimator_class, show=True):
+        assert estimator_class not in self.already_fitted_estimator_names, \
+            'This estimator class has already been fitted.' \
+            'Create a child class, if you wish to change some default parameters'
+
+        # Load full dataset
+        full_dataset = self.load_full_dataset()
+        assert len(full_dataset.subset_id_to_column_idxs) == self.nb_fit
+        assert not full_dataset.slicer.some_required_ind_are_not_defined
+
+        # Fit a margin function on each subset
+        margin_function_fitted_list = []
+        for subset_id in range(self.nb_fit):
+            print('Fitting {}/{} of {}...'.format(subset_id + 1, self.nb_fit,
+                                                  get_display_name_from_object_type(estimator_class)))
+            dataset = get_subset_dataset(full_dataset, subset_id=subset_id)  # type: SimulatedDataset
+            estimator = estimator_class.from_dataset(dataset)  # type: AbstractEstimator
+            # Fit the estimator and get the margin_function
+            estimator.fit()
+            margin_function_fitted_list.append(estimator.margin_function_fitted)
+
+        # Individual error dict
+        self.dump_fitted_margins_pickle(estimator_class, margin_function_fitted_list)
+
+        if show:
+            self.visualize_comparison_graph(estimator_names=[estimator_class])
+
+    def dump_fitted_margins_pickle(self, estimator_class, margin_function_fitted_list):
+        with open(self.fitted_margins_pickle_path(estimator_class), 'wb') as fp:
+            pickle.dump(margin_function_fitted_list, fp)
+
+    def load_fitted_margins_pickles(self, estimator_class):
+        with open(self.fitted_margins_pickle_path(estimator_class), 'rb') as fp:
+            return pickle.load(fp)
+
+    def visualize_comparison_graph(self, estimator_names=None):
+        # Visualize the result of several estimators on the same graph
+        if estimator_names is None:
+            estimator_names = self.already_fitted_estimator_names
+        assert len(estimator_names) > 0
+        # Load dataset
+        self.full_dataset = self.load_full_dataset()
+        self.margin_function_sample = self.full_dataset.margin_model.margin_function_sample
+
+        fig, axes = self.load_fig_and_axes()
+        for estimator_name in estimator_names:
+            self.margin_function_fitted_list = self.load_fitted_margins_pickles(estimator_name)
+
+            self.error_dict_all = [error_dict_between_margin_functions(reference=self.margin_function_sample,
+                                                                       fitted=margin_function_fitted)
+                                   for margin_function_fitted in self.margin_function_fitted_list]
+
+            # Mean margin
+            self.mean_margin_function_fitted = CombinedMarginFunction.from_margin_functions(
+                self.margin_function_fitted_list)
+
+            self.mean_error_dict = error_dict_between_margin_functions(self.margin_function_sample,
+                                                                       self.mean_margin_function_fitted)
+            self.visualize(fig, axes, show=False)
+        plt.show()
+
+    @property
+    def already_fitted_estimator_names(self):
+        return [d for d in os.listdir(self.directory_path) if op.isdir(op.join(self.directory_path, d))]
+
+    @property
+    def main_title(self):
+        return self.full_dataset.slicer.summary(show=False)
+
+    @staticmethod
+    def load_fig_and_axes():
+        fig, axes = plt.subplots(len(GevParams.GEV_VALUE_NAMES), 2)
+        fig.subplots_adjust(hspace=0.4, wspace=0.4)
+        return fig, axes
+
+    def visualize(self, fig=None, axes=None, show=True):
+        if fig is None or axes is None:
+            fig, axes = self.load_fig_and_axes()
+        for i, gev_value_name in enumerate(GevParams.GEV_VALUE_NAMES):
+            self.margin_graph(axes[i, 0], gev_value_name)
+            self.score_graph(axes[i, 1], gev_value_name)
+        if show:
+            fig.suptitle(self.main_title)
+            plt.show()
+
+    def margin_graph(self, ax, gev_value_name):
+        # Create bins of data, each with an associated color corresponding to its error
+
+        data = self.mean_error_dict[gev_value_name].values
+        data_min, data_max = data.min(), data.max()
+        nb_bins = 10
+        limits = np.linspace(data_min, data_max, num=nb_bins + 1)
+        limits[-1] += 0.01
+        # Binary color should
+        colors = cm.binary((limits - data_min / (data_max - data_min)))
+
+        # Display train/test points
+        for split, marker in [(self.full_dataset.train_split, 'o'), (self.full_dataset.test_split, 'x')]:
+            for left_limit, right_limit, color in zip(limits[:-1], limits[1:], colors):
+                # Find for the split the index
+                data_ind = self.mean_error_dict[gev_value_name].loc[
+                    self.full_dataset.coordinates.coordinates_index(split)].values
+                data_filter = np.logical_and(left_limit <= data_ind, data_ind < right_limit)
+
+                self.margin_function_sample.set_datapoint_display_parameters(split, datapoint_marker=marker,
+                                                                             filter=data_filter, color=color)
+                self.margin_function_sample.visualize_single_param(gev_value_name, ax, show=False)
+
+        # Display the individual fitted curve
+        self.mean_margin_function_fitted.color = 'lightskyblue'
+        for m in self.margin_function_fitted_list:
+            m.visualize_single_param(gev_value_name, ax, show=False)
+        # Display the mean fitted curve
+        self.mean_margin_function_fitted.color = 'blue'
+        self.mean_margin_function_fitted.visualize_single_param(gev_value_name, ax, show=False)
+
+    def score_graph(self, ax, gev_value_name):
+        # todo: for the moment only the train/test are interresting (the spatio temporal isn"t working yet)
+
+        sns.set_style('whitegrid')
+        s = self.mean_error_dict[gev_value_name]
+        for split in self.full_dataset.splits:
+            ind = self.full_dataset.coordinates_index(split)
+            data = s.loc[ind].values
+            sns.kdeplot(data, bw=0.5, ax=ax, label=split.name).set(xlim=0)
+        ax.legend()
+        # X axis
+        ax.set_xlabel('Absolute error in percentage')
+        plt.setp(ax.get_xticklabels(), visible=True)
+        ax.xaxis.set_tick_params(labelbottom=True)
+        # Y axis
+        ax.set_ylabel(gev_value_name)
+        plt.setp(ax.get_yticklabels(), visible=True)
+        ax.yaxis.set_tick_params(labelbottom=True)
+
+    # Input/Output
+
+    @property
+    def name(self):
+        return str(type(self)).split('.')[-1].split('Simulation')[0]
+
+    @property
+    def directory_path(self):
+        return op.join(get_full_path(relative_path=SIMULATION_RELATIVE_PATH), self.name, str(self.nb_fit))
+
+    @property
+    def dataset_path(self):
+        return op.join(self.directory_path, 'dataset')
+
+    @property
+    def dataset_csv_path(self):
+        return self.dataset_path + '.csv'
+
+    @property
+    def dataset_pickle_path(self):
+        return self.dataset_path + '.pkl'
+
+    def fitted_margins_pickle_path(self, estimator_class):
+        d = op.join(self.directory_path, get_display_name_from_object_type(estimator_class))
+        if not op.exists(d):
+            os.makedirs(d, exist_ok=True)
+        return op.join(d, 'fitted_margins.pkl')
+
+    def dump(self):
+        pass
+
+    def _dump(self, dataset: SimulatedDataset):
+        dataset.create_subsets(nb_subsets=self.nb_fit)
+        dataset.to_csv(self.dataset_csv_path)
+        # Pickle Dataset
+        if op.exists(self.dataset_pickle_path):
+            print('A dataset already exists, we will keep it intact, delete it manually if you want to change it')
+        else:
+            with open(self.dataset_pickle_path, 'wb') as fp:
+                pickle.dump(dataset, fp)
+
+    def load_full_dataset(self) -> SimulatedDataset:
+        # Class to handle pickle loading (and in case of module refactoring, I could change the module name here)
+        class RenamingUnpickler(pickle.Unpickler):
+            def find_class(self, module, name):
+                if module == 'mymodule':
+                    module = 'mymodule2'
+                return super().find_class(module, name)
+
+        with open(self.dataset_pickle_path, 'rb') as fp:
+            dataset = RenamingUnpickler(fp).load()
+        return dataset
diff --git a/experiment/simulation/lin_space_simulation.py b/experiment/simulation/lin_space_simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..910eb3a3c3492713513951be1240018f1f471887
--- /dev/null
+++ b/experiment/simulation/lin_space_simulation.py
@@ -0,0 +1,42 @@
+from experiment.simulation.abstract_simulation import AbstractSimulation
+from extreme_estimator.estimator.full_estimator.full_estimator_for_simulation import FULL_ESTIMATORS_FOR_SIMULATION
+from extreme_estimator.estimator.margin_estimator.margin_estimator_for_simulation import \
+    MARGIN_ESTIMATORS_FOR_SIMULATION
+from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel
+from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
+from extreme_estimator.gev_params import GevParams
+from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import LinSpaceSpatialCoordinates
+from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
+
+
+class LinSpaceSimulation(AbstractSimulation):
+    FITTED_ESTIMATORS = []
+
+    def __init__(self):
+        super().__init__()
+        self.nb_fit = 2
+        # Simulation parameters
+        self.nb_obs = 60
+        self.coordinates = LinSpaceSpatialCoordinates.from_nb_points(nb_points=21, train_split_ratio=0.75)
+        # MarginModel Linear with respect to the shape (from 0.01 to 0.02)
+        params_sample = {
+            (GevParams.GEV_LOC, 0): 10,
+            (GevParams.GEV_SHAPE, 0): 1.0,
+            (GevParams.GEV_SCALE, 0): 1.0,
+        }
+        self.margin_model = ConstantMarginModel(coordinates=self.coordinates, params_sample=params_sample)
+        self.max_stable_model = Smith()
+
+    def dump(self):
+        dataset = FullSimulatedDataset.from_double_sampling(nb_obs=self.nb_obs, margin_model=self.margin_model,
+                                                            coordinates=self.coordinates,
+                                                            max_stable_model=self.max_stable_model)
+        self._dump(dataset=dataset)
+
+
+if __name__ == '__main__':
+    simu = LinSpaceSimulation()
+    simu.dump()
+    # for estimator_class in MARGIN_ESTIMATORS_FOR_SIMULATION + FULL_ESTIMATORS_FOR_SIMULATION:
+    #     simu.fit(estimator_class, show=False)
+    simu.visualize_comparison_graph()
diff --git a/extreme_estimator/estimator/__init__.py b/extreme_estimator/estimator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/extreme_estimator/estimator/abstract_estimator.py b/extreme_estimator/estimator/abstract_estimator.py
index 246359cb3bcca220e420925a21bfc225ee053e52..76d6622b14c022d472296c64733ff4b191d1cb1f 100644
--- a/extreme_estimator/estimator/abstract_estimator.py
+++ b/extreme_estimator/estimator/abstract_estimator.py
@@ -4,7 +4,6 @@ from extreme_estimator.extreme_models.margin_model.margin_function.abstract_marg
     AbstractMarginFunction
 from extreme_estimator.extreme_models.margin_model.margin_function.linear_margin_function import LinearMarginFunction
 from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset
-from spatio_temporal_dataset.slicer.split import Split
 
 
 class AbstractEstimator(object):
@@ -22,6 +21,11 @@ class AbstractEstimator(object):
         self._margin_function_fitted = None
         self._max_stable_model_fitted = None
 
+    @classmethod
+    def from_dataset(cls, dataset: AbstractDataset):
+        # raise NotImplementedError('from_dataset class constructor has not been implemented for this class')
+        pass
+
     def fit(self):
         ts = time.time()
         self._fit()
@@ -33,6 +37,11 @@ class AbstractEstimator(object):
         assert self.is_fitted
         return self._params_fitted
 
+    # @property
+    # def max_stable_fitted(self) -> AbstractMarginFunction:
+    #     assert self._margin_function_fitted is not None, 'Error: estimator has not been fitted'
+    #     return self._margin_function_fitted
+
     @property
     def margin_function_fitted(self) -> AbstractMarginFunction:
         assert self.is_fitted
diff --git a/extreme_estimator/estimator/full_estimator/__init__.py b/extreme_estimator/estimator/full_estimator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/extreme_estimator/estimator/full_estimator.py b/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py
similarity index 92%
rename from extreme_estimator/estimator/full_estimator.py
rename to extreme_estimator/estimator/full_estimator/abstract_full_estimator.py
index 2ec2b86db93a90ffb428147bfe3a6c1c1a891e61..70259c5237572b5aab842ad488891882516aff13 100644
--- a/extreme_estimator/estimator/full_estimator.py
+++ b/extreme_estimator/estimator/full_estimator/abstract_full_estimator.py
@@ -1,9 +1,7 @@
 from extreme_estimator.estimator.abstract_estimator import AbstractEstimator
-from extreme_estimator.estimator.margin_estimator import SmoothMarginEstimator
-from extreme_estimator.estimator.max_stable_estimator import MaxStableEstimator
+from extreme_estimator.estimator.margin_estimator.abstract_margin_estimator import SmoothMarginEstimator
+from extreme_estimator.estimator.max_stable_estimator.abstract_max_stable_estimator import MaxStableEstimator
 from extreme_estimator.extreme_models.margin_model.abstract_margin_model import AbstractMarginModel
-from extreme_estimator.extreme_models.margin_model.margin_function.abstract_margin_function import \
-    AbstractMarginFunction
 from extreme_estimator.extreme_models.margin_model.margin_function.linear_margin_function import LinearMarginFunction
 from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearMarginModel
 from extreme_estimator.extreme_models.max_stable_model.abstract_max_stable_model import AbstractMaxStableModel
diff --git a/extreme_estimator/estimator/full_estimator/full_estimator_for_simulation.py b/extreme_estimator/estimator/full_estimator/full_estimator_for_simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..c758a31cb9263b83c4f91e6c0701af8133a118f6
--- /dev/null
+++ b/extreme_estimator/estimator/full_estimator/full_estimator_for_simulation.py
@@ -0,0 +1,19 @@
+from extreme_estimator.estimator.full_estimator.abstract_full_estimator import \
+    FullEstimatorInASingleStepWithSmoothMargin
+from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearAllParametersAllDimsMarginModel
+from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
+from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset
+
+
+class FullEstimatorInASingleStepWithSmoothMargin_LinearAllParametersAllDims_Smith(
+    FullEstimatorInASingleStepWithSmoothMargin):
+
+    @classmethod
+    def from_dataset(cls, dataset: AbstractDataset):
+        return cls(dataset, margin_model=LinearAllParametersAllDimsMarginModel(dataset.coordinates),
+                   max_stable_model=Smith())
+
+
+FULL_ESTIMATORS_FOR_SIMULATION = [
+    FullEstimatorInASingleStepWithSmoothMargin_LinearAllParametersAllDims_Smith
+]
diff --git a/extreme_estimator/estimator/margin_estimator/__init__.py b/extreme_estimator/estimator/margin_estimator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/extreme_estimator/estimator/margin_estimator.py b/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py
similarity index 81%
rename from extreme_estimator/estimator/margin_estimator.py
rename to extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py
index a68539d769512324bed5bec8c66a46b7346a146e..64082a398d0062e587a7898e91055089e8d63489 100644
--- a/extreme_estimator/estimator/margin_estimator.py
+++ b/extreme_estimator/estimator/margin_estimator/abstract_margin_estimator.py
@@ -1,7 +1,8 @@
 from extreme_estimator.estimator.abstract_estimator import AbstractEstimator
 from extreme_estimator.extreme_models.margin_model.margin_function.abstract_margin_function import \
     AbstractMarginFunction
-from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearMarginModel
+from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearMarginModel, \
+    LinearAllParametersAllDimsMarginModel
 from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset
 
 
@@ -22,17 +23,6 @@ class PointWiseMarginEstimator(AbstractMarginEstimator):
     pass
 
 
-class ConstantMarginEstimator(AbstractMarginEstimator):
-
-    def __init__(self, dataset: AbstractDataset, margin_model: LinearMarginModel):
-        super().__init__(dataset)
-        assert isinstance(margin_model, LinearMarginModel)
-        self.margin_model = margin_model
-
-    def _fit(self):
-        self._margin_function_fitted = self.margin_model.margin_function_start_fit
-
-
 class SmoothMarginEstimator(AbstractMarginEstimator):
     """# with different type of marginals: cosntant, linear...."""
 
diff --git a/extreme_estimator/estimator/margin_estimator/margin_estimator_for_simulation.py b/extreme_estimator/estimator/margin_estimator/margin_estimator_for_simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..34a645511ffe22e021e74d7affa3182c325f3456
--- /dev/null
+++ b/extreme_estimator/estimator/margin_estimator/margin_estimator_for_simulation.py
@@ -0,0 +1,15 @@
+from extreme_estimator.estimator.margin_estimator.abstract_margin_estimator import SmoothMarginEstimator
+from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearAllParametersAllDimsMarginModel
+from spatio_temporal_dataset.dataset.abstract_dataset import AbstractDataset
+
+
+class SmoothMarginEstimator_LinearAllParametersAllDims(SmoothMarginEstimator):
+
+    @classmethod
+    def from_dataset(cls, dataset: AbstractDataset):
+        return cls(dataset, LinearAllParametersAllDimsMarginModel(dataset.coordinates))
+
+
+MARGIN_ESTIMATORS_FOR_SIMULATION = [
+    SmoothMarginEstimator_LinearAllParametersAllDims
+]
diff --git a/extreme_estimator/estimator/max_stable_estimator/__init__.py b/extreme_estimator/estimator/max_stable_estimator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/extreme_estimator/estimator/max_stable_estimator.py b/extreme_estimator/estimator/max_stable_estimator/abstract_max_stable_estimator.py
similarity index 100%
rename from extreme_estimator/estimator/max_stable_estimator.py
rename to extreme_estimator/estimator/max_stable_estimator/abstract_max_stable_estimator.py
diff --git a/extreme_estimator/extreme_models/margin_model/margin_function/combined_margin_function.py b/extreme_estimator/extreme_models/margin_model/margin_function/combined_margin_function.py
index 7d149cb78fea9822f2c0826a8a75f06409dc180d..17a8cfcddbc15193cc5ff272785900c5c198c7b4 100644
--- a/extreme_estimator/extreme_models/margin_model/margin_function/combined_margin_function.py
+++ b/extreme_estimator/extreme_models/margin_model/margin_function/combined_margin_function.py
@@ -1,4 +1,5 @@
 from typing import List
+from itertools import combinations
 
 import numpy as np
 
@@ -24,7 +25,8 @@ class CombinedMarginFunction(AbstractMarginFunction):
     def from_margin_functions(cls, margin_functions: List[AbstractMarginFunction]):
         assert len(margin_functions) > 0
         assert all([isinstance(margin_function, AbstractMarginFunction) for margin_function in margin_functions])
-        common_coordinates = set([margin_function.coordinates for margin_function in margin_functions])
-        assert len(common_coordinates) == 1
-        coordinates = common_coordinates.pop()
+        all_coordinates = [margin_function.coordinates for margin_function in margin_functions]
+        for coordinates1, coordinates2 in combinations(all_coordinates, 2):
+            assert coordinates1 == coordinates2
+        coordinates = all_coordinates[0]
         return cls(coordinates, margin_functions)
diff --git a/extreme_estimator/extreme_models/margin_model/margin_function/utils.py b/extreme_estimator/extreme_models/margin_model/margin_function/utils.py
index b367ce6ab688bbf0f30d64957c0285b6fd4630ae..d4a990704d1a2ea199bec1b4d9c4c7ee50b309f8 100644
--- a/extreme_estimator/extreme_models/margin_model/margin_function/utils.py
+++ b/extreme_estimator/extreme_models/margin_model/margin_function/utils.py
@@ -17,7 +17,8 @@ def error_dict_between_margin_functions(reference: AbstractMarginFunction, fitte
     :param fitted:
     :return:
     """
-    assert reference.coordinates == fitted.coordinates
+    assert reference.coordinates == fitted.coordinates, \
+        'Coordinates have either been resampled or the split is not the same'
     reference_values = reference.gev_value_name_to_serie
     fitted_values = fitted.gev_value_name_to_serie
     gev_param_name_to_error_serie = {}
diff --git a/spatio_temporal_dataset/coordinates/abstract_coordinates.py b/spatio_temporal_dataset/coordinates/abstract_coordinates.py
index 7035c2f1217b943ca69f6f417888e6f9b466c1b3..14956f0280de94cd807a2335562975b325fb3ad4 100644
--- a/spatio_temporal_dataset/coordinates/abstract_coordinates.py
+++ b/spatio_temporal_dataset/coordinates/abstract_coordinates.py
@@ -40,11 +40,31 @@ class AbstractCoordinates(object):
 
     @classmethod
     def from_df(cls, df: pd.DataFrame):
-        pass
+        # Extract df_coordinate
+        coordinate_columns = [c for c in df.columns if c in cls.COORDINATES_NAMES]
+        df_coord = df.loc[:, coordinate_columns].copy()
+        # Extract the split
+        split_columns = [c for c in df.columns if c in [cls.SPATIAL_SPLIT, cls.TEMPORAL_SPLIT]]
+        s_split_spatial = df[cls.SPATIAL_SPLIT].copy() if cls.SPATIAL_SPLIT in df.columns else None
+        s_split_temporal = df[cls.TEMPORAL_SPLIT].copy() if cls.TEMPORAL_SPLIT in df.columns else None
+        # Infer the slicer class
+        if s_split_temporal is None and s_split_spatial is None:
+            raise ValueError('Both split are unspecified')
+        elif s_split_temporal is not None and s_split_spatial is None:
+            slicer_class = TemporalSlicer
+        elif s_split_temporal is None and s_split_spatial is not None:
+            slicer_class = SpatialSlicer
+        else:
+            slicer_class = SpatioTemporalSlicer
+        # Remove all the columns used from df
+        columns_used = coordinate_columns + split_columns
+        df.drop(columns_used, axis=1, inplace=True)
+        return cls(df_coord=df_coord, slicer_class=slicer_class,
+                   s_split_spatial=s_split_spatial, s_split_temporal=s_split_temporal)
 
     @classmethod
     def from_df_and_slicer(cls, df: pd.DataFrame, slicer_class: type, train_split_ratio: float = None):
-        # train_split_ratio is shared between the spatial part of the data, and the temporal part
+        # So far, the train_split_ratio is the same between the spatial part of the data, and the temporal part
 
         # All the index should be unique
         assert len(set(df.index)) == len(df)
@@ -81,9 +101,8 @@ class AbstractCoordinates(object):
 
     @property
     def df_merged(self) -> pd.DataFrame:
-        # Merged DataFrame of df_coord and s_split
-        return self.df_all_coordinates if self.s_split_spatial is None else self.df_all_coordinates.join(
-            self.s_split_spatial)
+        # Merged DataFrame of df_coord with s_split
+        return self.df_all_coordinates.join(self.df_split)
 
     # Split
 
@@ -104,7 +123,16 @@ class AbstractCoordinates(object):
     def ind_train_temporal(self) -> pd.Series:
         return ind_train_from_s_split(s_split=self.s_split_temporal)
 
-    # Columns
+    @property
+    def df_split(self):
+        split_name_to_s_split = {
+            self.SPATIAL_SPLIT: self.s_split_spatial,
+            self.TEMPORAL_SPLIT: self.s_split_temporal,
+        }
+        # Delete None s_split from the dictionary
+        split_name_to_s_split = {k: v for k, v in split_name_to_s_split.items() if v is not None}
+        # Create df_split from dict
+        return pd.DataFrame.from_dict(split_name_to_s_split)
 
     @property
     def coordinates_names(self) -> List[str]:
@@ -186,3 +214,7 @@ class AbstractCoordinates(object):
 
     def __rmul__(self, other):
         return self * other
+
+    def __eq__(self, other):
+        return self.df_merged.equals(other.df_merged)
+
diff --git a/spatio_temporal_dataset/dataset/abstract_dataset.py b/spatio_temporal_dataset/dataset/abstract_dataset.py
index be1f4b9711852f11b54dac50304b5e752227d775..8d1f27f39a1df20e0840ec16b046e728f573f668 100644
--- a/spatio_temporal_dataset/dataset/abstract_dataset.py
+++ b/spatio_temporal_dataset/dataset/abstract_dataset.py
@@ -1,6 +1,7 @@
+import copy
 import os
 import os.path as op
-from typing import List
+from typing import List, Dict
 
 import numpy as np
 import pandas as pd
@@ -17,11 +18,7 @@ class AbstractDataset(object):
         assert pd.Index.equals(observations.index, coordinates.index)
         self.observations = observations
         self.coordinates = coordinates
-
-    # @property
-    # def max_stable_fitted(self) -> AbstractMarginFunction:
-    #     assert self._margin_function_fitted is not None, 'Error: estimator has not been fitted'
-    #     return self._margin_function_fitted
+        self.subset_id_to_column_idxs = None  # type: Dict[int, List[int]]
 
     @property
     def slicer(self):
@@ -30,9 +27,9 @@ class AbstractDataset(object):
     @classmethod
     def from_csv(cls, csv_path: str):
         assert op.exists(csv_path)
-        df = pd.read_csv(csv_path)
-        temporal_maxima = AbstractSpatioTemporalObservations.from_df(df)
+        df = pd.read_csv(csv_path, index_col=0)
         coordinates = AbstractCoordinates.from_df(df)
+        temporal_maxima = AbstractSpatioTemporalObservations.from_df(df)
         return cls(temporal_maxima, coordinates)
 
     def to_csv(self, csv_path: str):
@@ -44,8 +41,7 @@ class AbstractDataset(object):
     @property
     def df_dataset(self) -> pd.DataFrame:
         # Merge dataframes with the maxima and with the coordinates
-        # todo: maybe I should add the split from the temporal observations
-        return self.observations.df_maxima_gev.join(self.coordinates.df_merged)
+        return self.observations.df_maxima_merged.join(self.coordinates.df_merged)
 
     # Observation wrapper
 
@@ -66,7 +62,7 @@ class AbstractDataset(object):
     def coordinates_values(self, split: Split = Split.all) -> np.ndarray:
         return self.coordinates.coordinates_values(split=split)
 
-    def coordinates_index(self, split: Split= Split.all) -> pd.Index:
+    def coordinates_index(self, split: Split = Split.all) -> pd.Index:
         return self.coordinates.coordinates_index(split=split)
 
     # Slicer wrapper
@@ -82,3 +78,25 @@ class AbstractDataset(object):
     @property
     def splits(self) -> List[Split]:
         return self.slicer.splits
+
+    # Dataset subsets
+
+    def create_subsets(self, nb_subsets):
+        self.subset_id_to_column_idxs = {}
+        for subset_id in range(nb_subsets):
+            column_idxs = [idx for idx in range(self.observations.nb_obs) if idx % nb_subsets == subset_id]
+            self.subset_id_to_column_idxs[subset_id] = column_idxs
+
+
+def get_subset_dataset(dataset: AbstractDataset, subset_id) -> AbstractDataset:
+    columns_idxs = dataset.subset_id_to_column_idxs[subset_id]
+    assert dataset.subset_id_to_column_idxs is not None, 'You need to create subsets'
+    assert subset_id in dataset.subset_id_to_column_idxs.keys()
+    subset_dataset = copy.deepcopy(dataset)
+    observations = subset_dataset.observations
+    if observations.df_maxima_gev is not None:
+        observations.df_maxima_gev = observations.df_maxima_gev.iloc[:, columns_idxs]
+    if observations.df_maxima_frech is not None:
+        observations.df_maxima_frech = observations.df_maxima_frech.iloc[:, columns_idxs]
+    return subset_dataset
+
diff --git a/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py b/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py
index f1c24cc6f91a569ed5ac7f6d88fa4cbabdc354d7..9e1e27f7a89859c441fc3c2350b085e307ccb083 100644
--- a/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py
+++ b/spatio_temporal_dataset/spatio_temporal_observations/abstract_spatio_temporal_observations.py
@@ -5,7 +5,11 @@ import numpy as np
 from spatio_temporal_dataset.slicer.abstract_slicer import df_sliced, AbstractSlicer
 from spatio_temporal_dataset.slicer.split import Split
 
+
 class AbstractSpatioTemporalObservations(object):
+    # Observation columns
+    OBSERVATIONS_GEV = 'obs_gev'
+    OBSERVATIONS_FRECH = 'obs_frech'
 
     def __init__(self, df_maxima_frech: pd.DataFrame = None, df_maxima_gev: pd.DataFrame = None):
         """
@@ -13,19 +17,17 @@ class AbstractSpatioTemporalObservations(object):
         Index are stations index
         Columns are the temporal moment of the maxima
         """
-        assert df_maxima_frech is not None or df_maxima_gev is not None
-        self.df_maxima_frech = df_maxima_frech
+        assert df_maxima_gev is not None or df_maxima_frech is not None
+        if df_maxima_gev is not None and df_maxima_frech is not None:
+            assert pd.Index.equals(df_maxima_gev.index, df_maxima_frech.index)
         self.df_maxima_gev = df_maxima_gev
+        self.df_maxima_frech = df_maxima_frech
 
     @classmethod
     def from_csv(cls, csv_path: str = None):
         assert csv_path is not None
         assert op.exists(csv_path)
-        df = pd.read_csv(csv_path)
-        # # Index correspond to the first column
-        # index_column_name = df.columns[0]
-        # assert index_column_name not in cls.coordinates_columns(df)
-        # df.set_index(index_column_name, inplace=True)
+        df = pd.read_csv(csv_path, index_col=0)
         return cls.from_df(df)
 
     @property
@@ -35,6 +37,16 @@ class AbstractSpatioTemporalObservations(object):
         else:
             return self.df_maxima_gev
 
+    @property
+    def df_maxima_merged(self):
+        df_maxima_list = []
+        for df, suffix in [(self.df_maxima_gev, self.OBSERVATIONS_GEV), (self.df_maxima_frech, self.OBSERVATIONS_FRECH)]:
+            if df is not None:
+                df_maxima = df.copy()
+                df_maxima.columns = [str(c) + ' ' + suffix for c in df_maxima.columns]
+                df_maxima_list.append(df_maxima)
+        return pd.concat(df_maxima_list, axis=1)
+
     @property
     def index(self) -> pd.Index:
         return self._df_maxima.index
@@ -45,7 +57,19 @@ class AbstractSpatioTemporalObservations(object):
 
     @classmethod
     def from_df(cls, df):
-        pass
+        df_maxima_list = []
+        for suffix in [cls.OBSERVATIONS_GEV, cls.OBSERVATIONS_FRECH]:
+            columns_with_suffix = [c for c in df.columns if str(c).endswith(suffix)]
+            if columns_with_suffix:
+                df_maxima = df[columns_with_suffix] if columns_with_suffix else None
+                df_maxima.columns = [c.replace(' ' + suffix, '') for c in df_maxima.columns]
+            else:
+                df_maxima = None
+            df_maxima_list.append(df_maxima)
+        df_maxima_gev, df_maxima_frech = df_maxima_list
+        if df_maxima_gev is not None and df_maxima_frech is not None:
+            assert pd.Index.equals(df_maxima_gev.columns, df_maxima_frech.columns)
+        return cls(df_maxima_gev=df_maxima_gev, df_maxima_frech=df_maxima_frech)
 
     def maxima_gev(self, split: Split = Split.all, slicer: AbstractSlicer = None) -> np.ndarray:
         return df_sliced(self.df_maxima_gev, split, slicer).values
diff --git a/test/test_experiment/test_simulation.py b/test/test_experiment/test_simulation.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb21c521e1a042996f6cf847a4cb231b630ff1da
--- /dev/null
+++ b/test/test_experiment/test_simulation.py
@@ -0,0 +1,14 @@
+# import unittest
+#
+# from experiment.simulation.lin_space_simulation import LinSpaceSimulation
+#
+#
+# class TestSimulation(unittest.TestCase):
+#     DISPLAY = False
+#
+#     def test_lin_space(self):
+#         s = LinSpaceSimulation()
+#         s.fit(show=self.DISPLAY)
+#
+# if __name__ == '__main__':
+#     unittest.main()
diff --git a/test/test_experiment/test_split_curve.py b/test/test_experiment/test_split_curve.py
index a521e573b95abdb3b6cd63cda6676b82e6790b3c..e112d4a094c26acdba650a920c45da2abc39a0b5 100644
--- a/test/test_experiment/test_split_curve.py
+++ b/test/test_experiment/test_split_curve.py
@@ -1,48 +1,43 @@
-import unittest
-
-from extreme_estimator.estimator.margin_estimator import ConstantMarginEstimator
-
-from experiment.fit_diagnosis.split_curve import SplitCurve
-from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel, \
-    LinearAllParametersAllDimsMarginModel
-from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
-from extreme_estimator.gev_params import GevParams
-from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import LinSpaceSpatialCoordinates
-from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
-
-
-class TestSplitCurve(unittest.TestCase):
-    DISPLAY = False
-
-    class SplitCurveFastForTest(SplitCurve):
-
-        def __init__(self, nb_fit: int = 1):
-            super().__init__(nb_fit)
-            self.nb_points = 50
-            self.nb_obs = 60
-            self.coordinates = LinSpaceSpatialCoordinates.from_nb_points(nb_points=self.nb_points, train_split_ratio=0.8)
-            # MarginModel Linear with respect to the shape (from 0.01 to 0.02)
-            params_sample = {
-                (GevParams.GEV_LOC, 0): 10,
-                (GevParams.GEV_SHAPE, 0): 1.0,
-                (GevParams.GEV_SCALE, 0): 1.0,
-            }
-            self.margin_model = ConstantMarginModel(coordinates=self.coordinates, params_sample=params_sample)
-            self.max_stable_model = Smith()
-
-        def load_dataset(self):
-            return FullSimulatedDataset.from_double_sampling(nb_obs=self.nb_obs, margin_model=self.margin_model,
-                                                             coordinates=self.coordinates,
-                                                             max_stable_model=self.max_stable_model)
-
-        def load_estimator(self, dataset):
-            # todo: create a test from that example
-            return ConstantMarginEstimator(dataset, LinearAllParametersAllDimsMarginModel(dataset.coordinates))
-
-    def test_split_curve(self):
-        s = self.SplitCurveFastForTest(nb_fit=2)
-        s.fit(show=self.DISPLAY)
-
-
-if __name__ == '__main__':
-    unittest.main()
+# import unittest
+#
+#
+# from experiment.simulation.abstract_simulation import AbstractSimulation
+# from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel, \
+#     LinearAllParametersAllDimsMarginModel
+# from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Smith
+# from extreme_estimator.gev_params import GevParams
+# from spatio_temporal_dataset.coordinates.spatial_coordinates.coordinates_1D import LinSpaceSpatialCoordinates
+# from spatio_temporal_dataset.dataset.simulation_dataset import FullSimulatedDataset
+#
+#
+# class TestSplitCurve(unittest.TestCase):
+#     DISPLAY = False
+#
+#     class SplitCurveFastForTest(AbstractSimulation):
+#
+#         def __init__(self, nb_fit: int = 1):
+#             super().__init__(nb_fit)
+#             self.nb_points = 50
+#             self.nb_obs = 60
+#             self.coordinates = LinSpaceSpatialCoordinates.from_nb_points(nb_points=self.nb_points, train_split_ratio=0.8)
+#             # MarginModel Linear with respect to the shape (from 0.01 to 0.02)
+#             params_sample = {
+#                 (GevParams.GEV_LOC, 0): 10,
+#                 (GevParams.GEV_SHAPE, 0): 1.0,
+#                 (GevParams.GEV_SCALE, 0): 1.0,
+#             }
+#             self.margin_model = ConstantMarginModel(coordinates=self.coordinates, params_sample=params_sample)
+#             self.max_stable_model = Smith()
+#
+#         def load_dataset(self):
+#             return FullSimulatedDataset.from_double_sampling(nb_obs=self.nb_obs, margin_model=self.margin_model,
+#                                                              coordinates=self.coordinates,
+#                                                              max_stable_model=self.max_stable_model)
+#
+#     def test_split_curve(self):
+#         s = self.SplitCurveFastForTest(nb_fit=2)
+#         s.fit(show=self.DISPLAY)
+#
+#
+# if __name__ == '__main__':
+#     unittest.main()
diff --git a/test/test_extreme_estimator/test_estimator/test_margin_estimators.py b/test/test_extreme_estimator/test_estimator/test_margin_estimators.py
index e9f1ef207791ce6fc739d16a1ce83b3a3429ba75..aa19eb3fdb298afba4eaacd29ab1d1c959df7af8 100644
--- a/test/test_extreme_estimator/test_estimator/test_margin_estimators.py
+++ b/test/test_extreme_estimator/test_estimator/test_margin_estimators.py
@@ -1,7 +1,6 @@
-import time
 import unittest
 
-from extreme_estimator.estimator.margin_estimator import SmoothMarginEstimator
+from extreme_estimator.estimator.margin_estimator.abstract_margin_estimator import SmoothMarginEstimator
 from spatio_temporal_dataset.dataset.simulation_dataset import MarginDataset
 from test.test_utils import load_smooth_margin_models, load_test_1D_and_2D_spatial_coordinates
 
diff --git a/test/test_spatio_temporal_dataset/test_dataset.py b/test/test_spatio_temporal_dataset/test_dataset.py
index 5c150da0e084893ffe7667ec43ad88f7a0339936..cefdced8fdaebfe5d25b9de16d7173ec35264bec 100644
--- a/test/test_spatio_temporal_dataset/test_dataset.py
+++ b/test/test_spatio_temporal_dataset/test_dataset.py
@@ -3,21 +3,23 @@ import unittest
 from itertools import product
 
 from spatio_temporal_dataset.dataset.simulation_dataset import MaxStableDataset
-from test.test_utils import load_test_max_stable_models, load_test_spatial_coordinates, load_test_3D_spatial_coordinates, \
+from test.test_utils import load_test_max_stable_models, load_test_spatial_coordinates, \
+    load_test_3D_spatial_coordinates, \
     load_test_1D_and_2D_spatial_coordinates
 
 
 class TestDataset(unittest.TestCase):
-    nb_obs = 10
-    nb_points = 10
+    nb_obs = 2
+    nb_points = 2
 
     def test_max_stable_dataset_R1_and_R2(self):
         max_stable_models = load_test_max_stable_models()[:]
-        coordinatess = load_test_1D_and_2D_spatial_coordinates(self.nb_points)
-        for coordinates, max_stable_model in product(coordinatess, max_stable_models):
-            MaxStableDataset.from_sampling(nb_obs=self.nb_obs,
-                                           max_stable_model=max_stable_model,
-                                           coordinates=coordinates)
+        coordinates = load_test_1D_and_2D_spatial_coordinates(self.nb_points)
+        for coordinates, max_stable_model in product(coordinates, max_stable_models):
+            dataset = MaxStableDataset.from_sampling(nb_obs=self.nb_obs,
+                                                     max_stable_model=max_stable_model,
+                                                     coordinates=coordinates)
+            assert len(dataset.df_dataset.columns) == self.nb_obs + dataset.coordinates.nb_coordinates
         self.assertTrue(True)
 
     def test_max_stable_dataset_crash_R3(self):
diff --git a/test/test_unitary/test_fitmaxstab/test_fitmaxstab_with_margin.py b/test/test_unitary/test_fitmaxstab/test_fitmaxstab_with_margin.py
index a0921cf48e0da112adfa3aed05925408aa7ec668..4246cb2785aed58bb110fcc817e26836c4db8a81 100644
--- a/test/test_unitary/test_fitmaxstab/test_fitmaxstab_with_margin.py
+++ b/test/test_unitary/test_fitmaxstab/test_fitmaxstab_with_margin.py
@@ -1,6 +1,6 @@
 import unittest
 
-from extreme_estimator.estimator.full_estimator import FullEstimatorInASingleStepWithSmoothMargin
+from extreme_estimator.estimator.full_estimator.abstract_full_estimator import FullEstimatorInASingleStepWithSmoothMargin
 from extreme_estimator.extreme_models.margin_model.smooth_margin_model import ConstantMarginModel, \
     LinearMarginModelExample
 from extreme_estimator.extreme_models.max_stable_model.abstract_max_stable_model import CovarianceFunction
diff --git a/test/test_unitary/test_fitmaxstab/test_fitmaxstab_without_margin.py b/test/test_unitary/test_fitmaxstab/test_fitmaxstab_without_margin.py
index baa4b03c1e1c79a3db2f6067810e37c1116f1f17..bfd48eb41acc6878508ee78156598dbda16eed86 100644
--- a/test/test_unitary/test_fitmaxstab/test_fitmaxstab_without_margin.py
+++ b/test/test_unitary/test_fitmaxstab/test_fitmaxstab_without_margin.py
@@ -1,6 +1,6 @@
 import unittest
 
-from extreme_estimator.estimator.max_stable_estimator import MaxStableEstimator
+from extreme_estimator.estimator.max_stable_estimator.abstract_max_stable_estimator import MaxStableEstimator
 from extreme_estimator.extreme_models.max_stable_model.abstract_max_stable_model import CovarianceFunction
 from extreme_estimator.extreme_models.max_stable_model.max_stable_models import Schlather
 from extreme_estimator.extreme_models.utils import r
diff --git a/test/test_utils.py b/test/test_utils.py
index b9badf698f90457131e0760cea155b24c303ca39..eeed52af32a3c2d7b03961d481e4031809439d65 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -1,6 +1,6 @@
-from extreme_estimator.estimator.full_estimator import SmoothMarginalsThenUnitaryMsp, \
+from extreme_estimator.estimator.full_estimator.abstract_full_estimator import SmoothMarginalsThenUnitaryMsp, \
     FullEstimatorInASingleStepWithSmoothMargin
-from extreme_estimator.estimator.max_stable_estimator import MaxStableEstimator
+from extreme_estimator.estimator.max_stable_estimator.abstract_max_stable_estimator import MaxStableEstimator
 from extreme_estimator.extreme_models.margin_model.smooth_margin_model import LinearAllParametersAllDimsMarginModel, \
     ConstantMarginModel
 from extreme_estimator.extreme_models.max_stable_model.abstract_max_stable_model import \
diff --git a/utils.py b/utils.py
index 36d17edc823f17181d4efd61f81288c9118f5115..3b0a9ccc060413531336f4ed95f0fda1b4fb273e 100644
--- a/utils.py
+++ b/utils.py
@@ -8,3 +8,7 @@ def get_root_path() -> str:
 def get_full_path(relative_path: str) -> str:
     return op.join(get_root_path(), relative_path)
 
+
+def get_display_name_from_object_type(object_type):
+    # assert isinstance(object_type, type), object_type
+    return str(object_type).split('.')[-1].split("'")[0]