Load <- function(var, exp = NULL, obs = NULL, sdates, lonmin = 0, lonmax = 360, 
                 latmin = -90, latmax = 90, nleadtime = NULL, nmember = NULL, 
                 nmemberobs = NULL, leadtimemin = 1, leadtimemax = NULL, 
                 storefreq = 'monthly', sampleperiod = 1, output = 'areave', 
                 method = 'conservative', grid = NULL, 
                 maskmod = vector("list", 15), maskobs = vector("list", 15), 
                 configfile = NULL) {
  # TODO: Comprovar tots els TODO i totes els bugfix
  # TODO: COPIAR I ACTUALITZAR DOC I TOTS ELS COMENTARIS EN GENERAL

  # TODO: I have added nmemberobs parameter

  # This function loads experimental data together with observational data at 
  # the corresponding dates from the specified experimental and observational 
  # datasets. It organizes the data in two matrices with dimensions:
  #  c(nexp/nmod, nmembers, nsdates, nleadtimes) for the experiments
  #  c(nobs/nreanalyses, nmembers, nsdates, nleadtimes) for the observations
  # up to
  #  c(nexp/nmod, nmembers, nsdates, nleadtimes, ndepth, nlat, nlon) 
  #  c(nobs/nreanalyses, nmembers, nsdates, nleadtimes, ndepth, nlat, nlon)
  # Only a specified variable and set of starting dates is loaded.
  # Once the two matrices are filled by calling this function, other functions
  # in the 2dverification package that require this data structure can be 
  # executed (e.g: Clim() to compute climatologies,  Ano() to compute 
  # anomalies, ...).
  #
  # Load() retrieves information about the location of the datasets from a 
  # configuration file that has to be filled in following the rules specified
  # in ?LoadConfigurationFile.
  # The data files in the file system can be in the following formats:
  #  - Experimental datasets:
  #   · Stored in a file per ensemble (the file path must contain the starting
  #     date).
  #   · Stored in a file per member (the file path must contain the starting
  #     date and member number, being 0 the first member).
  #  - Observational datasets:
  #   · Stored in a single file (cdo showmon and showyear will read the
  #     month and year associated to each value).
  #   · Stored in a file per month containing all the members (the file path
  #     must contain the year and month numbers).
  #   · Stored in a file per month per each member (the file path must contain
  #     the year and month numbers and the member number, being 0 the first member).
  # From which it is possible to load:
  #  - 2d and global mean variables (variable name inside .nc files can be 
  #    different but it is not recommended).
  #  - Supported outputs: lonlat, lon, lat, areave (except in single file
  #    observations, which only support lonlat if is a 2d variable or areave if
  #    is a global mean, only reading data, not processing)
  #
  # The function Load() returns a list which contains four components: 
  # $mod, $obs, $lat and $lon.
  # $mod is the matrix containing the experimental data.
  # $obs is the matrix containing the observational data.
  # $lat and $lon are the latitudes and longitudes of the model grid (0 if the
  # loaded variable is a global mean).
  #
  # The experimental data matrix will contain the values of a given variable 
  # for all the experiments the user wish to compare for a set of starting 
  # dates, lead-times, longitudes and latitudes interpolated to the common grid
  # and with the masks applied.
  # The observational data matrix will contain the observed values of the same
  # variable gathered from the specified observational datasets scanning the 
  # data repository. The observational data is chosen so as to date-correspond
  # the experimental data.
  #
  # The data matrices are built with the dimensions in the following order and 
  # with the following lengths:
  # 1- The number of experimental datasets determined by the user (we need to 
  # store data of all the experiments in the same array) for the experimental 
  # matrix or the number of observational datasets available for validation in 
  # the observational matrix.
  # 2- The greatest number of members across all experiments.
  # 3- The number of starting dates determined by the user (we need to store 
  # data of each prediction of the model in each starting date).
  # 4- The greatest number of lead-times.
  # 5- The number of latitudes of the zone we want to consider.
  # 6- The number of longitudes of the zone we want to consider.
  #
  # Dimensions 5 and 6 are optional and their presence will depend on whether 
  # the variable loaded is 2-dimensional or an area average. 
  # In the case of an area average the dimensions of the matrix will be only the 
  # first 4.
  #
  # Furthermore, if the user loads a 2-dimensional variable, he/she can ask 
  # Load() to load it as area averages, as longitudinal averages in function of 
  # latitudes or as in latitudinal averages in function of longitudes. In these 
  # cases the 5th and/or 6th dimension will also disappear.
  #
  # The observational data matrix is built very similarly to the experimental 
  # matrix. The only differences are that the first dimension turns to be the
  # number of observational datasets and the length of the 2nd dimension turns  
  # to be the number of members of the observational datasets. Later, for each 
  # lead-time we will store observational data into it if possible.
  #
  # Any value that can't be filled (either in the experimental matrix or the 
  # observational matrix) should figure as an NA value.
  # 
  # Args:
  #   var: Variable id. Must match with at least one of the listed in the 
  #        configuration file.
  #   exp: IMPORTANT: Place first the experiment with the largest number of 
  #        members and, if possible, with the largest number of leadtimes. If
  #        not possible, it is mandatory to specify the argument nleadtime
  #        and/or nmember.
  #        Collection of experiment ids. All must match at least one entry in
  #        the tables of experiments in the configuration files.
  #        c('EnsEcmwfDec', 'EnsUkmoDec', 'EnsCerfacsDec', 'EnsIfmDec',
  #          'EnsEcmwfSeas', 'EnsCmccSeas', 'EnsIfmSeas', 'EnsMetfrSeas',
  #          'EnsUkmoSeas', 'DePreSysAsimDec', 'DePreSysNoAsimDec',
  #          'DePreSysAsimSeas', 'ECMWF_S3Seas', 'ECMWF_S4_sea',
  #          'ECMWF_S4_ann', 'hadcm3dec', 'miroc4dec', 'miroc5dec',
  #          'mri-cgcm3dec', 'cancm4dec1', 'cancm4dec2', 'cnrm-cm5dec',
  #          'knmidec', 'smhidec', 'mpimdec', 'gfdldec', 'cmcc-cmdec',
  #          'ipsldec', 'bccdec', 'gfdlhis', 'ipslhis', 'cmcc-cmhis', 'bcchis',
  #          'i00k', 'b013', 'b014', ...)
  #   obs: IMPORTANT: Place first the observation with the largest number of 
  #        members or specify the argument nmemberobs.
  #        Collection of observation ids. All must match at least one entry in
  #        the tables of observations in the configuration files.
  #        c('ERA40', 'NCEP', 'ERAint', '20thCv2', 'GHCN', 'GHCNERSSTGISS', 
  #          'ERSST', 'HadISST', 'GPCP', 'GPCC', 'CRU', 'HadSLP', 'NSIDC', 
  #          'PIOMAS', 'UdCL', 'DS94', 'OAFlux', 'DFS4.3', 'NCDCglo', 'NCDCland', 
  #          'NCDCoc', 'GISSglo', 'GISSland', 'GISSoc', 'HadCRUT3glo', 
  #          'HadCRUT4', 'HadSST2oc', 'CRUTEM3land')
  #   sdates: c('YYYYMMDD','YYYYMMDD', ...)
  #   lonmin: >= 0, default: 0
  #   lonmax: <= 360, default: 360
  #   latmin: >= -90, default: -90
  #   latmax: <= 90, default: 90
  #   nleadtime: Optional argument needed only if the first experiment in the
  #              parameter exp does not have the largest number of leadtimes.
  #              Default: number of leadtimes of the first experiment.
  #   nmember: Some experiments have more members in starting dates other than
  #            the first or more than other experiments loaded at the same 
  #            Load() call. If it is the case in the first experiment specified,
  #            fill nmember with the largest number of members.
  #            This argument always needs to be filled when loading file per 
  #            member experiments, also with the largest number of members.
  #   nmemberobs: Same as 'nmember' but for observational datasets.
  #   leadtimemin: Load into the matrices only the leadtimes from leadtimemin. 
  #                Default: 1.
  #   leadtimemax: Load into the matrices only the leadtimes before leadtimemax.
  #                Default: nleadtime.
  #   storefreq: Frequency at which the data to be loaded are stored in the 
  #              repository. Can take values 'monthly' or 'daily'. 
  #              Default: 'monthly'.
  #   sampleperiod: To load only a subset between leadtimemin and leadtimemax 
  #                 with a specified period of subsampling. 
  #                 Default: 1 (all leadtimes are loaded).
  #   output: 'areave' / 'lon' / 'lat' / 'lonlat'.
  #           1) Time series of area-averaged variables over the specified 
  #              domain.
  #           2) Time series of meridional averages as a function of longitudes.
  #           3) Time series of zonal averages as a function of latitudes.
  #           4) Time series of 2d fields.
  #           Default: 'areave'
  #   method: 'bilinear' / 'bicubic' / 'conservative' / 'distance-weighted'
  #           Method of interpolation for 'lon' / 'lat' / 'lonlat' output 
  #           options.
  #           Default: 'conservative'.
  #   grid: To choose a common output grid.
  #         Possible options: rNXxNY or tTRgrid, ex: r96x72, t106grid.
  #         Default: By default, the data of each experimental dataset will be 
  #         loaded into the matrix using the grid in which the data is stored 
  #         in the repository.
  #         IMPORTANT: If various experiments in different grids are specified, 
  #         a common grid has to be specified using this argument.
  #
  #         How grids work:
  #  
  #         We may load one or more experiments and corresponding data from one 
  #         or more observations.
  #         The most usual is that they are on different grids.
  #
  #         We can set Load() to output the data in 4 different modes:
  #         
  #         If output = 'areave' all the data is area-averaged.
  #         If output = 'lon', the data are averaged along the latitude 
  #         dimension and output as a function of the longitudes.
  #         If output = 'lat', the data are averaged along the longitude 
  #         dimension and output as a function of the latitudes.
  #         If output = 'lonlat', the data are output as a function of the 
  #         longitudes and latitudes.
  #         
  #         We refer to the last 3 modes as maps.
  #
  #         If we want to get data output in maps but the experiments and
  #         observations are on different grids, we need to specify a common 
  #         gridding (with the  parameter grid) onto which the loaded data 
  #         will be interpolated.
  #         If we don't do, Load() will crash.
  #         
  #         If we want to get area-averages, the experiments and observations 
  #         can be on different grids and there is no need to specify a common 
  #         grid: Load() will calculate their mean over the original grids 
  #         unless a common grid is specified.
  #         TODO: Not for obs! Obs will be regridded always to the first grid.
  #               Should we add a grid for obs too?
  #
  #         Whenever we specify a common gridding, all data (observational and
  #         experimental) is interpolated onto it.
  #
  #   maskmod: list(mask[lon,lat]) = 1/0: kept/removed grid cell over the 
  #            entire model domains.
  #            Warning: list() compulsory even if 1 model!!!
  #            Default: 1 everywhere.
  #
  #            How masks work:
  #            
  #            When we want to disable certain values we can specify masks. The 
  #            disabled values will be replaced with NA values.
  #
  #            In the case that you wish to load data as area-averages:
  #            You can specify a mask for each experiment and observation.
  #            Each area average will be performed on the original experiment 
  #            or observation grid and after applying the respective mask.
  #
  #            In the case that you wish to load maps:
  #            You will have defined a mandatory common grid which all the data 
  #            will be interpolated onto.
  #            If you want to specify a mask, you will have to provide it 
  #            already interpolated onto the common grid (you may use 'cdo' for 
  #            this purpose).
  #            It is not usual to apply different masks on experimental 
  #            datasets on the same grid. All the experiment masks are expected 
  #            to be the same.
  #            In this case, defining masks for the observational data will be 
  #            useless: the same mask applied to the experimental data will be 
  #            applied to
  #            the observational data because the observations are interpolated 
  #            on the common grid for which the mask has already been defined 
  #            when loading experimental data.
  #
  #   maskobs: list(mask[lon,lat]) = 1/0: kept/removed grid cell over the 
  #            entire observed domains, only necessary for 'areave' output 
  #            option.
  #            Warning: list() compulsory even if 1 dataset !!!
  #            Default: 1 everywhere.
  # 
  # Returns:
  #   $mod: Model outputs.
  #         If output = 'areave', matrix with dimensions
  #           c(nmod/nexp or nobs, nmemb/nparam, nsdates, nltime)
  #         If output = 'lat', matrix with dimensions
  #           c(nmod/nexp or nobs, nmemb/nparam, nsdates, nltime, nlat)
  #         If output = 'lon', matrix with dimensions
  #           c(nmod/nexp or nobs, nmemb/nparam, nsdates, nltime, nlon)
  #         If output = 'lonlat', matrix with dimensions
  #           c(nmod/nexp or nobs, nmemb/nparam, nsdates, nltime, nlat, nlon)
  #   $obs: Observations. Matrix with same dimensions as '$mod'.
  #   $lat: Latitudes of the model grid.
  #   $lon: Longitudes of the model grid.
  #
  # History:
  #   1.0  #  2011-03  (V. Guemas, virginie.guemas@ic3.cat)     # Original code
  #   1.1  #  2014-03  (N. Manubens, nicolau.manubens@ic3.cat)  # Formatting to CRAN
  #   1.2  #  2015-01  (N. Manubens, nicolau.manubens@ic3.cat)  # Configuration file
  
  ## Packages and resources required.
  #library(ncdf)

  # Extend the current environment with the functions and variables related to 
  # the configuration file mechanism which contain the information about the 
  # location of the datasets.
  putInDictionary <- replaceVariablesInString <- NULL
  replace_values <- is_atm_var <- exp_info <- obs_info <- NULL
  is_file_per_member_exp <- is_file_per_member_obs <- is_file_per_dataset_obs <- NULL
  LoadConfigurationFile(environment())
 
  # 
  #  Get matrices dimensions from the input
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  #
  # The two data matrices are similar and have 7 dimensions each with the 
  # following lengths:
  #   1) Number of experimental/observational datasets.
  #   2) Number of members.
  #   3) Number of starting dates.
  #   4) Number of lead-times.
  #   5) Number of latitudes (optional).
  #   6) Number of longitudes (optional).
  # 
  # We can give values to some of these lengths already. 
  # The lengths will vary in function of the datasets we load and will be 
  # re-adjusted along the process.
  nmod <- length(exp)
  nobs <- length(obs)
  nsdates <- length(sdates)
  
  ## Are the dimensions of the matrices yet defined?
  dims2define <- TRUE
  ## Are the matrices yet created?
  mat2define <- TRUE
  ## Is the mask for each experiment still to be created?
  flag_mask_mod <- array(TRUE, dim = nmod)
  ## Is the mask for each observation still to be created?
  flag_mask_obs <- array(TRUE, dim = nobs)
  ## We choose the kind of interpolation for the 'cdo regrid' tool.
  remap <- switch(method, 'bilinear' = 'remapbil', 'bicubic' = 'remapbic', 
                  'conservative' = 'remapcon', 'distance-weighted' = 'remapdis')
  common_grid <- grid
  ## For each experiment we will keep a matrix of weights to make data in wider
  ## areas more important.
  ## Due to NA values in the data the weights will change among experiments, 
  ## thus it is needed to keep a matrix of weights for each experiment.
  weight_area <- list()
  ## bugfix: weight_lon <- list()
  ## For each observational dataset we keep likely a matrix of weights.
  weight_area_obs <- list()
  ## bugfix: weight_lon_obs <- list()

  ## TODO: lat_obs and lon_obs..?
  lat_mod <- lon_mod <- NULL
  var_exp <- NULL
  var_obs <- NULL
  ## Make sure that longitude bounds are positive
  if  (lonmin < 0) {
    lonmin <- lonmin + 360
  }
  if (lonmax < 0) {
    lonmax <- lonmax + 360
  }

  if (!is_atm_var && (output != 'areave')) {
    print(paste("Warning: '", output, "' output format not allowed when loading global mean variables. Forcing to 'areave'.", 
                sep = ''))
    output <- 'areave'
  }

  # Start loading data into the matrices.
  jsdate <- 1
  for (sdate in sdates) {  # Loop on starting dates
    # Put the starting date in the table of variables.
    # These variables will help to build the path to each dataset file.
    replace_values <- putInDictionary(replace_values, "START_DATE", sdate)
    #
    #  Loading experimental data
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #
    dataset_type <- 'exp' 
    jmod <- 1
    for (mod in exp) {  # Loop on experimental datasets
      # Put the experiment name in the table of variables.
      replace_values <- putInDictionary(replace_values, "EXP_NAME", mod)
      # And the first member number
      jmemb <- 1
      replace_values <- putInDictionary(replace_values, "MEMBER_NUMBER", jmemb - 1)
      # and its associated values read from the configuration file
      dataset_info <- exp_info[[jmod]]
      replace_values <- putInDictionary(replace_values, "EXP_MAIN_PATH", dataset_info[1])
      replace_values <- putInDictionary(replace_values, "EXP_FILE_PATH", dataset_info[2])
      replace_values <- putInDictionary(replace_values, "GRID", dataset_info[3])
      replace_values <- putInDictionary(replace_values, "NC_VAR_NAME", dataset_info[4])
      namevar <- replaceVariablesInString(dataset_info[4], replace_values)
      
      # The data of the first dataset file is loaded to try to work out the
      # dimensions of the output matrices
      filename <- file_found <- lon <- lat <- tmp <- NULL
      LoadDataFile(environment())

      ## TODO: Should we allow empty values in experimental data?
      #if (!file_found && jmod == 1 && jsdate == 1) {
      #  stop("Error: there must be data in the file system for at least the first member of the first experimental dataset.")
      #}

      # If a file was found, we can work out the number of members. Otherwise 
      # we skip to the next experiment
      if (file_found || is_file_per_member_exp[jmod]) {
        if (is_file_per_member_exp[jmod]) {
          if (is.null(nmember)) {
            ## TODO: this default is not general
            nmember <- nmemb <- 9
            print("Warning: the 'nmember' argument must be filled when placing first a file per member experiment. Forcing to 9.")
          } else {
            nmemb <- nmember
          }
        } else {
          nmemb <- dim(tmp)[3]
          if (is.null(nmember)) {
            nmember <- nmemb
          }
        }
        if (nmemb > nmember) {
          stop("Error: PUT FIRST THE EXPERIMENT ID WITH THE LARGEST NUMBER OF MEMBERS or fill in correctly the 'nmember' argument.
                If already done, check the dimensions of your files in the repository.")
        }

        print(filename)
        
        # We are ready to loop on the members.

        for (jmemb in 1:nmemb) {
          #Put the member number in the table of variables for the configuration file.
          replace_values <- putInDictionary(replace_values, "MEMBER_NUMBER", jmemb - 1)
          loadmemb <- jmemb
          # If it is a file per member experiment we will load the data at 
          # each iteration.
          if (is_file_per_member_exp[jmod] && (jmemb > 1)) {
            LoadDataFile(environment())
            loadmemb <- 1
            if (file_found) {
              print(filename)
            }
          }
          
          if (file_found) {
            ## At this point, if we are in the first experiment, we can define 
            ## the definitive lengths of the dimensions of the experimental 
            ## matrix.
            if (dims2define) {
              if (is.null(nleadtime)) {
                nleadtime <- dim(tmp)[4]
              }
              if (is.null(leadtimemax)) {
                leadtimemax <- nleadtime
              }
              dims2define <- FALSE
            }

            ## If the variable is 2-dimensional:
            if (is_atm_var) {
              # We loop on the lead-times. 
              for (jtime in seq(leadtimemin, leadtimemax, sampleperiod)) {
                ## For each lead-time we create a matrix
                ## of size longitudes x latitudes and fill it in with the data in 
                ## the matrix tmp that corresponds to the current lead-time.
                tmp1 <- array(dim = c(length(lon), length(lat)))
                ## TODO: Everything should be included in this 'if' to avoid
                ##       unneeded calculations when jtime > dim(tmp)[4]
                if (jtime <= dim(tmp)[4] && loadmemb <= dim(tmp)[3]) {
                  tmp1 <- tmp[, , loadmemb, jtime]
                }
                #
                #  Selecting the masked domain
                # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
                #
                indlon <- which((lon >= lonmin & lon <= lonmax) | 
                                (lonmax < lonmin & (lon >= lonmin | lon <= lonmax)))
                tmp2 <- tmp1[indlon, which(lat >= latmin & lat <= latmax)]
                ## In tmp2, we have the data of the current lead-time placed
                ## inside the specified longitudes and latitudes.
                ## If we have not created the mask of te current model yet:
                if (flag_mask_mod[jmod]) {
                  ## If the user did not specify a mask, we create one full of 1s.
                  if (is.null(maskmod[[jmod]])) {
                    maskmod[[jmod]] <- array(1, dim = dim(tmp1))
                  }
                  ## Else, we take the specified mask.
                  ## We slice it to fit the limited area.
                  maskmod[[jmod]] <- maskmod[[jmod]][indlon, 
                                     which(lat >= latmin & lat <= latmax)]
                  ## We define the output longitudes and latitudes
                  lat_mod <- lat[which(lat >= latmin & lat <= latmax)]
                  lon_mod <- lon[indlon]
                  ## Now the mask is marked as created.
                  flag_mask_mod[jmod] <- FALSE
                  
                  #
                  #  Computing weigths for averaging
                  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  #
                  ## If the mask was not created yet, the weights were not 
                  ## computed either. We coumpute them.
                  weight <- InsertDim(cos(lat_mod * pi / 180), 1, dim(tmp2)[1])
                  weight[which(maskmod[[jmod]] < 0.5 | is.na(tmp2))] <- NA
                  weight_lon <- weight / InsertDim(Mean1Dim(weight, 2, narm = TRUE),
                                                   2, dim(tmp2)[2])
                  ## bugfix: 
                  ##weight_lon[[jmod]] <- weight / InsertDim(Mean1Dim(weight, 2, 
                  ##                                                  narm = TRUE),
                  ##                                         2, dim(tmp2)[2])
                  weight_area[[jmod]] <- weight / mean(weight, na.rm = TRUE)
                  
                  #
                  #  Defining output matrix
                  # ~~~~~~~~~~~~~~~~~~~~~~~~
                  #
                  ## Now we will apply the weights and store the result into the
                  ## experimental matrix. If it has not been created, we create 
                  ## it.
                  ## If the user specified an output type of area average, there
                  ## will not be the 5th and 6th dimensions of longitudes and 
                  ## latitudes, and so on.
                  if (mat2define) {
                    nleadtime2 <- (leadtimemax - leadtimemin) %/% sampleperiod + 1
                    var_exp <- switch(output,
                                      'areave' = array(dim = c(nmod, nmember, nsdates, nleadtime2)),
                                      'lon' = array(dim = c(nmod, nmember, nsdates, nleadtime2, dim(tmp2)[1])),
                                      'lat' = array(dim = c(nmod, nmember, nsdates, nleadtime2, dim(tmp2)[2])),
                                      'lonlat' = array(dim = c(nmod, nmember, nsdates, nleadtime2, dim(tmp2)[2:1])))
                    ## We mark that the matrices are now created.
                    mat2define <- FALSE
                  }
                }
                ## We apply the mask to the data.
                tmp2[which(maskmod[[jmod]] < 0.5)] <- NA
                # 
                #  Computing the outputs
                # ~~~~~~~~~~~~~~~~~~~~~~~
                #
                # We apply the weights to the data and store it into the 
                # experimental matrix.
                jtime2 <- (jtime - leadtimemin) %/% sampleperiod + 1
                if (output == 'areave') {
                  var_exp[jmod, jmemb, jsdate, jtime2] <- mean(tmp2 * weight_area[[jmod]], na.rm = TRUE)
                } else if (output == 'lon') {
                  var_exp[jmod, jmemb, jsdate, jtime2, ] <- Mean1Dim(tmp2 * weight_lon, 2, narm = TRUE)
                  ## bugfix:
                  ##                                           weight_lon[[jmod]],
                } else if (output == 'lat') {
                  var_exp[jmod, jmemb, jsdate, jtime2, ] <- Mean1Dim(tmp2, 1, narm = TRUE)
                } else if (output == 'lonlat') {
                  var_exp[jmod, jmemb, jsdate, jtime2, , ] <- t(signif(tmp2, 5))
                } else {
                  stop("Wrong output option")
                }
              }
            ## If the variable is a global mean:
            } else {
              ## We do not need to apply masks or weights. Just create the 
              ## matrices if not yet created and store the data into the 
              ## experimental one.
              if (mat2define) {
                nleadtime2 <- (leadtimemax - leadtimemin) %/% sampleperiod + 1
                var_exp <- array(dim = c(nmod, nmember, nsdates, nleadtime2))
                mat2define <- FALSE
              }
              var_exp[jmod, jmemb, jsdate, 1:min(nleadtime2, 
                (dim(tmp)[4] - leadtimemin) %/% sampleperiod + 1)] <- tmp[1, 1, 
                loadmemb, seq(leadtimemin, min(leadtimemax, dim(tmp)[4]), 
                sampleperiod)]
            }
          } else {
            print(paste("Warning: Member file not found, filling with NA values instead:", filename))
          }
        }
      } else {
        print(paste("Warning: Ensemble file not found, filling with NA values instead:", filename))
      }
      jmod <- jmod + 1
    }

    # Define the number of leadtimes if there are no experiments to load.
    if ((length(obs) > 0) && (sdate == sdates[1])) {
      ## TODO: replace by if (dims2define) ? dims2define = FALSE
      if (is.null(leadtimemax)) {
        diff <- Sys.time() - as.POSIXct(paste(substr(sdate, 1, 4), '-',
                substr(sdate, 5, 6), '-', substr(sdate, 7, 8), sep=''))
        if (storefreq == 'monthly') { 
          leadtimemax <- as.integer(diff/30) 
        } else {
          leadtimemax <- as.integer(diff)
        }
      }
      nleadtime2 <- (leadtimemax - leadtimemin) %/% sampleperiod + 1
    }
  
    #
    #  Loading observational data
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #
    # Now we have to load the observational data in the current starting date
    # from the specified observational datasets that date corresponds the 
    # experimental data.
    # Each file in the repository contains data of one month.
    
    dataset_type <- 'obs'
    jobs <- 1
    for (ref in obs) {  # Loop on observational datasets.
      # Put the observation name in the table of variables for the 
      # configuration file.
      replace_values <- putInDictionary(replace_values, "OBS_NAME", ref)

      # TODO: Possible to use cdo method for all obs?
      # Two methods are used. 
      # For file per dataset observations the months and 
      # years of each value are extracted from the file via 'cdo 
      # showmon/showyear' and then selected.
      # For file per member or ensemble observations the months and years of
      # each value are extracted from the file name and each file is sliced
      # according to the selected leadtimes.
      if (!is_file_per_dataset_obs[jobs]) {
        ## The current starting date is transformed into a number to calculate the
        ## first month and day of the observation.
        if (storefreq == 'daily') {
          iday <- substr(sdate, 7, 8)
          if (iday == '') {
            iday <- '01'
          } 
          startdate <- as.POSIXct(paste(substr(sdate, 1, 4), '-',
                       substr(sdate, 5, 6), '-', iday, ' 12:00:00', sep = '')) + 
                       (leadtimemin - 1) * 86400
          iyear <- substr(startdate, 1, 4)
          imon <- as.integer(substr(startdate, 6, 7))
        } else {
          imon <- (as.integer(substr(sdate, 5, 
                   6)) + leadtimemin - 2) %% 12 + 1
          iyear <- as.integer(substr(sdate, 1, 4)) + (as.integer(substr(sdate, 
                    5, 6)) + leadtimemin - 2) %/% 12
        }
        
        ## jtime is the index of the current lead-time.
        jtime <- 1
        # We loop on the lead-times.
        while (jtime <= nleadtime2) {
          ## The current lead-time is calculated from the current starting 
          ## date as number and from the index of the current lead-time.
          ## TODO: Avoid reloading same file when possible
          if (storefreq == 'daily') {
            newdate <- startdate + 86400 * (jtime - 1) * sampleperiod
            iyear <- substr(newdate, 1, 4)
            imon <- as.integer(substr(newdate, 6, 7))
            itimind <- as.integer(substr(newdate, 9, 10))
            if (LeapYear(as.integer(iyear))) {
              lenmon <- 29
            } else { 
              lenmon <- 28
            }
            lenmon <- switch(substr(newdate, 6, 7), '01' = 31, '03' = 31, 
                      '04' = 30, '05' = 31, '06' = 30, '07' = 31, '08' = 31,
                      '09' = 30, '10' = 31, '11' = 30, '12' = 31, lenmon)
          } else {
            if (jtime > 1) {
              imon <- imon + sampleperiod
              iyear <- iyear + (imon - 1) %/% 12
              imon <- (imon - 1) %% 12 + 1
            }
            itimind <- 1
            lenmon <- 1
          }
          replace_values <- putInDictionary(replace_values, "YEAR", iyear)
          replace_values <- putInDictionary(replace_values, "MONTH", sprintf("%2.2i", imon))
          jmemb <- 1
          replace_values <- putInDictionary(replace_values, "MEMBER_NUMBER", jmemb - 1)
          dataset_info <- obs_info[[jobs]]
          replace_values <- putInDictionary(replace_values, "OBS_MAIN_PATH", dataset_info[1])
          replace_values <- putInDictionary(replace_values, "OBS_FILE_PATH", dataset_info[2])
          replace_values <- putInDictionary(replace_values, "NC_VAR_NAME", dataset_info[3])
          namevar <- replaceVariablesInString(dataset_info[3], replace_values)
          
          filename <- file_found <- lon <- lat <- tmp <- NULL
          LoadDataFile(environment())
          
          ## TODO: Is expected in other functions that obs have same number of members?
          if (is_file_per_member_obs[jobs]) {
            if (is.null(nmemberobs)) {
              stop("Error: the 'nmemberobs' argument must be filled when placing first a file per member observation.")
            } else {
              nmembobs <- nmemberobs
            }
          } else {
            nmembobs <- dim(tmp)[3]
            if (is.null(nmembobs)) {
              if (!is.null(nmemberobs)) {
                nmembobs <- nmemberobs
              }
            } else if (is.null(nmemberobs)) {
              nmemberobs <- nmembobs
            }
          }
          
          if (file_found || is_file_per_member_obs[jobs]) {
            print(filename)
            if (nmembobs > nmemberobs) {
              stop("Error: PUT FIRST THE OBSERVATION ID WITH THE LARGEST NUMBER OF MEMBERS or fill in correctly the 'nmemberobs' argument.
                    If already done, check the dimensions of your files in the repository.")
            }

            for (jmemb in 1:nmembobs) {
              #Put the member number in the table of variables for the configuration file.
              replace_values <- putInDictionary(replace_values, "MEMBER_NUMBER", jmemb - 1)
              loadmemb <- jmemb
              if (is_file_per_member_obs[jobs] && (jmemb > 1)) {
                LoadDataFile(environment())
                loadmemb <- 1
                if (file_found) {
                  print(filename)
                }
              }
            
              if (file_found) {
                #
                #  Selecting the masked domain 
                # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                #
                if (storefreq == 'monthly') {
                  rangeind <- jtime
                } else {
                  rangeind <- jtime:min((lenmon - itimind
                                         ) %/% sampleperiod + jtime, nleadtime2)
                }
                rangeindout <- seq(itimind, min(lenmon, (nleadtime2 - jtime + 1
                                   ) * sampleperiod + itimind - 1), sampleperiod)
                if (is_atm_var) {
                  indlon <- which((lon >= lonmin & lon <= lonmax) | (
                                  lonmax < lonmin & (lon >= lonmin | lon <= lonmax
                                  )))
                  tmp1 <- tmp[indlon, which(lat >= latmin & lat <= latmax), loadmemb, ]
                  if (length(dim(tmp1)) == 2 ) {
                    tmp1 <- InsertDim(tmp1, 3, 1) 
                  }
                  lat_obs <- lat[which(lat >= latmin & lat <= latmax)]
                  lon_obs <- lon[indlon]
                  if (flag_mask_obs[jobs]) {
                    if (((output != 'areave') || !is.null(grid)) && (nmod >= 1)) {
                      maskobs[[jobs]] <- maskmod[[nmod]] 
                    } else {
                      if (is.null(maskobs[[jobs]])) {
                        maskobs[[jobs]] <- array(1, dim = dim(tmp)[1:2])
                      } 
                      maskobs[[jobs]] <- maskobs[[jobs]][indlon, 
                                           which(lat >= latmin & lat <= latmax)] 
                    }
                    flag_mask_obs[jobs] <- FALSE
                    #
                    #  Computing weigths for averaging
                    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    #
                    weight <- InsertDim(cos(lat_obs * pi / 180), 1, dim(tmp1)[1])
                    weight[which(maskobs[[jobs]] < 0.5 | is.na(tmp1[, , 1]))] <- NA
                    ## bugfix: weight_lon_obs[[jobs]] <- weight / InsertDim(Mean1Dim(weight, 
                    ##                          2, narm = TRUE), 2, dim(tmp1)[2])
                    weight_area_obs[[jobs]] <- weight / mean(weight, na.rm = TRUE)
                    #
                    #  Defining output matrix
                    # ~~~~~~~~~~~~~~~~~~~~~~~~
                    #
                    if (jobs == 1) {
                      var_obs <- switch(output, 
                      'areave' = array(dim = c(nobs, nmemberobs, nsdates, nleadtime2)),
                      'lon' = array(dim = c(nobs, nmemberobs, nsdates, nleadtime2, dim(tmp1)[1])),
                      'lat' = array(dim = c(nobs, nmemberobs, nsdates, nleadtime2, dim(tmp1)[2])),
                      'lonlat' = array(dim = c(nobs, nmemberobs, nsdates, nleadtime2, dim(tmp1)[2:1])))
                    }
                  }
                  tmp1[which(InsertDim(maskobs[[jobs]], 3, lenmon) < 0.5)] <- NA
                  #
                  #  Computing the outputs
                  # ~~~~~~~~~~~~~~~~~~~~~~~
                  #
                  if (output == 'areave') {
                    for (ind in 1:lenmon) { 
                      var_obs[jobs, jmemb, jsdate, rangeind[ind]] <- mean(tmp1[, ,
                      rangeindout[ind]] * weight_area_obs[[jobs]], na.rm = TRUE)
                    }
                  } else if (output == 'lon') {
                    var_obs[jobs, jmemb, jsdate, rangeind, ] <- aperm(Mean1Dim(
                      tmp1 * InsertDim(weight_lon, 3, lenmon), 2,
                      narm = TRUE)[, rangeindout], length(dim(tmp1[, , 
                      rangeindout])):1)
                    ## bugfix:
                    ## * InsertDim(weight_lon_obs[[jobs]], 3, lenmon), 2,
                  } else if (output == 'lat') {
                    var_obs[jobs, jmemb, jsdate, rangeind, ] <- aperm(Mean1Dim(tmp1
                    , 1, narm = TRUE)[, rangeindout], 
                    length(dim(tmp1[, , rangeindout])):1)
                  } else if (output == 'lonlat') {
                    var_obs[jobs, jmemb, jsdate, rangeind, , ] <- aperm(
                    signif(tmp1[, , rangeindout], 5), 
                    length(dim(tmp1[, , rangeindout])):1)
                  } else {
                    stop("Wrong output option")
                  }
                } else {
                  ## If the variable is oceanic, it will be a global mean so the weights 
                  ## do not need to be calculated:
                  var_obs[jobs, jmemb, jsdate, rangeind] <- tmp[1, 1, loadmemb, rangeindout]
                  ## TODO: Missing lat_obs <- 0 lon_obs <- 0?
                }
              } else {
                print(paste("Warning: Observation member monthly file not found, filling with NA values instead:", filename))
              }
            }
          } else {
            print(paste("Warning: Observation ensemble monthly file not found, filling with NA values instead:", filename))
          }
          jtime <- jtime + (lenmon - itimind) %/% sampleperiod + 1
        }
      } else {
        ## Selection via 'cdo showmon/showyear'
        filename <- lon <- lat <- tmp <- NULL
        LoadDataFile(environment())
        
        if (file_found) {
          print(filename)
          for (jmemb in 1:nmembobs) {
            ## TODO: Enable all possible outputs, not only lonlat and areave when globalmean var?
            ## TODO: Explain what I did to Vir. Is it ok?
            if ((jobs == 1) && (sdate == sdates[1]) && (jmemb == 1)) {
              var_obs <- array(dim = c(nobs, nmemberobs, nsdates, nleadtime2))
            }
            mons <- strsplit(system(paste('cdo showmon ', filename, 
                             ' 2>/dev/null'), intern = TRUE), split = ' ')
            years <- strsplit(system(paste('cdo showyear ', filename, 
                              ' 2>/dev/null'), intern = TRUE), split = ' ')
            mons <- as.integer(mons[[1]][which(mons[[1]] != "")])
            years <- as.integer(years[[1]][which(years[[1]] != "")])
            lt_indices <- c(1:length(dim(tmp)[4]))
            lt_indices_ts <- ts(lt_indices, start = c(years[1], mons[1]), 
                             end = c(years[length(years)], mons[length(mons)]),
                             frequency = 12)
            lt_indices_ts_2 <- window(lt_indices_ts, start = c(as.integer(
                              substr(sdate, 1, 4)), as.integer(
                              substr(sdate, 5, 6))), end = c(3000, 12),
                             frequency = 12, extend = TRUE)
            if (is_atm_var) {
              ## Store values into observational matrix.
              var_obs[jobs, jmemb, jsdate, , , ] <- tmp[, , jmemb, lt_indices_ts_2[seq(leadtimemin, leadtimemax, sampleperiod)]]
            } else {
              ## Store values into observational matrix.
              var_obs[jobs, jmemb, jsdate, ] <- tmp[1, 1, jmemb, lt_indices_ts_2[seq(leadtimemin, leadtimemax, sampleperiod)]]
            }
          }
        } else {
          print(paste("Warning: Observation dataset file not found, filling with NA values instead:", filename))
        }
      }
      ## Loop on the next observational dataset.
      jobs <- jobs + 1
    } 
    ## Loop on the next starting date.
    jsdate <- jsdate + 1
  }
  ## Remove auxiliar files.
  system("rm -f tmp.nc")
  # Case exp == NULL
  if (is.null(lat_mod)) {
    lat_mod <- lat_obs
  }
  if (is.null(lon_mod)) {
    lon_mod <- lon_obs
  }
  #
  #  Outputs
  # ~~~~~~~~~
  #
  invisible(list(mod = var_exp, obs = var_obs, lat = lat_mod, lon = lon_mod))
}
