def step_3(topo_nc, list_with_synoptic_nc, dictionary_4, nc_out, create_davit_netcdf=True, log=False):
    ''' Procedure creates unstructured grid NetCDF file under `nc_out` fname.

    Args:
    -----
        topo_nc (str):
            path to netcdf file with x,y vectors and "bathymetry" variable for mask
        list_with_synoptic_nc (list(str)):
            paths to netcdf with synoptic data. At first position should be the main data-file
        dictionary_1 (str):
            path to txt file with dictionary to suggest standart mossco-baw variable name correlation
        dictionary_2 (str):
            path to txt file after scanning variables
        dictionary_3 (str):
            path to cdl file with standard variables
        dictionary_4 (str):
            path to cdl file to be created

    Return:
    -------
        nc_out (str):
            path to netcdf to be created
    '''
    sprint('{0}{0}{1}{0}{0}'.format(' '*20+'+'*30+'\n', ' '*20+'+'*10+'  STEP 3  '+'+'*10+'\n'), log=log)
    
    # --------------------------------------------------
    # 1) Read, x any y vectors from the netcdf
    # --------------------------------------------------
    sprint('searching x, y, bathymetry ...', log=log)
    #coords = process_mossco_netcdf.find_coordinate_vars(topo_nc, log=log)
    structGrid = process_mixed_data.containerForGridGeneration(topo_nc, log=log)
    coords = structGrid.get_data()
    meta   = structGrid.get_metadata()

    # --------------------------------------------------
    # 2) Create mask
    # --------------------------------------------------
    sprint('creating mask...', log=log)
    #m = process_mossco_netcdf.make_mask_array_from_mossco_bathymetry(topo_nc, varname=coords['bName'], fillvalue=None, transpose=True, log=log)
    m = structGrid.get_mask(transpose=False, log=log)

    

    # --------------------------------------------------
    # 3) Create grid, and unpack values
    # --------------------------------------------------
    start_index = 0
    sprint('Generating uGrid... (be patient, this may take a while)')
    dims, topo, nodes, edges, faces, bounds = make_grid.make_2d_qudratic_grid_or_curvilinear(coords['x'], coords['y'],
                                                data_location=meta['x']['points_location'], mask=m, log=log, startingindex=start_index)

    nMesh2_node = dims[0]
    nMesh2_edge = dims[1]
    nMesh2_face = dims[2]
    nMaxMesh2_face_nodes = dims[3]

    Mesh2_edge_nodes = topo[0]
    Mesh2_edge_faces = topo[1]
    Mesh2_face_nodes = topo[2]
    Mesh2_face_edges = topo[3]

    Mesh2_node_x = nodes[0]
    Mesh2_node_y = nodes[1]

    Mesh2_edge_x = edges[0]
    Mesh2_edge_y = edges[1]

    Mesh2_face_x = faces[0]
    Mesh2_face_y = faces[1]
    Mesh2_face_center_x = faces[2]
    Mesh2_face_center_y = faces[3]
    Mesh2_face_area = faces[4]

    Mesh2_edge_x_bnd = bounds[0]
    Mesh2_edge_y_bnd = bounds[1]
    Mesh2_face_x_bnd = bounds[2]
    Mesh2_face_y_bnd = bounds[3]

    # --------------------------------------------------
    # 4) Get bumber of vertical layers, dimensions from MOSSCO
    # --------------------------------------------------
    nLayers, layer_fname = process_mossco_netcdf.get_number_of_depth_layer_from_mossco(list_with_synoptic_nc, dimname='getmGrid3D_getm_3')

    # --------------------------------------------------
    # 5) Create netcdf
    # --------------------------------------------------
    if not create_davit_netcdf:
        print "\nAbortig here...\nNetcdf has not been created, switch flag 'create_davit_netcdf' to True."
        sys.exit(0)

    process_davit_ncdf.create_uGrid_ncdf(nc_out,
                        nMesh2_node, nMesh2_edge, nMesh2_face, nMaxMesh2_face_nodes,
                        Mesh2_edge_nodes, Mesh2_edge_faces, Mesh2_face_nodes, Mesh2_face_edges,
                        Mesh2_node_x, Mesh2_node_y, Mesh2_edge_x, Mesh2_edge_y,
                        Mesh2_face_x, Mesh2_face_y, Mesh2_face_center_x, Mesh2_face_center_y,
                        Mesh2_face_area=Mesh2_face_area,
                        Mesh2_edge_x_bnd=Mesh2_edge_x_bnd, Mesh2_edge_y_bnd=Mesh2_edge_y_bnd,
                        Mesh2_face_x_bnd=Mesh2_face_x_bnd, Mesh2_face_y_bnd=Mesh2_face_y_bnd,
                        coord_type=meta['x']['coordinate_type'],
                        dim_nMesh2_layer2d=1, dim_nMesh2_layer3d=nLayers, dim_nMesh2_class_names_strlen=20, dim_nMesh2_suspension_classes=1,
                        start_index=start_index,
                        log=log)
    if log: print 'grid created', '\n', '-'*100, '\n', 'Now adding data', '\n', '-'*100

    
    # --------------------------------------------------
    # 6) fill netcdf with time variables (TIME and DATATIME)
    # --------------------------------------------------
    if log: print '-'*100
    time_added = False
    for nc_file in list_with_synoptic_nc:
        try:
            process_davit_ncdf.append_Time_andDatetime_to_netcdf(nc_out, nc_file, time_var_name='time', log=log)
            if log: print 'added "nMesh2_data_time" from file ', nc_file
            time_added = True
            break
        except KeyError:  # if var is not found in current file => skip to next file
            pass
    if not time_added:
        print 'WARNING! added dummy "nMesh2_data_time"'
        process_davit_ncdf.append_Time_andDatetime_to_netcdf(nc_out, dummy_values=True, log=log)


    if log: print '-'*100
    # ---------------------------------------------------------------------------
    # 7) Layer thicness
    # ---------------------------------------------------------------------------
    
    # now moved to the very bottom, since we want to use dictionary VARS
    # that is generated by processing Dict4

    # --------------------------------------------------
    # 8) fill netcdf with SYNOPTIC data!!!
    # --------------------------------------------------
    if log: print '-'*100+'\n+Now adding data based on Dictionary 4.\n'+'-'*100
    # --------------------------------------------------
    # -- 8.1) fill netcdf with SYNOPTIC data!!!
    # --------------------------------------------------
    VARS = process_cdl.read_file_with_only_variables(process_cdl.read_file_delete_comments(dictionary_4, comments='//'))

    # -----------------------------------------------------------------------------------------------
    # -- 8.2) cycle through found variables
    # -----------------------------------------------------------------------------------------------
    for var_name, var in VARS.iteritems():
        sprint('Variable read from Dictionary 4:', var.get_name(), log=log)
        varExt = process_mixed_data.cdlVariableExt(var)  #var is an instance of type <cdlVariable>
        source = varExt.get_source_metadata()

        # -----------------------------------------------------------------------------------------------
        # 8.2.4) add data
        # -----------------------------------------------------------------------------------------------

        if source['nNonOneDims'] not in [0, 1, 2, 3, 4]:
            ui.promt('WARNING! Skipping variable: <{0}> with dimensions <{1}> of shape <{2}>. It has <{3}> non-one dimensions. Currently <=4 is supported. Press ENTER to continue'.format(
                        source['name'], source['dims'], source['shape']), source['nNonOneDims'], color='yellow', pause=True)
            break
        raw_data = process_mossco_netcdf.read_mossco_nc_rawvar(source['fname'], source['name'])
        var_data = process_mixed_data.flatten_xy_data(raw_data, mask=m)


        # -----------------------------------------------------------------------------------------------
        # 8.2.6) append data variable to nc_out...
        # -----------------------------------------------------------------------------------------------
        process_davit_ncdf.append_VariableData_to_netcdf(nc_out, var, var_data, fv=source['fillvalue'],  log=log)
        sprint('\n', log=log)
        del varExt
    


    # -----------------------------------------------------------------------------------------------
    # 9) Layer thickness
    # -----------------------------------------------------------------------------------------------
    sprint('-'*100, log=log)
    sprint('Now adding vertical layer information', log=log)
    sprint('-'*100, log=log)

    vertical_coord_mode = 'sigma'

    if nLayers > 1:  #if a real 3d is here
        LAYERS_ADDED = False
        if vertical_coord_mode == 'sigma':
            add_eta = 'Mesh2_face_Wasserstand_2d' in VARS.keys()
            add_depth = 'Mesh2_face_depth_2d' in VARS.keys()
            try:
                process_davit_ncdf.append_sigma_vertical_coord_vars(list_with_synoptic_nc, nLayers, nc_out, add_eta=add_eta, add_depth=add_depth, mask=m, log=log)
                LAYERS_ADDED = True
            except Exception as exp:
                sprint(exp, mode='fail')
                traceback.print_exc(file=sys.stderr)
        else:
            raise NotImplementedError()
        if not LAYERS_ADDED:
            ui.promt('Now i will try to add dummy vertical data. Press ENTER to see info about these values', pause=True)
            sprint(process_davit_ncdf.append_test_Mesh2_face_z_3d_and_Mesh2_face_z_3d_bnd.__doc__)
            if ui.promtYesNo('Do you want to proceed?', quitonno=True):
                try:
                    process_davit_ncdf.append_test_Mesh2_face_z_3d_and_Mesh2_face_z_3d_bnd(nc_out, nx=meta['b']['shape'][-1],
                                    ny=meta['b']['shape'][-2], mask=m, log=log)
                except Exception as exp:
                    sprint(exp, mode='fail')
                    traceback.print_exc(file=sys.stderr)
                    ui.promt('Failed to find any vertical-layer information. Will proceed without any. Press ENTER', color='yellow', pause=True)


                
    if log: print '-'*100


    if create_davit_netcdf:
        print 'File created:', os.path.abspath(nc_out)
