Example #1
0
    def writeGrid(self, baseName=None):
        """
        Write the grids of each instance

        Parameters
        ----------
        baseName : str or None
            a base namve that will be used to generate filenames for
            all instance mesh files.

        Ney Secco 2017-03
        """

        # We need to reexplode the original file
        if self.myID == 0:

            # Load the CGNS file
            combined_file = cs.readGrid(self.CGNSFile)

            # Explode the CGNS file by zones (this will only work if the user used cgns_utils combine
            # to create the input CGNS file, since the explosion uses the domain names)
            grids, zoneNames = cs.explodeByZoneName(combined_file)

            # Save temporary grid files with the exploded zones
            for grid, zoneName in zip(grids, zoneNames):
                grid.writeToCGNS("_" + zoneName + ".cgns")

            # Delete grids to free space
            del grids
            del combined_file

        # Assign baseName if user provided none
        if baseName is None:
            baseName = "IDWarpMulti"

        # Loop over all instances to write their meshes
        for instanceID, mesh in enumerate(self.meshes):

            # Generate a fileName
            fileName = baseName + "_inst%03d.cgns" % (instanceID)

            # Call function to write the mesh of the current instance
            mesh.writeGrid(fileName)

        # Now the root proc can remove the temporary grid files
        if self.myID == 0:
            for zoneName in zoneNames:
                os.system("rm _" + zoneName + ".cgns")
