def main(options, main_comm, debugMsg, timer):
    """setup the environment for running the diagnostics in parallel. 

    Calls 2 different regridding types
    model1 only 
    model1 and model2

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages
    timer (object) - timer object for keeping times

    The env_diags_lnd.xml configuration file defines whether or not to regrid the climatology files. 
    See (website URL here...) for a complete desciption of the env_diags_lnd XML options.
    """

    # initialize the environment dictionary
    envDict = dict()
    regrid_list = list()
    climo_list = list()

    # set some variables for all tasks
    regrid_script = 'se2fv_esmf.regrid2file.ncl'
    m_dir = 'lnd'

    # CASEROOT is given on the command line as required option --caseroot
    caseroot = options.caseroot[0]
    debugMsg('caseroot = {0}'.format(caseroot), header=True, verbosity=1)

    debugMsg('calling initialize_main', header=True, verbosity=1)
    envDict = initialize_main(envDict, caseroot, debugMsg, options.standalone)

    if main_comm.is_manager():

        debugMsg('calling check_ncl_nco', header=True, verbosity=1)
        diagUtilsLib.check_ncl_nco(envDict)

        if not os.path.exists(envDict['WKDIR']):
            os.makedirs(envDict['WKDIR'])

        # build up the climo files to be regridded in parallel
        if (envDict['regrid_1'] == 'True'):
            # setup the working directory first before calling the base class prerequisites
            endYr = (int(envDict['clim_first_yr_1']) + int(envDict['clim_num_yrs_1'])) - 1
            subdir = '{0}.{1}-{2}'.format(envDict['caseid_1'], envDict['clim_first_yr_1'], endYr)
            workdir = '{0}/climo/{1}/{2}/{3}/'.format(envDict['PTMPDIR_1'], envDict['caseid_1'], subdir, m_dir)
            regrid_list = get_climo_files_to_regrid(workdir, envDict['lnd_modelstream_1'], '1', envDict, debugMsg)
            debugMsg('t = 1 regrid_list = {0}'.format(regrid_list), header=True, verbosity=1)

        if (envDict['MODEL_VS_MODEL'] == 'True' and envDict['regrid_2'] == 'True'):

            # setup the working directory first before calling the base class prerequisites
            endYr = (int(envDict['clim_first_yr_2']) + int(envDict['clim_num_yrs_2'])) - 1
            subdir = '{0}.{1}-{2}'.format(envDict['caseid_2'], envDict['clim_first_yr_2'], endYr)
            workdir = '{0}/climo/{1}/{2}/{3}/'.format(envDict['PTMPDIR_2'], envDict['caseid_2'], subdir, m_dir)
            regrid_list = regrid_list + get_climo_files_to_regrid(workdir, envDict['lnd_modelstream_2'], '2', envDict, debugMsg)
            debugMsg('t = 2 regrid_list = {0}'.format(regrid_list), header=True, verbosity=1)

    main_comm.sync()

    # broadcast envDict to all tasks
    envDict['NCLPATH'] = envDict['POSTPROCESS_PATH']+'/lnd_diag/shared/'   
    envDict = main_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)

    # broadcast the regrid_list to all tasks
    regrid_list = main_comm.partition(data=regrid_list, func=partition.Duplicate(), involved=True)
    main_comm.sync()

    # initialize some variables for distributing regridding across the communicators
    size = main_comm.get_size()
    rank = main_comm.get_rank()
    main_comm.sync()

    # ration files to be regridded
    if main_comm.is_manager():
        num_regrids = len(regrid_list)
        debugMsg('{0} num_regrids'.format(num_regrids), header=True, verbosity=1)

        for i in range(num_regrids):
            debugMsg('Sent out index {2!r}'.format(rank, size, i), header=True, verbosity=1)
            main_comm.ration(i)

        for i in range(size - 1):
            debugMsg('Sent None'.format(rank, size), header=True, verbosity=1)
            main_comm.ration(None)

    else:
        i = -1
        while i is not None:
            debugMsg('Recvd index {2!r}'.format(rank, size, i), header=True, verbosity=1)
            i = main_comm.ration()

            if i is not None:
                # extract the i'th list of the regrid_list
                climo_list = regrid_list[i]
                t = climo_list[0]
                ext_dir = climo_list[1]
                climo_file = climo_list[2]
        
                # setup the working directory first for each climo file
                endYr = (int(envDict['clim_first_yr_'+t]) + int(envDict['clim_num_yrs_'+t])) - 1
                subdir = '{0}.{1}-{2}'.format(envDict['caseid_'+t], envDict['clim_first_yr_'+t], endYr)
                workdir = '{0}/climo/{1}/{2}/{3}/'.format(envDict['PTMPDIR_'+t], envDict['caseid_'+t], subdir, m_dir)

                timer_tag = '{0}_{1}'.format(t, climo_file)
                timer.start(timer_tag)
                debugMsg('Before call to lnd_regrid using workdir = {0}/{1}'.format(workdir, ext_dir), header=True, verbosity=1)
                diagUtilsLib.lnd_regrid(climo_file, regrid_script, t, workdir, ext_dir, envDict)
                timer.stop(timer_tag)

                debugMsg("Total time to regrid file {0} = {1}".format(climo_file, timer.get_time(timer_tag)), header=True, verbosity=1)
