Exemple #1
0
def generate_typedefs_makefile(metadata_define, typedefs_makefile,
                               typedefs_cmakefile, typedefs_sourcefile):
    """Generate list of Fortran modules containing CCPP type/kind definitions,
       and create makefile/cmakefile snippets for host model build system"""
    logging.info(
        'Generating list of Fortran modules containing CCPP type definitions ...'
    )
    success = True
    #
    typedefs = []
    # (1) Search for type definitions in the metadata, defined by:
    #    (a) the type not being a standard type, and
    #    (b) the type not being the CCPP framework internal type
    #    (c) the standard_name being identical to the type name
    # (2) Search for kind definitions in the metadata, defined by:
    #    (a) the standard_name starting with "kind_"
    #    (b) the type being integer and the units being none
    for key in metadata_define.keys():
        # derived data types
        if not metadata_define[key][0].type in STANDARD_VARIABLE_TYPES and \
                not metadata_define[key][0].type == CCPP_TYPE and \
                metadata_define[key][0].type == metadata_define[key][0].standard_name:
            container = decode_container_as_dict(
                metadata_define[key][0].container)
            if not 'MODULE' in container.keys():
                logging.error("Invalid type definition for type {}: {}".format(
                    metadata_define[key][0].type,
                    metadata_define[key][0].print_debug()))
                success = False
                continue
            # Fortran modules are lowercase and have the ending ".mod"
            typedef_fortran_module = "{}.mod".format(
                container['MODULE']).lower()
            if not typedef_fortran_module in typedefs:
                typedefs.append(typedef_fortran_module)
        # kind definitions
        elif metadata_define[key][0].standard_name.startswith("kind_") and \
                metadata_define[key][0].type == STANDARD_INTEGER_TYPE and \
                metadata_define[key][0].units == 'none':
            container = decode_container_as_dict(
                metadata_define[key][0].container)
            if not 'MODULE' in container.keys():
                logging.error("Invalid kind definition for kind {}: {}".format(
                    metadata_define[key][0].type,
                    metadata_define[key][0].print_debug()))
                success = False
                continue
            # Fortran modules are lowercase and have the ending ".mod"
            typedef_fortran_module = "{}.mod".format(
                container['MODULE']).lower()
            if not typedef_fortran_module in typedefs:
                typedefs.append(typedef_fortran_module)

    logging.info('Generating typedefs makefile/cmakefile snippet ...')
    # Write the Fortran modules without path - the build system knows where they are
    makefile = TypedefsMakefile()
    makefile.filename = typedefs_makefile + '.tmp'
    cmakefile = TypedefsCMakefile()
    cmakefile.filename = typedefs_cmakefile + '.tmp'
    sourcefile = TypedefsSourcefile()
    sourcefile.filename = typedefs_sourcefile + '.tmp'
    # Sort typedefs so that the order remains the same (for cmake to avoid) recompiling
    typedefs.sort()
    # Generate list of type definitions
    makefile.write(typedefs)
    cmakefile.write(typedefs)
    sourcefile.write(typedefs)
    if os.path.isfile(typedefs_makefile) and \
            filecmp.cmp(typedefs_makefile, makefile.filename):
        os.remove(makefile.filename)
        os.remove(cmakefile.filename)
        os.remove(sourcefile.filename)
    else:
        if os.path.isfile(typedefs_makefile):
            os.remove(typedefs_makefile)
        if os.path.isfile(typedefs_cmakefile):
            os.remove(typedefs_cmakefile)
        if os.path.isfile(typedefs_sourcefile):
            os.remove(typedefs_sourcefile)
        os.rename(makefile.filename, typedefs_makefile)
        os.rename(cmakefile.filename, typedefs_cmakefile)
        os.rename(sourcefile.filename, typedefs_sourcefile)
    #
    logging.info('Added {0} typedefs to {1}, {2}, {3}'.format(
        len(typedefs), typedefs_makefile, typedefs_cmakefile,
        typedefs_sourcefile))
    return success
Exemple #2
0
def convert_local_name_from_new_metadata(metadata, standard_name,
                                         typedefs_new_metadata,
                                         converted_variables):
    """Convert local names in new metadata format (no old-style DDT references, array references as
    standard names) to old metadata format (with old-style DDT references, array references as local names)."""
    success = True
    var = metadata[standard_name][0]
    # Check if this variable has already been converted
    if standard_name in converted_variables:
        logging.debug(
            'Variable {0} was in old metadata format and has already been converted'
            .format(standard_name))
        return (success, var.local_name, converted_variables)
    # Decode container into a dictionary
    container = decode_container_as_dict(var.container)
    # Check if variable is in old or new metadata format
    module_name = container['MODULE']
    if not module_name in typedefs_new_metadata.keys():
        logging.debug(
            'Variable {0} is in old metadata format, no conversion necessary'.
            format(standard_name))
        return (success, var.local_name, converted_variables)
    # For module variables set type_name to module_name
    if not 'TYPE' in container.keys():
        type_name = module_name
    else:
        type_name = container['TYPE']
    # Check that this module/type is configured (modules will have empty prefices)
    if not type_name in typedefs_new_metadata[module_name].keys():
        logging.error(
            "Module {0} uses the new metadata format, but module/type {1} is not configured"
            .format(module_name, type_name))
        success = False
        return (success, None, converted_variables)

    # The local name (incl. the array reference) is in new metadata format
    local_name = var.local_name
    logging.info(
        "Converting local name {0} of variable {1} from new to old metadata".
        format(local_name, standard_name))
    if "(" in local_name:
        (actual_var_name,
         array_reference) = split_var_name_and_array_reference(local_name)
        indices = array_reference.lstrip('(').rstrip(')').split(',')
        indices_local_names = []
        for index_range in indices:
            # Leave colons-only dimension alone
            if index_range == ':':
                indices_local_names.append(index_range)
                continue
            # Split by colons to get a pair of dimensions
            dimensions = index_range.split(':')
            dimensions_local_names = []
            for dimension in dimensions:
                # Leave literals alone
                try:
                    int(dimension)
                    dimensions_local_names.append(dimension)
                    continue
                except ValueError:
                    pass
                # Convert the local name of the dimension to old metadata standard, if necessary (recursive call)
                (success, local_name_dim,
                 converted_variables) = convert_local_name_from_new_metadata(
                     metadata, dimension, typedefs_new_metadata,
                     converted_variables)
                if not success:
                    return (success, None, converted_variables)
                # Update the local name of the dimension, if necessary
                if not metadata[dimension][0].local_name == local_name_dim:
                    logging.debug(
                        "Updating local name of variable {0} from {1} to {2}".
                        format(dimension, metadata[dimension][0].local_name,
                               local_name_dim))
                    metadata[dimension][0].local_name = local_name_dim
                dimensions_local_names.append(local_name_dim)
            indices_local_names.append(':'.join(dimensions_local_names))
        # Put back together the array reference with local names in old metadata format
        array_reference_local_names = '(' + ','.join(indices_local_names) + ')'
        # Compose local name (still without any DDT reference prefix)
        local_name = actual_var_name + array_reference_local_names

    # Prefix the local name with the reference if not empty
    if typedefs_new_metadata[module_name][type_name]:
        local_name = typedefs_new_metadata[module_name][
            type_name] + '%' + local_name
    if success:
        converted_variables.append(standard_name)

    return (success, local_name, converted_variables)