Example #2
0
def main():
    parser = get_parser()
    # Get the arguments we need!
    args = parser.parse_args()

    # -------------------------------------------
    #         Selection of the task
    # -------------------------------------------

    # The time combine is special. First we generate the list of files we
    # need to deal with.
    if args.mode == "timeCombine":
        # Get the directory name where the baseName is:
        path = os.path.dirname(os.path.abspath(args.baseName))

        # Get the full list of files in this directory:
        allFiles = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
        files = []

        parts = args.baseName.split("%d")
        maxLength = 0
        for f in allFiles:
            if (parts[0] == "" or parts[0] in f) and (parts[1] == "" or parts[1] in f):
                # Make sure there is a .cgns in there somwhere
                if ".cgns" in f:
                    files.append(f)
                    maxLength = max(maxLength, len(f))
                    files = sorted(files)

        if args.outFile is None:
            outFile = "unsteady.plt"
        else:
            outFile = args.outFile

        # Now we make a character array of the file names, and hand if off to
        # fortran for all the actual reading/writing.
        fileNames = numpy.zeros((len(files), 256), "c")
        for i in range(len(files)):
            fileNames[i, 0 : len(files[i])] = files[i]

        libcgns_utils.utils.time_combine(fileNames, outFile)
        sys.exit(0)

    if args.mode == "testBlock":
        nx = args.nx
        ny = args.ny
        nz = args.nz
        X = numpy.zeros((nx, ny, nz, 3))
        Xcart = []
        Xcart.append(numpy.linspace(0, 1, nx))
        Xcart.append(numpy.linspace(0, 1, ny))
        Xcart.append(numpy.linspace(0, 1, nz))
        Xx, Xy, Xz = numpy.meshgrid(Xcart[0], Xcart[1], Xcart[2], indexing="ij")
        X[:, :, :, 0] = Xx
        X[:, :, :, 1] = Xy
        X[:, :, :, 2] = Xz
        b = Block("domain.00001", [nx, ny, nz], X)
        # Add bocos so we can run it:
        b.addBoco(Boco("iMin", BC["bcfarfield"], [[1, 1], [1, ny], [1, nz]], "far"))
        b.addBoco(Boco("iMax", BC["bcfarfield"], [[nx, nx], [1, ny], [1, nz]], "far"))
        b.addBoco(Boco("jMin", BC["bcsymmetryplane"], [[1, nx], [1, 1], [1, nz]], "sym"))
        b.addBoco(Boco("jMax", BC["bcsymmetryplane"], [[1, nx], [ny, ny], [1, nz]], "sym"))
        b.addBoco(Boco("kMin", BC["bcwallviscous"], [[1, nx], [1, ny], [1, 1]], "wall"))
        b.addBoco(Boco("kMax", BC["bcfarfield"], [[1, nx], [1, ny], [nz, nz]], "far"))
        g = Grid()
        g.addBlock(b)
        g.writeToCGNS(args.outFile)
        sys.exit(0)

    # The 'combine' function is done first sicne it is the only function
    # that reads multiple cgns files.
    if args.mode == "combine":
        grids = []
        for fName in args.gridFiles:
            grid = readGrid(fName)
            grids.append(grid)

        combinedGrid = combineGrids(grids)
        combinedGrid.writeToCGNS(args.outFile)

        # This task is now finished
        sys.exit(0)

    if args.mode == "explicitCart":
        # This task doesn't have args.gridFile so do it first
        xMin = [args.xmin, args.ymin, args.zmin]
        xMax = [args.xmax, args.ymax, args.zmax]

        simpleCart(xMin, xMax, args.dh, args.hExtra, args.nExtra, args.sym, args.mgcycle, args.outFile)

        sys.exit(0)

    if args.mode == "plot3d2cgns":
        # This doesn't read a cgns file so do this first too.
        convertPlot3d(args.plot3dFile, args.gridFile)
        sys.exit(0)

    # Get the current working grid 'curGrid' by reading the input
    curGrid = readGrid(args.gridFile)

    # The following are "special" and done first since they do not
    # have a CGNS output.

    if args.mode == "extractSurface":
        curGrid.extractSurface(args.surfFile)
        sys.exit(0)

    if args.mode == "extractSpecifiedSurface":
        curGrid.extractSpecifiedSurface(
            args.surfFile, args.blockID, args.imin, args.imax, args.jmin, args.jmax, args.kmin, args.kmax
        )
        sys.exit(0)

    if args.mode == "cgns2plot3d":
        curGrid.writePlot3d(args.plot3dFile)
        sys.exit(0)

    if args.mode == "blockSizes":
        curGrid.printBlockInfo()
        sys.exit(0)

    # Determine if we have an output file:
    try:
        if args.outFile is None:
            # Determine where to put a file:
            dirpath = tempfile.mkdtemp()

            # Define a temp output file
            outFileName = os.path.join(dirpath, "tmp.cgns")
        else:
            outFileName = args.outFile
    except Exception:
        outFile = None

    # Perform one of the following actions:
    if args.mode == "flip":
        curGrid.flip(args.axis)

    elif args.mode == "scale":
        curGrid.scale(args.scale)

    elif args.mode == "mirror":
        curGrid = mirrorGrid(curGrid, args.axis, args.tol)

    elif args.mode == "coarsen":
        curGrid.coarsen()

    elif args.mode == "refine":
        curGrid.refine(args.axes)

    elif args.mode == "split":
        curGrid = splitGrid(curGrid, args.splitFile)

    elif args.mode == "merge":
        curGrid = mergeGrid(curGrid)

    elif args.mode == "connect":
        if args.connectSelf:
            curGrid.connectSelfOnly(args.tol)
        else:
            curGrid.connect(args.tol)

    elif args.mode == "divide":
        curGrid = divideGrid(curGrid)

    elif args.mode == "autoBC":
        curGrid.autoBC(args.radius, args.sym, [args.xOffset, args.yOffset, args.zOffset])

    elif args.mode == "overwriteFamilies":
        curGrid.overwriteFamilies(args.familyFile)

    elif args.mode == "writeSubfaceFamily":
        curGrid.writeSubfaceFamily(args.familyFile)

    elif args.mode == "copyFamilyInfo":
        sourceGrid = readGrid(args.sourceFile)
        curGrid.copyFamilyInfo(sourceGrid)

    elif args.mode == "overwriteBC":
        curGrid.overwriteBCs(args.bcFile)

    elif args.mode == "removeBC":
        curGrid.removeBCs()

    elif args.mode == "rebunch":
        curGrid.rebunch(args.spacing, args.extraCells, args.nodes)

    elif args.mode == "randomize":
        curGrid.randomize(args.seed, args.keepRHS)

    elif args.mode == "reorder":
        curGrid.reorder(args.intDigits)

    elif args.mode == "symmZero":
        curGrid.symmZero(args.sym)

    elif args.mode == "symmZeroNoBC":
        curGrid.symmZeroNoBC(args.sym, args.tol)

    elif args.mode == "double2D":
        curGrid.double2D()

    elif args.mode == "removeBlocks":
        curGrid.removeBlocks(args.blockIDs)

    elif args.mode == "cartesian":
        found_overset = False
        for block in curGrid.blocks:
            for boco in block.bocos:
                if boco.type == BC["bcoverset"]:
                    found_overset = True
        if found_overset:
            curGrid.cartesian(args.cartFile, args.outFile)
        else:
            print("The CGNS file has no overset boundary conditions")
        sys.exit(0)

    elif args.mode == "simpleCart":
        curGrid.simpleCart(args.dh, args.hExtra, args.nExtra, args.sym, args.mgcycle, args.outFile)
        sys.exit(0)

    elif args.mode == "simpleOCart":
        curGrid.simpleOCart(args.dh, args.hExtra, args.nExtra, args.sym, args.mgcycle, args.outFile)
        sys.exit(0)

    elif args.mode == "translate":
        curGrid.translate(args.dx, args.dy, args.dz)

    elif args.mode == "rotate":
        curGrid.rotate(args.vx, args.vy, args.vz, args.theta)

    elif args.mode == "autoOversetBC":
        curGrid.autoOversetBC(args.sym, args.connectSelf, args.tol)

    elif args.mode == "autoNearfieldBC":
        curGrid.autoNearfieldBC(args.sym)

    elif args.mode == "autoFarfieldBC":
        curGrid.autoFarfieldBC(args.sym)

    elif args.mode == "fillOpenBCs":
        curGrid.fillOpenBCs(BC[args.bocoType], args.famName)

    elif args.mode == "include":
        toWrite = []
        for spec in args.rangeSpec.split(","):
            if "-" in spec:
                tmp = spec.split("-")
                start = int(tmp[0])
                end = int(tmp[1])
            else:
                start = int(spec)
                end = int(spec)
            for i in range(start, end + 1):
                toWrite.append(i)
        toWrite = numpy.unique(toWrite)
        toWrite.sort()
        curGrid.writeToCGNSSelected(args.outFile, toWrite)
        sys.exit(0)

    elif args.mode == "section":
        if len(curGrid.blocks) != 1:
            print("section command works only on grids with 1 block")
            sys.exit(0)
        curGrid.blocks[0].section(args.iStart, args.iEnd, args.jStart, args.jEnd, args.kStart, args.kEnd)

    elif args.mode == "explode":
        # Split original multiblock grid in a list of single-block grids
        gridList = explodeGrid(curGrid)

        # Check if the user gave a reference name. Otherwise, use the input name as reference
        if args.outFile is None:
            # Get the base name
            outFile = os.path.splitext(os.path.basename(args.gridFile))[0]
        else:
            outFile = args.outFile

        # Generate a list of names for the files by adding integers to the reference name
        fileNames = [outFile + "_%03d" % index + ".cgns" for index in range(1, len(gridList) + 1)]

        # Save each grid
        for index in range(len(gridList)):
            gridList[index].writeToCGNS(fileNames[index])

        # Finish execution
        sys.exit(0)

    elif args.mode == "explodeKmin":
        # Split original multiblock grid in a list of single-block grids
        # that contains just the K = 1 face
        gridList = explodeGrid(curGrid, kMin=True)

        # Check if the user gave a reference name. Otherwise, use the input name as reference
        if args.outFile is None:
            # Get the base name
            outFile = os.path.splitext(os.path.basename(args.gridFile))[0]
        else:
            outFile = args.outFile

        # Generate a list of names for the files by adding integers to the reference name
        fileNames = [outFile + "_%03d" % index + ".xyz" for index in range(1, len(gridList) + 1)]

        # Save each grid
        for index in range(len(gridList)):
            gridList[index].writePlot3d(fileNames[index])

        # Finish execution
        sys.exit(0)

    elif args.mode == "explodeByZoneName":
        # Split original multiblock grid into a list of multiblock grids
        # that correspond to each component based on zone names
        gridList, nameList = explodeByZoneName(curGrid)

        # Save each grid
        for grid in gridList:
            fileName = grid.name
            grid.writeToCGNS(fileName + ".cgns")

        # Finish execution
        sys.exit(0)

    elif args.mode == "info":
        curGrid.printInfo()
        sys.exit(0)

    elif args.mode == "extrude":
        curGrid.extrude(args.direction)

    elif args.mode == "revolve":
        if args.normalDirection == args.axis:
            print("ERROR: Normal direction and revolve axis cannot be the same. Exiting...")
            sys.exit(0)
        curGrid.revolve(args.normalDirection, args.axis, args.startAngle, args.endAngle, args.nThetas)

    elif args.mode == "extractConv":
        # extracts the convergence history contained in the CGNS file and saves it in a pickle file

        # Check if the user gave a reference name. Otherwise, use the input name as reference
        if args.outFile is None:

            # Get the base name
            outFile = os.path.splitext(os.path.basename(args.gridFile))[0]

            # Add extension based on output type
            if args.outType == "pickle":
                outFile = outFile + ".pickle"
            elif args.outType == "tecplot":
                outFile = outFile + ".dat"

        else:
            outFile = args.outFile

        # The function readGrid already read all the convergence history arrays.
        # Now we just need to save them in a file!
        if args.outType == "pickle":
            with open(outFile, "w") as fid:
                pickle.dump(curGrid.convArray, fid)

        elif args.outType == "tecplot":

            # Create a single 2D array that will contain all data
            data = []

            # Get the number of iterations
            numIter = len(curGrid.convArray[curGrid.convArray.keys()[0]])

            # Append iteration counter
            data.append(range(1, numIter + 1))

            for entry in curGrid.convArray.keys():
                data.append(curGrid.convArray[entry])

            # Convert data to array
            data = numpy.array(data).T

            # Write tecplot results
            write_tecplot_file(outFile, "Convergence", ["Iteration"] + curGrid.convArray.keys(), data)

        # Print log
        print("Saved convergence history into:")
        print(outFile)

        # Finish execution
        sys.exit(0)

    # Write out the grid.
    curGrid.writeToCGNS(outFileName)

    # Possibly copy back to the original:
    if args.outFile is None:
        shutil.copyfile(outFileName, args.gridFile)
        shutil.rmtree(dirpath)