def main(options, main_comm, debugMsg):
    """setup the environment for running the diagnostics in parallel. 

    Calls 2 different diagnostics generation types:
    model vs. observation 
    model vs. model 

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages

    The env_diags_atm.xml configuration file defines the way the diagnostics are generated. 
    See (website URL here...) for a complete desciption of the env_diags_atm XML options.
    """

    # initialize the environment dictionary
    envDict = dict()

    # CASEROOT is given on the command line as required option --caseroot
    if main_comm.is_manager():
        caseroot = options.caseroot[0]
        debugMsg('caseroot = {0}'.format(caseroot), header=True)

        debugMsg('calling initialize_main', header=True)
        envDict = initialize_main(envDict, caseroot, debugMsg, options.standalone)

        debugMsg('calling check_ncl_nco', header=True)
        diagUtilsLib.check_ncl_nco(envDict)

    # broadcast envDict to all tasks
    envDict = main_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)
    sys.path.append(envDict['PATH'])
    main_comm.sync()

    # check to see if the climos need to be regridded into a lat/lon grid
    if (envDict['test_regrid'] == 'True' or envDict['cntl_regrid'] == 'True'):
        if main_comm.is_manager():
            print('calling regrid_climos')
        regrid_climos(envDict, main_comm)
    main_comm.sync()

    # get list of diagnostics types to be created
    diag_list = list()
    diag_list = setup_diags(envDict)
    if  main_comm.is_manager():
        print('User requested diagnostics:')
        for diag in diag_list:
            print('  {0}'.format(diag))

    main_comm.sync()

    # broadcast the diag_list to all tasks
    num_of_diags = len(diag_list)
    num_of_diags = main_comm.partition(num_of_diags, func=partition.Duplicate(), involved=True)
    diag_list = main_comm.partition(data=diag_list, func=partition.Duplicate(), involved=True)
    main_comm.sync()

    # initialize some variables for distributing diagnostics across the communicators
    diags_send = diag_list
    gmaster = main_comm.is_manager()
    gsize = main_comm.get_size()
    grank = main_comm.get_rank()
    local_diag_list = list()

    # divide the main communicator into sub_communicators to be passed to each diag class
    # split mpi comm world if the size of the communicator > 1 and the num_of_diags > 1
    if gsize > 1 and num_of_diags > 1:
        temp_color = (grank % num_of_diags)
        if (temp_color == num_of_diags):
            temp_color = temp_color - 1
        groups = list()
        for g in range(0,num_of_diags):
            groups.append(g)
        debugMsg('global_rank {0}, temp_color {1}, #of groups(diag types) {2}, groups {3}, diag_list {4}'.format(grank, temp_color, num_of_diags, groups, diag_list))
        group = groups[temp_color]
        inter_comm, multi_comm = main_comm.divide(group)
        color = inter_comm.get_color()
        lsize = inter_comm.get_size()
        lrank = inter_comm.get_rank()
        lmaster = inter_comm.is_manager()
        debugMsg('color {0}, lsize {1}, lrank {2}, lmaster {3}'.format(color, lsize, lrank, lmaster))

        # partition the diag_list between communicators
        DIAG_LIST_TAG = 10
        if lmaster:
            local_diag_list = multi_comm.partition(diag_list,func=partition.EqualStride(),involved=True)
            for b in range(1, lsize):
                diags_send = inter_comm.ration(data=local_diag_list, tag=DIAG_LIST_TAG)
        else:
            local_diag_list = inter_comm.ration(tag=DIAG_LIST_TAG)
        debugMsg('local_diag_list {0}',format(local_diag_list))
    else:
        inter_comm = main_comm
        lmaster = main_comm.is_manager()
        lsize = main_comm.get_size()
        lrank = main_comm.get_rank()
        local_diag_list = diag_list

    inter_comm.sync()
    main_comm.sync()    
    
    debugMsg('lsize = {0}, lrank = {1}'.format(lsize, lrank))
    inter_comm.sync()

    # loop through the local_diag_list list
    for requested_diag in local_diag_list:
        try:
            diag = atm_diags_factory.atmosphereDiagnosticsFactory(requested_diag,envDict)

            # check the prerequisites for the diagnostics types
            debugMsg('Checking prerequisites for {0}'.format(diag.__class__.__name__), header=True)
            envDict = diag.check_prerequisites(envDict, inter_comm)
            inter_comm.sync()
            debugMsg('inter_comm = {0}'.format(inter_comm))
            diag.run_diagnostics(envDict, inter_comm)
            
        except atm_diags_bc.RecoverableError as e:
            # catch all recoverable errors, print a message and continue.
            print(e)
            print("Skipped '{0}' and continuing!".format(request_diag))
        except RuntimeError as e:
            # unrecoverable error, bail!
            print(e)
            return 1

    main_comm.sync()
