diff --git a/sen2chain/cloud_mask.py b/sen2chain/cloud_mask.py
index 6653ef837a6c60d510d0860022678e99c2a7a75b..131c05b0c8a2bef1a01712bc68224a26d771e5af 100755
--- a/sen2chain/cloud_mask.py
+++ b/sen2chain/cloud_mask.py
@@ -15,6 +15,7 @@ from shapely.ops import transform
 import rasterio
 from rasterio.features import shapes, rasterize
 import numpy as np
+from itertools import compress
 from scipy import ndimage
 from typing import Sequence, List, Dict, Union
 from osgeo import gdal
@@ -441,5 +442,63 @@ def create_cloud_mask_v003(cloud_mask: Union[str, pathlib.PosixPath],
     os.remove(out_temp)
     logger.info("Done: {}".format(out_path.name))
 
+def create_cloud_mask_v004(scl_path: Union[str, pathlib.PosixPath],
+                           out_path="./cm004.jp2",
+                           iterations: int = 5,
+                           cld_shad: bool = True,
+                           cld_med_prob: bool = True,
+                           cld_hi_prob: bool = True,
+                           thin_cir: bool = True,
+                           ) -> None:
+    """
+    create cloud mask version cm004. This cloudmask uses 20m resolution SCL image from Sen2Cor 
+    The number of dilatation cycles can be manually modified by the user. Default value: 5 cycles. 
+    :param scl_path: path to the Sen2Cor 20m scene classification raster.
+    :param out_path: path to the output file.
+    :param iterations: number of dilatation cylces to apply.
+    :param cld_shad: usage of the CLOUD_SHADOWS (3)
+    :param cld_med_prob: usage of the CLOUD_MEDIUM_PROBABILITY (8)
+    :param cld_hi_prob: usage of the CLOUD_HIGH_PROBABILITY (9)
+    :param thin_cir: usage of the THIN_CIRRUS (10)
+    """
+    
+    out_temp_path = Path(Config().get("temp_path"))
+    out_temp = str(out_temp_path / (out_path.stem + "_tmp_cm004.tif"))
     
+    with rasterio.open(str(scl_path)) as scl_src:
+        scl_profile = scl_src.profile
+        scl = scl_src.read(1).astype(np.int8)
+    
+    list_values = list(compress([3, 8, 9, 10], [cld_shad, cld_med_prob, cld_hi_prob, thin_cir]))
+    cld = np.isin(scl, list_values)
+    
+    if iterations > 0:
+        kernel = np.array([[0, 1, 1, 1, 0, 0],
+                           [1, 1, 1, 1, 1, 1],
+                           [1, 1, 1, 1, 1, 1],
+                           [1, 1, 1, 1, 1, 1],
+                           [0, 1, 1, 1, 1, 0]])
+        cld_dilated = ndimage.binary_dilation(cld, kernel, iterations = iterations)
+    else:
+        cld_dilated = cld
+    
+    scl_profile.update(driver="Gtiff",
+                       compress="DEFLATE",
+                       tiled=False,
+                       dtype=np.int8)
+                       
+    with rasterio.Env(GDAL_CACHEMAX=512) as env:
+        with rasterio.open(str(out_temp), "w", **scl_profile) as dst:
+            dst.write(cld_dilated.astype(np.int8), 1)
+    
+    # Save to JP2000 
+    src_ds = gdal.Open(out_temp)
+    driver = gdal.GetDriverByName("JP2OpenJPEG")
+    dst_ds = driver.CreateCopy(str(out_path), src_ds,
+                               options=["CODEC=JP2", "QUALITY=100", "REVERSIBLE=YES", "YCBCR420=NO"])
+    dst_ds = None
+    src_ds = None
+
+    os.remove(out_temp)
+    logger.info("Done: {}".format(out_path.name))    
 
diff --git a/sen2chain/products.py b/sen2chain/products.py
index 2c8051eafb36fb8825108c1880b116220b1428c7..0a985829aa88a02c5c490b7edafa73e315adddee 100755
--- a/sen2chain/products.py
+++ b/sen2chain/products.py
@@ -17,7 +17,7 @@ from .utils import grouper, setPermissions, get_current_Sen2Cor_version
 from .config import Config, SHARED_DATA
 from .xmlparser import MetadataParser, Sen2ChainMetadataParser
 from .sen2cor import process_sen2cor
-from .cloud_mask import create_cloud_mask, create_cloud_mask_v2, create_cloud_mask_b11, create_cloud_mask_v003
+from .cloud_mask import create_cloud_mask, create_cloud_mask_v2, create_cloud_mask_b11, create_cloud_mask_v003, create_cloud_mask_v004
 from .indices import IndicesCollection
 from .colormap import create_l2a_ql, create_l1c_ql
 
@@ -516,6 +516,10 @@ class L2aProduct(Product):
                            cm_version: str = "cm001",
                            probability: int = 1,
                            iterations: int = 5,
+                           cld_shad: bool = True,
+                           cld_med_prob: bool = True,
+                           cld_hi_prob: bool = True,
+                           thin_cir: bool = True,
                            reprocess: bool = False,
                            #~ out_path_mask = None,
                            #~ out_path_mask_b11 = None
@@ -531,7 +535,12 @@ class L2aProduct(Product):
                                         sen2chain_processing_version = self.sen2chain_processing_version,
                                         cm_version = cm_version, 
                                         probability = probability, 
-                                        iterations = iterations)
+                                        iterations = iterations,
+                                        cld_shad = cld_shad, 
+                                        cld_med_prob = cld_med_prob,
+                                        cld_hi_prob = cld_hi_prob, 
+                                        thin_cir = thin_cir,
+                                        )
         
         if cloudmask.path.exists() and not reprocess:
                 logger.info("{} cloud mask already computed".format(cloudmask.identifier))