Example #3
0
    def __init__(self, CGNSFile, optionsDict, comm=None, dtype="d", debug=False):
        """
        Create the MultiUSMesh object.

        INPUTS:

        CGNSFile: string -> file name of the CGNS file. This CGNS file should be generated with
        cgns_utils combine, so that the domain names have the appropriate convention. That is,
        domains will have the same name as their original files. Domains that share the same name
        will be grouped to make an IDWarp instance.

        optionsDict: dictionary of dictionaries -> Dictionary containing dictionaries that will
        be used to initialize multiple IDWarp instances. The keys are domain names and the
        values are dictionaries of standard IDWarp options that will be applied to this domain.
        The domains of the full CGNS file that do not have a corresponding entry in optionsDict will
        not be warped. For instance, if the CGNS file has the domains wing.00000, wing.00001, and wing.00002
        associated with a wing mesh that we want to warp, then optionsDict should have an entry for 'wing'.

        Ney Secco 2017-02
        """

        # Check if cs was imported correctly:
        if cs is None:
            raise Error("cgns_utils could not be loaded correctly. MultiUSMesh " "requires cgns_utils to function.")

        # Assign communicator if we do not have one yet
        if comm is None:
            comm = MPI.COMM_WORLD

        # Check if warp has already been set by the complex version
        try:
            self.warp
        except AttributeError:
            curDir = os.path.basename(os.path.dirname(os.path.realpath(__file__)))
            self.warp = MExt("libidwarp", curDir, debug=debug)._module

        # Store communicator
        self.comm = comm

        # Store original file name
        self.CGNSFile = CGNSFile

        # Store scalar type
        self.dtype = dtype

        # Only the root processor will take the combined CGNS file
        # and explode it by instance.
        if self.myID == 0:

            # Initialize list to store the block IDs that belong to each IDWarp instance.
            # For example, suppose that our combined CGNS file has 21 blocks.
            # Blocks 1 to 5 belong to the fuselage
            # Blocks 6 to 12 belong to the wing
            # Blocks 13 to 21 belong to the background mesh
            # Then cgnsBlockIntervals = [[0,5],[5,12],[12,21]
            self.cgnsBlockIntervals = []

            # Initialize array to store volume nodes CGNS intervals for each instance
            self.cgnsVolNodeIntervals = []

            # Initialize block counter
            blockCounter = 0

            # Initialize node counter
            nodeCounter = 0

            # Load the CGNS file
            combined_file = cs.readGrid(CGNSFile)

            # Explode the CGNS file by zones (this will only work if the user used cgns_utils combine
            # to create the input CGNS file, since the explosion uses the domain names)
            grids, zoneNames = cs.explodeByZoneName(combined_file)

            # Save temporary grid files with the exploded zones
            for grid, zoneName in zip(grids, zoneNames):
                grid.writeToCGNS("_" + zoneName + ".cgns")

                # Store the number of blocks in each zone
                self.cgnsBlockIntervals.append([blockCounter, blockCounter + len(grid.blocks)])

                # Count the number of nodes (here is degrees of freedom or nodes*3
                totalNodes = 0
                for blk in grid.blocks:
                    totalNodes += blk.dims[0] * blk.dims[1] * blk.dims[2] * 3

                # Store the number of volume nodes in each zone
                self.cgnsVolNodeIntervals.append([nodeCounter, nodeCounter + totalNodes])

                # Update block counter
                blockCounter = blockCounter + len(grid.blocks)

                # Update node counter
                nodeCounter = nodeCounter + totalNodes

            # Delete grids to free space
            del grids
            del combined_file

        else:

            # Initialize variables to get results in the end
            zoneNames = None
            self.cgnsBlockIntervals = None
            self.cgnsVolNodeIntervals = None

        # Send information to all procs
        zoneNames = self.comm.bcast(zoneNames, root=0)
        self.cgnsBlockIntervals = self.comm.bcast(self.cgnsBlockIntervals, root=0)
        self.cgnsVolNodeIntervals = self.comm.bcast(self.cgnsVolNodeIntervals, root=0)

        # Get names for nearfield meshes.
        # The nearfield mesh names will be the keys of the options dictionary.
        nearfieldNames = optionsDict.keys()

        # Initialize list of IDWarp instances
        self.meshes = []

        # Initialize list to hold indices of the background zones
        self.backgroundInstanceIDs = []

        # Loop over all zones that we found in the combined CGNS file
        for zoneNumber, zoneName in enumerate(zoneNames):

            # Check if the zone belongs to a nearfield mesh
            if zoneName in nearfieldNames:

                # ------------------------------------------------------
                # READING NEARFIELD MESHES (The ones that will be warped)
                #

                # Assign the name of the temporary CGNS file to the options.
                # This is the file that contains the mesh o a single component.
                # Remember that we should use the temporary grid file.
                optionsDict[zoneName]["gridFile"] = "_" + zoneName + ".cgns"

                # Initialize an IDWarp instance with the current options
                if self.dtype == "d":
                    currMesh = self.warp.USMesh(options=optionsDict[zoneName], comm=self.comm)
                elif self.dtype == "D":
                    currMesh = self.warp.USMesh_C(options=optionsDict[zoneName], comm=self.comm)

            else:

                # We have a background mesh

                # Regenerate the temporary filename for the background grid
                bgFile = "_" + zoneName + ".cgns"

                # ------------------------------------------------------
                # READING BACKGROUND MESHES

                # =========================================================#
                # THIS IS A MESSY (HOPEFULLY TEMPORARY) WAY OF LOADING THE
                # BACKGROUND MESH NODES. IF YOU COME UP WITH A BETTER WAY
                # TO GET volNodes, PLEASE ADD IT HERE.
                # volNodes is a flattened vector that contains the background
                # mesh volume nodes that belong to the current proc.

                # Let's try using IDWarp's CGNS loader to extract the bakground nodes.
                # However, we will have to trick IDWarp in order to do this, since it
                # expects a surface mesh in the file.
                # So we will make a copy of the background mesh file, assign an arbitrary
                # wall surface, and then load it with IDWarp

                # Only the root proc will modify the input file
                if self.myID == 0:

                    # Make a copy of the background mesh file
                    os.system("cp " + bgFile + " tmp_bg_file.cgns")

                    # Create a temporary BC file
                    with open("tmp_bcdata.dat", "w") as fid:
                        fid.write("1 iLow BCwall wall\n")

                    # Use CGNS utils to modify the BCs
                    os.system("cgns_utils overwritebc tmp_bg_file.cgns tmp_bcdata.dat")

                # Create dummy set of options just to load the CGNS file
                dummyOptions = {
                    "gridFile": "tmp_bg_file.cgns",
                    "warpType": "unstructured",
                }

                # Initialize an IDWarp instance with the current options
                if self.dtype == "d":
                    currMesh = self.warp.USMesh(options=dummyOptions, comm=self.comm)
                elif self.dtype == "D":
                    currMesh = self.warp.USMesh_C(options=dummyOptions, comm=self.comm)

                # Initialize a dummy surface in the background mesh
                """
                if self.myID == 0:
                    print('===========================================')
                    print('ATTENTION: This is a dummy initialization for background mesh warping.')
                pts = np.array([[1.0, 0.0, 1.0],
                                [2.0, 0.0, 1.0],
                                [2.0, 1.0, 1.0],
                                [1.0, 1.0, 1.0]])*(self.myID+1)
                conn = np.array([0,1,2,3])
                faceSizes = np.array([4])
                currMesh.setSurfaceDefinition(pts, conn, faceSizes)
                if self.myID == 0:
                    print('Dummy initialization is Done!')
                    print('===========================================')
                """
                if self.myID == 0:
                    print("===========================================")
                    print("ATTENTION: This is a dummy initialization for background mesh warping.")

                currMesh._setInternalSurface()

                if self.myID == 0:
                    print("Dummy initialization is Done!")
                    print("===========================================")

                # The root proc can remove the temporary files
                if self.myID == 0:

                    # Make a copy of the background mesh file
                    os.system("rm tmp_bg_file.cgns")
                    os.system("rm tmp_bcdata.dat")

                # Store the ID of this zone
                self.backgroundInstanceIDs.append(zoneNumber)

            # Append the instance to the list.
            # We will store even the background mesh instances for now,
            # but we will delete them as soon as we call self.setExternalMeshIndices().
            self.meshes.append(currMesh)

        # Now the root proc can remove the temporary grid files
        if self.myID == 0:
            for zoneName in zoneNames:
                os.system("rm _" + zoneName + ".cgns")

        # ------------------------------------------------------
        # Initialize other fields for completness
        self.numSurfNodes = None  # How many solver surface nodes we have in the current proc, for all instances
        self.numVolNodes = None  # How many solver volume nodes we have in the current proc, for all instances
        self.cgnsVolNodeMasks = []  # Mask used to filter which volume nodes given by the solver belong to each instance