def main(options, main_comm, debugMsg):
    """setup the environment for running the diagnostics in parallel. 

    Calls 6 different diagnostics generation types:
    model vs. observation (optional BGC - ecosystem)
    model vs. control (optional BGC - ecosystem)
    model time-series (optional BGC - ecosystem)

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages

    The env_diags_ocn.xml configuration file defines the way the diagnostics are generated. 
    See (website URL here...) for a complete desciption of the env_diags_ocn XML options.
    """

    # initialize the environment dictionary
    envDict = dict()

    # CASEROOT is given on the command line as required option --caseroot
    if main_comm.is_manager():
        caseroot = options.caseroot[0]
        debugMsg('caseroot = {0}'.format(caseroot), header=True, verbosity=2)

        debugMsg('calling initialize_main', header=True, verbosity=2)
        envDict = initialize_main(envDict, caseroot, debugMsg, options.standalone)

        debugMsg('calling check_ncl_nco', header=True, verbosity=2)
        diagUtilsLib.check_ncl_nco(envDict)

    # broadcast envDict to all tasks
    envDict = main_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)
    sys.path.append(envDict['PATH'])
    main_comm.sync()

    # get list of diagnostics types to be created
    diag_list = list()
    num_of_diags = 0

    if main_comm.is_manager():
        diag_list, diag_dict = setup_diags(envDict)

        num_of_diags = len(diag_list)
        if num_of_diags == 0:
            print('No ocean diagnostics specified. Please check the {0}/env_diags_ocn.xml settings.'.format(envDict['PP_CASE_PATH']))
            sys.exit(1)

        print('User requested diagnostics:')
        for diag in diag_list:
            print('  {0}'.format(diag))

        try:
            os.makedirs(envDict['WORKDIR'])
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                err_msg = 'ERROR: ocn_diags_generator.py problem accessing the working directory {0}'.format(envDict['WORKDIR'])
                raise OSError(err_msg)

        debugMsg('Ocean diagnostics - Creating main index.html page', header=True, verbosity=2)

        # define the templatePath
        templatePath = '{0}/diagnostics/diagnostics/ocn/Templates'.format(envDict['POSTPROCESS_PATH']) 

        templateLoader = jinja2.FileSystemLoader( searchpath=templatePath )
        templateEnv = jinja2.Environment( loader=templateLoader )
            
        template_file = 'ocean_diagnostics.tmpl'
        template = templateEnv.get_template( template_file )
            
        # get the current datatime string for the template
        now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        # set the template variables
        templateVars = { 'casename' : envDict['CASE'],
                         'tagname' : envDict['CESM_TAG'],
                         'diag_dict' : diag_dict,
                         'control_casename' : envDict['CNTRLCASE'],
                         'start_year' : envDict['YEAR0'],
                         'stop_year' : envDict['YEAR1'],
                         'control_start_year' : envDict['CNTRLYEAR0'],
                         'control_stop_year' : envDict['CNTRLYEAR1'],
                         'today': now,
                         'tseries_start_year' : envDict['TSERIES_YEAR0'],
                         'tseries_stop_year' : envDict['TSERIES_YEAR1']
                         }

        # write the main index.html page to the top working directory
        main_html = template.render( templateVars )
        with open( '{0}/index.html'.format(envDict['WORKDIR']), 'w') as index:
            index.write(main_html)

        debugMsg('Ocean diagnostics - Copying stylesheet', header=True, verbosity=2)
        shutil.copy2('{0}/Templates/diag_style.css'.format(envDict['POSTPROCESS_PATH']), '{0}/diag_style.css'.format(envDict['WORKDIR']))

        debugMsg('Ocean diagnostics - Copying logo files', header=True, verbosity=2)
        if not os.path.exists('{0}/logos'.format(envDict['WORKDIR'])):
            os.mkdir('{0}/logos'.format(envDict['WORKDIR']))

        for filename in glob.glob(os.path.join('{0}/Templates/logos'.format(envDict['POSTPROCESS_PATH']), '*.*')):
            shutil.copy(filename, '{0}/logos'.format(envDict['WORKDIR']))
 
        # setup the unique OCNDIAG_WEBDIR output file
        env_file = '{0}/env_diags_ocn.xml'.format(envDict['PP_CASE_PATH'])
        key = 'OCNDIAG_WEBDIR'
        value = envDict['WORKDIR']
        ##web_file = '{0}/web_dirs/{1}.{2}-{3}'.format(envDict['PP_CASE_PATH'], key, main_comm.get_size(), main_comm.get_rank() )
        web_file = '{0}/web_dirs/{1}.{2}'.format(envDict['PP_CASE_PATH'], key, datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S'))
        try:
            diagUtilsLib.write_web_file(web_file, 'ocn', key, value)
        except:
            print('WARNING ocn_diags_generator unable to write {0}={1} to {2}'.format(key, value, web_file))

    main_comm.sync()

    # broadcast the diag_list to all tasks
    num_of_diags = main_comm.partition(num_of_diags, func=partition.Duplicate(), involved=True)
    diag_list = main_comm.partition(data=diag_list, func=partition.Duplicate(), involved=True)
    main_comm.sync()

    # initialize some variables for distributing diagnostics across the communicators
    diags_send = diag_list
    gmaster = main_comm.is_manager()
    gsize = main_comm.get_size()
    grank = main_comm.get_rank()
    local_diag_list = list()

    # divide the main communicator into sub_communicators to be passed to each diag class
    # split mpi comm world if the size of the communicator > 1 and the num_of_diags > 1
    if gsize > 1 and num_of_diags > 1:
        temp_color = (grank % num_of_diags)
        if (temp_color == num_of_diags):
            temp_color = temp_color - 1
        groups = list()
        for g in range(0,num_of_diags):
            groups.append(g)
        debugMsg('global_rank {0}, temp_color {1}, #of groups(diag types) {2}, groups {3}, diag_list {4}'.format(grank, temp_color, num_of_diags, groups, diag_list), header=True, verbosity=2)
        group = groups[temp_color]
        inter_comm, multi_comm = main_comm.divide(group)
        color = inter_comm.get_color()
        lsize = inter_comm.get_size()
        lrank = inter_comm.get_rank()
        lmaster = inter_comm.is_manager()
        debugMsg('color {0}, lsize {1}, lrank {2}, lmaster {3}'.format(color, lsize, lrank, lmaster), header=True, verbosity=2)

        # partition the diag_list between communicators
        DIAG_LIST_TAG = 10
        if lmaster:
            local_diag_list = multi_comm.partition(diag_list,func=partition.EqualStride(),involved=True)
            debugMsg('lrank = {0} local_diag_list = {1}'.format(lrank, local_diag_list), header=True, verbosity=2)
            for b in range(1, lsize):
                diags_send = inter_comm.ration(data=local_diag_list, tag=DIAG_LIST_TAG) 
                debugMsg('b = {0} diags_send = {1} lsize = {2}'.format(b, diags_send, lsize), header=True, verbosity=2)
        else:
            local_diag_list = inter_comm.ration(tag=DIAG_LIST_TAG)
        debugMsg('local_diag_list {0}',format(local_diag_list), header=True, verbosity=2)
    else:
        inter_comm = main_comm
        lmaster = main_comm.is_manager()
        lsize = main_comm.get_size()
        lrank = main_comm.get_rank()
        local_diag_list = diag_list

    inter_comm.sync()
    main_comm.sync()

    # loop through the local_diag_list 
    for requested_diag in local_diag_list:
        try:
            debugMsg('requested_diag {0}, lrank {1}, lsize {2}, lmaster {3}'.format(requested_diag, lrank, lsize, lmaster), header=True, verbosity=2)
            diag = ocn_diags_factory.oceanDiagnosticsFactory(requested_diag)

            # check the prerequisites for the diagnostics types
            debugMsg('Checking prerequisites for {0}'.format(diag.__class__.__name__), header=True, verbosity=2)
            
            skip_key = '{0}_SKIP'.format(requested_diag)
            if lmaster:
                try:
                    envDict = diag.check_prerequisites(envDict)
                except ocn_diags_bc.PrerequisitesError:
                    print("Problem with check_prerequisites for '{0}' skipping!".format(requested_diag))
                    envDict[skip_key] = True
                except RuntimeError as e:
                    # unrecoverable error, bail!
                    print(e)
                    envDict['unrecoverableErrorOnMaster'] = True

            inter_comm.sync()

            # broadcast the envDict
            envDict = inter_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)

            if envDict.has_key('unrecoverableErrorOnMaster'):
                raise RuntimeError

            # run the diagnostics type on each inter_comm
            if not envDict.has_key(skip_key):
                # set the shell env using the values set in the XML and read into the envDict across all tasks
                cesmEnvLib.setXmlEnv(envDict)
                # run the diagnostics
                envDict = diag.run_diagnostics(envDict, inter_comm)

            inter_comm.sync()
            
        except ocn_diags_bc.RecoverableError as e:
            # catch all recoverable errors, print a message and continue.
            print(e)
            print("Skipped '{0}' and continuing!".format(requested_diag))
        except RuntimeError as e:
            # unrecoverable error, bail!
            print(e)
            return 1

    main_comm.sync()