@@ -573,7 +582,17 @@ class L2aProduct(Product):
                 
                 
             elif cm_version == "cm004":
-                toto=12
+                if cloudmask.path.exists():     # in version 3.8 will be updated using missing_ok = True
+                    cloudmask.path.unlink()
+                    cloudmask._info_path.unlink()
+                create_cloud_mask_v004(scl_path = self.scl_20m,
+                                       out_path = cloudmask.path,
+                                       iterations = iterations,
+                                       cld_shad = cld_shad, 
+                                       cld_med_prob = cld_med_prob,
+                                       cld_hi_prob = cld_hi_prob, 
+                                       thin_cir = thin_cir,
+                                       )
             else:
                 logger.info("Wrong cloudmask version {}".format(cm_version))
 
@@ -1068,15 +1087,29 @@ class NewCloudMaskProduct:
                  cm_version: str = "cm001",
                  probability: int = 1,
                  iterations: int = 5,
+                 cld_shad: bool = True,
+                 cld_med_prob: bool = True,
+                 cld_hi_prob: bool = True,
+                 thin_cir: bool = True,
                  ) -> None:
         if not (identifier or l2a_identifier):
             raise ValueError("Product or L2a identifier cannot be empty")
         else:
             self.tile = self.get_tile(identifier or l2a_identifier)
             self.l2a = (l2a_identifier or self.get_l2a(identifier)).replace(".SAFE", "")
-            self.suffix = [i for i in ["CM001", "CM002-B11", "CM003-PRB" + str(probability) + "-ITER" + str(iterations)] if cm_version.upper() in i][0]
+            self.suffix = [i for i in ["CM001", 
+                                       "CM002-B11", 
+                                       "CM003-PRB" + str(probability) + "-ITER" + str(iterations),
+                                       "CM004-CSH" + str(int(cld_shad)) + \
+                                            "-CMP" + str(int(cld_med_prob)) + \
+                                            "-CHP" + str(int(cld_hi_prob)) + \
+                                            "-TCI" + str(int(thin_cir)) + \
+                                            "-ITER" + str(iterations),
+                                       ] if cm_version.upper() in i][0]
             self.identifier = identifier or self.l2a + "_" + self.suffix + ".jp2"
-            self.cm_version, self.probability, self.iterations = self.get_cm_version(self.identifier)
+            #~ self.cm_version, self.probability, self.iterations = self.get_cm_version(self.identifier)
+            self.mask_info = self.get_cm_version(self.identifier)
+            
             self.path = self._library_path / self.tile / self.l2a / self.identifier
             self._info_path = self.path.parent / (self.path.stem + ".xml")
             self.init_md()