def append_sigma_vertical_coord_vars(list_with_filenames, nLayers, nc_out_fname, add_eta=False, add_depth=False, mask=None, sigma_varname='level', log=False):
    ''' Appends variables that define vertical position of layers...
            - nMesh2_layer_3d                       >>> 1d sigma coords of cell center
            - Mesh2_face_z_face_3d                  >>> elevation cell center values
            - Mesh2_face_z_face_3d_bnd              >>> elevation cell border values
            - (optionaly) Mesh2_face_Wasserstand_2d >>> water level
            - (optionaly) Mesh2_face_depth_2d       >>> bottom depth
        ... to passed `nc_out_fname` netcdf file
        
    Args:
    -----
        list_with_filenames (list of str):
            list with names of netcdf files. The var `sigma_varname` will be searched within this files
        nLayers (int):
            number of vertical layers
        nc_out_fname (str):
            filename of the output netcdf file
        add_eta (bool):
            flag to add variable "Mesh2_face_Wasserstand_2d" to file `nc_out_fname`.
            This is useful because, most likely this var is already appended or will be
            appended to file based on DICTIONARY4
        add_depth (bool):
            flag to add variable "Mesh2_face_depth_2d" to file `nc_out_fname`
            This is useful because, most likely this var is already appended or will be
            appended to file based on DICTIONARY4
        mask (2D array of bool):
            2d array of (y, x) dimensions with boolean mask (to treat NaN cells)
        sigma_varname (str):
            name of the varable to get sigma-layer info from
        log (bool):
            flag to print output
        
    '''
    _i = '\t'
    _n = 'append_sigma_vertical_coord_vars()'
    sprint(_n, 'Appending sigma_vertical coordinates ...', log=log, mode='bold')
    # ----------------------------------------
    # ----------------------------------------
    # ---------------  SIGMA   ---------------
    # ----------------------------------------
    # ----------------------------------------
    var = process_cdl.cdlVariable()
    var.set_name('nMesh2_layer_3d')
    var.set_dtype('double')
    var.set_dims(('nMesh2_layer_3d', ))
    var.set_fillvalue(False)
    var.set_attr('standard_name', 'ocean_sigma_coordinate')
    var.set_attr('long_name', "sigma at layer midpoints")
    var.set_attr('positive', 'up')
    var.set_attr('formula_terms', 'sigma: nMesh2_layer_3d eta: Mesh2_face_Wasserstand_2d depth: Mesh2_face_depth_2d')

    sigma, sigma_type = process_mossco_netcdf.get_sigma_coordinates(list_with_filenames, nLayers, sigma_varname=sigma_varname, waterdepth_varname='water_depth_at_soil_surface', layerdepth_varname='getmGrid3D_getm_layer', indent=_i, log=log)
    if sigma_type == 'center':
        pass
    elif sigma_type == 'border':
        sigma = process_mixed_data.create_sigma_coords_of_layer_center(sigma)

    append_VariableData_to_netcdf(nc_out_fname, var, sigma, fv=var.get_fillvalue(), log=log, indent=_i)
    del var

    bathymetry = None
    for nc_file in list_with_filenames:
        root_grp = Dataset(nc_file, mode='r')
        if 'bathymetry' in root_grp.variables.keys() and bathymetry is None:
            bathymetry = process_mossco_netcdf.read_mossco_nc_rawvar(nc_file, 'bathymetry')
        root_grp.close()
        del root_grp

    # ----------------------------------------
    # ----------------------------------------
    # ---------------  ETA   -----------------
    # ----------------------------------------
    # ----------------------------------------
    var_e = process_cdl.cdlVariable()
    var_e.set_name('Mesh2_face_Wasserstand_2d')
    var_e.set_dtype('float')
    var_e.set_dims(('nMesh2_data_time', 'nMesh2_face'))
    var_e.set_fillvalue(False)
    var_e.set_attr('long_name', "Wasserstand, Face (Polygon)")
    var_e.set_attr('standard_name', 'sea_surface_height')
    var_e.set_attr('units', 'm')
    var_e.set_attr('name_id', 3)
    var_e.set_attr('cell_measures', 'area: Mesh2_face_wet_area')
    var_e.set_attr('cell_measures', 'nMesh2_data_time: point area: mean')
    var_e.set_attr('coordinates', 'Mesh2_face_x Mesh2_face_y Mesh2_face_lon Mesh2_face_lat')
    var_e.set_attr('grid_mapping', 'Mesh2_crs')
    var_e.set_attr('mesh', 'Mesh2')
    var_e.set_attr('location', 'face')

    sprint(_n, ' Get waterlevel ...', log=log, mode='bold')
    water_level = process_mossco_netcdf.get_water_level(list_with_filenames, wl_vname='water_level',
                    water_depth_at_soil_surface_vname='water_depth_at_soil_surface', bathymetry_vname='bathymetry',
                    log=log, indent=_i)
    # append var after


    # ----------------------------------------
    # ----------------------------------------
    # --------------  DEPTH   ----------------
    # ----------------------------------------
    # ----------------------------------------
    var_d = process_cdl.cdlVariable()
    var_d.set_name('Mesh2_face_depth_2d')
    var_d.set_dtype('double')
    var_d.set_dims(('nMesh2_time', 'nMesh2_face'))
    var_d.set_fillvalue(False)
    var_d.set_attr('long_name', "Topographie")
    var_d.set_attr('standard_name', 'sea_floor_depth_below_geoid')
    var_d.set_attr('units', 'm')
    var_d.set_attr('name_id', 17)
    var_d.set_attr('cell_measures', 'area: Mesh2_face_area')
    var_d.set_attr('cell_measures', 'nMesh2_time: mean area: mean')
    var_d.set_attr('coordinates', 'Mesh2_face_x Mesh2_face_y Mesh2_face_lon Mesh2_face_lat')
    var_d.set_attr('grid_mapping', 'Mesh2_crs')
    var_d.set_attr('mesh', 'Mesh2')
    var_d.set_attr('location', 'face')
    # append var after

    # ----------------------------------------
    # ----------------------------------------
    # ------------  ELEVATION   --------------
    # ----------------------------------------
    
    # ----------------------------------------
    # FACE cell center values.....
    # ----------------------------------------
    var1 = process_cdl.cdlVariable()
    var1.set_name('Mesh2_face_z_face_3d')
    var1.set_dtype('float')
    var1.set_dims(('nMesh2_data_time', 'nMesh2_layer_3d', 'nMesh2_face'))
    var1.set_fillvalue(None)
    var1.set_attr('long_name', 'z_face [ face ]')
    var1.set_attr('units', 'm')
    var1.set_attr('positive', 'up')
    var1.set_attr('name_id', 1702)
    var1.set_attr('bounds', 'Mesh2_face_z_face_bnd_3d')
    var1.set_attr('standard_name', 'depth')
   
    # ----------------------------------------
    # FACE cell border values.....
    # ----------------------------------------
    var2 = process_cdl.cdlVariable()
    var2.set_name('Mesh2_face_z_face_bnd_3d')
    var2.set_dtype('float')
    var2.set_dims(('nMesh2_data_time', 'nMesh2_layer_3d', 'nMesh2_face', 'two'))
    var2.set_fillvalue(None)
    var2.set_attr('long_name', 'elevations of lower and upper layer-boundaries')
    var2.set_attr('units', 'm')

    sprint(_n, ' Get elevation of cell centers and cell borders ...', log=log, mode='bold')
    elev, elev_borders = process_mixed_data.create_layer_elevation_from_sigma_coords(water_level, sigma, bathymetry, log=log, indent=_i)
    

    var_data1  = process_mixed_data.flatten_xy_data(elev, mask=mask)
    var_data2 = process_mixed_data.flatten_xy_data(elev_borders, mask=mask)
    
    append_VariableData_to_netcdf(nc_out_fname, var1, var_data1, fv=var1.get_fillvalue(), log=log, indent=_i)
    append_VariableData_to_netcdf(nc_out_fname, var2, var_data2, fv=var2.get_fillvalue(), log=log, indent=_i)
    del var1, var2



    if add_depth:
        var_data = process_mixed_data.flatten_xy_data(bathymetry, mask=mask)
        append_VariableData_to_netcdf(nc_out_fname, var_d, var_data, fv=var_d.get_fillvalue(), log=log, indent=_i)
        del var_d
    if add_eta:
        var_data = process_mixed_data.flatten_xy_data(water_level, mask=mask)
        append_VariableData_to_netcdf(nc_out_fname, var_e, var_data, fv=var_e.get_fillvalue(), log=log, indent=_i)
        del var_e

    if log:
        print '-'*25+'\n'