Esempio n. 4
0
def main(options, main_comm, debugMsg):
    """setup the environment for running the diagnostics in parallel. 

    Calls 2 different diagnostics generation types:
    model vs. observation 
    model vs. model 

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages

    The env_diags_atm.xml configuration file defines the way the diagnostics are generated. 
    See (website URL here...) for a complete desciption of the env_diags_atm XML options.
    """

    # initialize the environment dictionary
    envDict = dict()

    # CASEROOT is given on the command line as required option --caseroot
    if main_comm.is_manager():
        caseroot = options.caseroot[0]
        debugMsg('caseroot = {0}'.format(caseroot), header=True)

        debugMsg('calling initialize_main', header=True)
        envDict = initialize_main(envDict, caseroot, debugMsg,
                                  options.standalone)

        debugMsg('calling check_ncl_nco', header=True)
        diagUtilsLib.check_ncl_nco(envDict)

    # broadcast envDict to all tasks
    envDict = main_comm.partition(data=envDict,
                                  func=partition.Duplicate(),
                                  involved=True)
    sys.path.append(envDict['PATH'])
    main_comm.sync()

    # check to see if the climos need to be regridded into a lat/lon grid
    if (envDict['test_regrid'] == 'True' or envDict['cntl_regrid'] == 'True'):
        regrid_climos(envDict, main_comm)
    main_comm.sync()

    # get list of diagnostics types to be created
    diag_list = list()
    diag_list = setup_diags(envDict)
    if main_comm.is_manager():
        print('User requested diagnostics:')
        for diag in diag_list:
            print('  {0}'.format(diag))

    main_comm.sync()

    # broadcast the diag_list to all tasks
    num_of_diags = len(diag_list)
    num_of_diags = main_comm.partition(num_of_diags,
                                       func=partition.Duplicate(),
                                       involved=True)
    diag_list = main_comm.partition(data=diag_list,
                                    func=partition.Duplicate(),
                                    involved=True)
    main_comm.sync()

    # initialize some variables for distributing diagnostics across the communicators
    diags_send = diag_list
    gmaster = main_comm.is_manager()
    gsize = main_comm.get_size()
    grank = main_comm.get_rank()
    local_diag_list = list()

    # divide the main communicator into sub_communicators to be passed to each diag class
    # split mpi comm world if the size of the communicator > 1 and the num_of_diags > 1
    if gsize > 1 and num_of_diags > 1:
        temp_color = (grank % num_of_diags)
        if (temp_color == num_of_diags):
            temp_color = temp_color - 1
        groups = list()
        for g in range(0, num_of_diags):
            groups.append(g)
        debugMsg(
            'global_rank {0}, temp_color {1}, #of groups(diag types) {2}, groups {3}, diag_list {4}'
            .format(grank, temp_color, num_of_diags, groups, diag_list))
        group = groups[temp_color]
        inter_comm, multi_comm = main_comm.divide(group)
        color = inter_comm.get_color()
        lsize = inter_comm.get_size()
        lrank = inter_comm.get_rank()
        lmaster = inter_comm.is_manager()
        debugMsg('color {0}, lsize {1}, lrank {2}, lmaster {3}'.format(
            color, lsize, lrank, lmaster))

        # partition the diag_list between communicators
        DIAG_LIST_TAG = 10
        if lmaster:
            local_diag_list = multi_comm.partition(
                diag_list, func=partition.EqualStride(), involved=True)
            for b in range(1, lsize):
                diags_send = inter_comm.ration(data=local_diag_list,
                                               tag=DIAG_LIST_TAG)
        else:
            local_diag_list = inter_comm.ration(tag=DIAG_LIST_TAG)
        debugMsg('local_diag_list {0}', format(local_diag_list))
    else:
        inter_comm = main_comm
        lmaster = main_comm.is_manager()
        lsize = main_comm.get_size()
        lrank = main_comm.get_rank()
        local_diag_list = diag_list

    inter_comm.sync()
    main_comm.sync()

    debugMsg('lsize = {0}, lrank = {1}'.format(lsize, lrank))
    inter_comm.sync()

    # loop through the local_diag_list list
    for requested_diag in local_diag_list:
        try:
            diag = atm_diags_factory.atmosphereDiagnosticsFactory(
                requested_diag, envDict)

            # check the prerequisites for the diagnostics types
            debugMsg('Checking prerequisites for {0}'.format(
                diag.__class__.__name__),
                     header=True)

            #if lmaster:
            envDict = diag.check_prerequisites(envDict, inter_comm)

            inter_comm.sync()

            ## broadcast the envDict
            #envDict = inter_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)

            # set the shell env using the values set in the XML and read into the envDict across all tasks
            #cesmEnvLib.setXmlEnv(envDict)

            debugMsg('inter_comm = {0}'.format(inter_comm))
            diag.run_diagnostics(envDict, inter_comm)

        except atm_diags_bc.RecoverableError as e:
            # catch all recoverable errors, print a message and continue.
            print(e)
            print("Skipped '{0}' and continuing!".format(request_diag))
        except RuntimeError as e:
            # unrecoverable error, bail!
            print(e)
            return 1

    main_comm.sync()