@@ -1116,12 +1149,40 @@ class NewCloudMaskProduct:
         :param string: string from which to extract the version name.
         """
         try:
-            return re.findall(r"S2.+_(CM[0-9]{3})-PRB(.*)-ITER(.*)\.", identifier)[0]
+            pat = re.compile(r"S2.+_(?P<cm_version>CM00[1-2])")
+            return pat.match(identifier).groupdict()
         except:
-            try:
-                return [re.findall(r"S2.+_(CM[0-9]{3}).+", identifier)[0], None, None]
-            except:
-                return [None, None, None]
+            pass
+        try:
+            pat = re.compile(r"S2.+_(?P<cm_version>CM003)" + \
+                             "-PRB(?P<probability>.*)" + \
+                             "-ITER(?P<iterations>.*)" + \
+                             ".jp2")
+            return pat.match(identifier).groupdict()
+        except:
+            pass
+        try:
+            pat = re.compile(r"S2.+_(?P<cm_version>CM004)" + \
+                             "-CSH(?P<cld_shad>.*)" + \
+                             "-CMP(?P<cld_med_prob>.*)" + \
+                             "-CHP(?P<cld_hi_prob>.*)" + \
+                             "-TCI(?P<thin_cir>.*)" + \
+                             "-ITER(?P<iterations>.*)" + \
+                             ".jp2")
+            return pat.match(identifier).groupdict()
+        except:
+            pass
+
+        #~ try:
+            #~ return re.findall(r"S2.+_(CM004)-CSH(.*)-CMP(.*)-CHP(.*)-TCI(.*)-ITER(.*)\.", identifier)[0]
+        #~ except:
+            #~ try:
+                #~ return [re.findall(r"S2.+_(CM003)-PRB(.*)-ITER(.*)\.", identifier)[0], None, None]
+            #~ except:
+                #~ try:
+                    #~ return [re.findall(r"S2.+_(CM00[1-2]).+", identifier)[0], None, None]
+                #~ except:
+                    #~ return [None, None, None]
     
     @property
     def sen2chain_version(self):
@@ -1172,6 +1233,10 @@ class IndiceProduct:
                  cm_version: str = "cm001",
                  probability: int = 1,
                  iterations: int = 5,
+                 cld_shad: bool = True,
+                 cld_med_prob: bool = True,
+                 cld_hi_prob: bool = True,
+                 thin_cir: bool = True,
                  ) -> None:
         if not (identifier or (l2a_identifier and indice)):
             raise ValueError("Product or (L2a identifier and indice) cannot be empty")
@@ -1181,17 +1246,28 @@ class IndiceProduct:
             self.indice = (indice or identifier.replace(".", "_").split("_")[7]).upper()
             self.masked = masked
             if self.masked:
-                self.suffix = [i for i in ["CM001", "CM002-B11", "CM003-PRB" + str(probability) + "-ITER" + str(iterations)] if cm_version.upper() in i][0]
+                #~ self.suffix = [i for i in ["CM001", "CM002-B11", "CM003-PRB" + str(probability) + "-ITER" + str(iterations)] if cm_version.upper() in i][0]
+                self.suffix = [i for i in ["CM001", 
+                                           "CM002-B11", 
+                                           "CM003-PRB" + str(probability) + "-ITER" + str(iterations),
+                                           "CM004-CSH" + str(int(cld_shad)) + \
+                                                "-CMP" + str(int(cld_med_prob)) + \
+                                                "-CHP" + str(int(cld_hi_prob)) + \
+                                                "-TCI" + str(int(thin_cir)) + \
+                                                "-ITER" + str(iterations),
+                                           ] if cm_version.upper() in i][0]
                 self.identifier = identifier or self.l2a + "_" + self.indice + "_" + self.suffix + ".jp2"
-                self.cm_version, self.probability, self.iterations = NewCloudMaskProduct.get_cm_version(self.identifier)
+                #~ self.cm_version, self.probability, self.iterations = NewCloudMaskProduct.get_cm_version(self.identifier)
+                self.mask_info = NewCloudMaskProduct.get_cm_version(self.identifier)
             else:
                 self.suffix = None
                 self.identifier = identifier or self.l2a + "_" + self.indice + ".jp2"
-                self.cm_version, self.probability, self.iterations = 3* [None]
+                #~ self.cm_version, self.probability, self.iterations = 3* [None]
+                self.mask_info = None
             self.path = self._indices_path / self.indice / self.tile / self.l2a / self.identifier
-            self.cm_version = self.cm_version or cm_version
-            self.probability = self.probability or probability
-            self.iterations = self.iterations or iterations
+            #~ self.cm_version = self.cm_version or cm_version
+            #~ self.probability = self.probability or probability
+            #~ self.iterations = self.iterations or iterations
             self._info_path = self.path.parent / (self.path.stem + ".xml")
             self.init_md()