def main(options, main_comm, debugMsg, timer):
    """setup the environment for running the diagnostics in parallel. 

    Calls 2 different regridding types
    model1 only 
    model1 and model2

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages
    timer (object) - timer object for keeping times

    The env_diags_lnd.xml configuration file defines whether or not to regrid the climatology files. 
    See (website URL here...) for a complete desciption of the env_diags_lnd XML options.
    """

    # initialize the environment dictionary
    envDict = dict()
    regrid_list = list()
    climo_list = list()

    # set some variables for all tasks
    regrid_script = 'se2fv_esmf.regrid2file.ncl'
    m_dir = 'lnd'

    # CASEROOT is given on the command line as required option --caseroot
    caseroot = options.caseroot[0]
    debugMsg('caseroot = {0}'.format(caseroot), header=True, verbosity=1)

    debugMsg('calling initialize_main', header=True, verbosity=1)
    envDict = initialize_main(envDict, caseroot, debugMsg, options.standalone)

    if main_comm.is_manager():

        debugMsg('calling check_ncl_nco', header=True, verbosity=1)
        diagUtilsLib.check_ncl_nco(envDict)

        if not os.path.exists(envDict['WKDIR']):
            os.makedirs(envDict['WKDIR'])

        # build up the climo files to be regridded in parallel
        if (envDict['regrid_1'] == 'True'):
            # setup the working directory first before calling the base class prerequisites
            endYr = (int(envDict['clim_first_yr_1']) +
                     int(envDict['clim_num_yrs_1'])) - 1
            subdir = '{0}.{1}-{2}'.format(envDict['caseid_1'],
                                          envDict['clim_first_yr_1'], endYr)
            workdir = '{0}/climo/{1}/{2}/{3}/'.format(envDict['PTMPDIR_1'],
                                                      envDict['caseid_1'],
                                                      subdir, m_dir)
            regrid_list = get_climo_files_to_regrid(
                workdir, envDict['lnd_modelstream_1'], '1', envDict, debugMsg)
            debugMsg('t = 1 regrid_list = {0}'.format(regrid_list),
                     header=True,
                     verbosity=1)

        if (envDict['MODEL_VS_MODEL'] == 'True'
                and envDict['regrid_2'] == 'True'):

            # setup the working directory first before calling the base class prerequisites
            endYr = (int(envDict['clim_first_yr_2']) +
                     int(envDict['clim_num_yrs_2'])) - 1
            subdir = '{0}.{1}-{2}'.format(envDict['caseid_2'],
                                          envDict['clim_first_yr_2'], endYr)
            workdir = '{0}/climo/{1}/{2}/{3}/'.format(envDict['PTMPDIR_2'],
                                                      envDict['caseid_2'],
                                                      subdir, m_dir)
            regrid_list = regrid_list + get_climo_files_to_regrid(
                workdir, envDict['lnd_modelstream_2'], '2', envDict, debugMsg)
            debugMsg('t = 2 regrid_list = {0}'.format(regrid_list),
                     header=True,
                     verbosity=1)

    main_comm.sync()

    # broadcast envDict to all tasks
    envDict['NCLPATH'] = envDict['POSTPROCESS_PATH'] + '/lnd_diag/shared/'
    envDict = main_comm.partition(data=envDict,
                                  func=partition.Duplicate(),
                                  involved=True)

    # broadcast the regrid_list to all tasks
    regrid_list = main_comm.partition(data=regrid_list,
                                      func=partition.Duplicate(),
                                      involved=True)
    main_comm.sync()

    # initialize some variables for distributing regridding across the communicators
    size = main_comm.get_size()
    rank = main_comm.get_rank()
    main_comm.sync()

    # ration files to be regridded
    if main_comm.is_manager():
        num_regrids = len(regrid_list)
        debugMsg('{0} num_regrids'.format(num_regrids),
                 header=True,
                 verbosity=1)

        for i in range(num_regrids):
            debugMsg('Sent out index {2!r}'.format(rank, size, i),
                     header=True,
                     verbosity=1)
            main_comm.ration(i)

        for i in range(size - 1):
            debugMsg('Sent None'.format(rank, size), header=True, verbosity=1)
            main_comm.ration(None)

    else:
        i = -1
        while i is not None:
            debugMsg('Recvd index {2!r}'.format(rank, size, i),
                     header=True,
                     verbosity=1)
            i = main_comm.ration()

            if i is not None:
                # extract the i'th list of the regrid_list
                climo_list = regrid_list[i]
                t = climo_list[0]
                ext_dir = climo_list[1]
                climo_file = climo_list[2]

                # setup the working directory first for each climo file
                endYr = (int(envDict['clim_first_yr_' + t]) +
                         int(envDict['clim_num_yrs_' + t])) - 1
                subdir = '{0}.{1}-{2}'.format(envDict['caseid_' + t],
                                              envDict['clim_first_yr_' + t],
                                              endYr)
                workdir = '{0}/climo/{1}/{2}/{3}/'.format(
                    envDict['PTMPDIR_' + t], envDict['caseid_' + t], subdir,
                    m_dir)

                timer_tag = '{0}_{1}'.format(t, climo_file)
                timer.start(timer_tag)
                debugMsg(
                    'Before call to lnd_regrid using workdir = {0}/{1}'.format(
                        workdir, ext_dir),
                    header=True,
                    verbosity=1)
                diagUtilsLib.lnd_regrid(climo_file, regrid_script, t, workdir,
                                        ext_dir, envDict)
                timer.stop(timer_tag)

                debugMsg("Total time to regrid file {0} = {1}".format(
                    climo_file, timer.get_time(timer_tag)),
                         header=True,
                         verbosity=1)
def main(options, main_comm, debugMsg):
    """setup the environment for running the diagnostics in parallel. 

    Calls 6 different diagnostics generation types:
    model vs. observation (optional BGC - ecosystem)
    model vs. control (optional BGC - ecosystem)
    model time-series (optional BGC - ecosystem)

    Arguments:
    options (object) - command line options
    main_comm (object) - MPI simple communicator object
    debugMsg (object) - vprinter object for printing debugging messages

    The env_diags_ocn.xml configuration file defines the way the diagnostics are generated. 
    See (website URL here...) for a complete desciption of the env_diags_ocn XML options.
    """

    # initialize the environment dictionary
    envDict = dict()

    # CASEROOT is given on the command line as required option --caseroot
    if main_comm.is_manager():
        caseroot = options.caseroot[0]
        debugMsg('caseroot = {0}'.format(caseroot), header=True, verbosity=2)

        debugMsg('calling initialize_main', header=True, verbosity=2)
        envDict = initialize_main(envDict, caseroot, debugMsg, options.standalone)

        debugMsg('calling check_ncl_nco', header=True, verbosity=2)
        diagUtilsLib.check_ncl_nco(envDict)

    # broadcast envDict to all tasks
    envDict = main_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)
    sys.path.append(envDict['PATH'])
    main_comm.sync()

    # get list of diagnostics types to be created
    diag_list = list()
    num_of_diags = 0

    if main_comm.is_manager():
        diag_list, diag_dict = setup_diags(envDict)

        num_of_diags = len(diag_list)
        if num_of_diags == 0:
            print('No ocean diagnostics specified. Please check the {0}/env_diags_ocn.xml settings.'.format(envDict['PP_CASE_PATH']))
            sys.exit(1)

        print('User requested diagnostics:')
        for diag in diag_list:
            print('  {0}'.format(diag))

        try:
            os.makedirs(envDict['WORKDIR'])
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                err_msg = 'ERROR: ocn_diags_generator.py problem accessing the working directory {0}'.format(envDict['WORKDIR'])
                raise OSError(err_msg)

        debugMsg('Ocean diagnostics - Creating main index.html page', header=True, verbosity=2)

        # define the templatePath
        templatePath = '{0}/diagnostics/diagnostics/ocn/Templates'.format(envDict['POSTPROCESS_PATH']) 

        templateLoader = jinja2.FileSystemLoader( searchpath=templatePath )
        templateEnv = jinja2.Environment( loader=templateLoader )
            
        template_file = 'ocean_diagnostics.tmpl'
        template = templateEnv.get_template( template_file )
            
        # get the current datatime string for the template
        now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

        # set the template variables
        templateVars = { 'casename' : envDict['CASE'],
                         'tagname' : envDict['CESM_TAG'],
                         'username' : envDict['USER_NAME'],
                         'diag_dict' : diag_dict,
                         'control_casename' : envDict['CNTRLCASE'],
                         'start_year' : envDict['YEAR0'],
                         'stop_year' : envDict['YEAR1'],
                         'control_start_year' : envDict['CNTRLYEAR0'],
                         'control_stop_year' : envDict['CNTRLYEAR1'],
                         'today': now,
                         'tseries_start_year' : envDict['TSERIES_YEAR0'],
                         'tseries_stop_year' : envDict['TSERIES_YEAR1']
                         }

        # write the main index.html page to the top working directory
        main_html = template.render( templateVars )
        with open( '{0}/index.html'.format(envDict['WORKDIR']), 'w') as index:
            index.write(main_html)

        debugMsg('Ocean diagnostics - Copying stylesheet', header=True, verbosity=2)
        shutil.copy2('{0}/Templates/diag_style.css'.format(envDict['POSTPROCESS_PATH']), '{0}/diag_style.css'.format(envDict['WORKDIR']))

        debugMsg('Ocean diagnostics - Copying logo files', header=True, verbosity=2)
        if not os.path.exists('{0}/logos'.format(envDict['WORKDIR'])):
            os.mkdir('{0}/logos'.format(envDict['WORKDIR']))

        for filename in glob.glob(os.path.join('{0}/Templates/logos'.format(envDict['POSTPROCESS_PATH']), '*.*')):
            shutil.copy(filename, '{0}/logos'.format(envDict['WORKDIR']))
 
        # setup the unique OCNDIAG_WEBDIR output file
        env_file = '{0}/env_diags_ocn.xml'.format(envDict['PP_CASE_PATH'])
        key = 'OCNDIAG_WEBDIR'
        value = envDict['WORKDIR']
        ##web_file = '{0}/web_dirs/{1}.{2}-{3}'.format(envDict['PP_CASE_PATH'], key, main_comm.get_size(), main_comm.get_rank() )
        web_file = '{0}/web_dirs/{1}.{2}'.format(envDict['PP_CASE_PATH'], key, datetime.datetime.now().strftime('%Y-%m-%d_%H%M%S'))
        try:
            diagUtilsLib.write_web_file(web_file, 'ocn', key, value)
        except:
            print('WARNING ocn_diags_generator unable to write {0}={1} to {2}'.format(key, value, web_file))

    main_comm.sync()

    # broadcast the diag_list to all tasks
    num_of_diags = main_comm.partition(num_of_diags, func=partition.Duplicate(), involved=True)
    diag_list = main_comm.partition(data=diag_list, func=partition.Duplicate(), involved=True)
    main_comm.sync()

    # initialize some variables for distributing diagnostics across the communicators
    diags_send = diag_list
    gmaster = main_comm.is_manager()
    gsize = main_comm.get_size()
    grank = main_comm.get_rank()
    local_diag_list = list()

    # divide the main communicator into sub_communicators to be passed to each diag class
    # split mpi comm world if the size of the communicator > 1 and the num_of_diags > 1
    if gsize > 1 and num_of_diags > 1:
        temp_color = (grank % num_of_diags)
        if (temp_color == num_of_diags):
            temp_color = temp_color - 1
        groups = list()
        for g in range(0,num_of_diags):
            groups.append(g)
        debugMsg('global_rank {0}, temp_color {1}, #of groups(diag types) {2}, groups {3}, diag_list {4}'.format(grank, temp_color, num_of_diags, groups, diag_list), header=True, verbosity=2)
        group = groups[temp_color]
        inter_comm, multi_comm = main_comm.divide(group)
        color = inter_comm.get_color()
        lsize = inter_comm.get_size()
        lrank = inter_comm.get_rank()
        lmaster = inter_comm.is_manager()
        debugMsg('color {0}, lsize {1}, lrank {2}, lmaster {3}'.format(color, lsize, lrank, lmaster), header=True, verbosity=2)

        # partition the diag_list between communicators
        DIAG_LIST_TAG = 10
        if lmaster:
            local_diag_list = multi_comm.partition(diag_list,func=partition.EqualStride(),involved=True)
            debugMsg('lrank = {0} local_diag_list = {1}'.format(lrank, local_diag_list), header=True, verbosity=2)
            for b in range(1, lsize):
                diags_send = inter_comm.ration(data=local_diag_list, tag=DIAG_LIST_TAG) 
                debugMsg('b = {0} diags_send = {1} lsize = {2}'.format(b, diags_send, lsize), header=True, verbosity=2)
        else:
            local_diag_list = inter_comm.ration(tag=DIAG_LIST_TAG)
        debugMsg('local_diag_list {0}',format(local_diag_list), header=True, verbosity=2)
    else:
        inter_comm = main_comm
        lmaster = main_comm.is_manager()
        lsize = main_comm.get_size()
        lrank = main_comm.get_rank()
        local_diag_list = diag_list

    inter_comm.sync()
    main_comm.sync()

    # loop through the local_diag_list 
    for requested_diag in local_diag_list:
        try:
            debugMsg('requested_diag {0}, lrank {1}, lsize {2}, lmaster {3}'.format(requested_diag, lrank, lsize, lmaster), header=True, verbosity=2)
            diag = ocn_diags_factory.oceanDiagnosticsFactory(requested_diag)

            # check the prerequisites for the diagnostics types
            debugMsg('Checking prerequisites for {0}'.format(diag.__class__.__name__), header=True, verbosity=2)
            
            skip_key = '{0}_SKIP'.format(requested_diag)
            if lmaster:
                try:
                    envDict = diag.check_prerequisites(envDict)
                except ocn_diags_bc.PrerequisitesError:
                    print("Problem with check_prerequisites for '{0}' skipping!".format(requested_diag))
                    envDict[skip_key] = True
                except RuntimeError as e:
                    # unrecoverable error, bail!
                    print(e)
                    envDict['unrecoverableErrorOnMaster'] = True

            inter_comm.sync()

            # broadcast the envDict
            envDict = inter_comm.partition(data=envDict, func=partition.Duplicate(), involved=True)

            if envDict.has_key('unrecoverableErrorOnMaster'):
                raise RuntimeError

            # run the diagnostics type on each inter_comm
            if not envDict.has_key(skip_key):
                # set the shell env using the values set in the XML and read into the envDict across all tasks
                cesmEnvLib.setXmlEnv(envDict)
                # run the diagnostics
                envDict = diag.run_diagnostics(envDict, inter_comm)

            inter_comm.sync()
            
        except ocn_diags_bc.RecoverableError as e:
            # catch all recoverable errors, print a message and continue.
            print(e)
            print("Skipped '{0}' and continuing!".format(requested_diag))
        except RuntimeError as e:
            # unrecoverable error, bail!
            print(e)
            return 1

    main_comm.sync()