示例#1
0
文件: viewer.py 项目: snilek/sfepy
 def _make_iterator(repeat, n_row, n_col):
     ii = 0
     for ij, iric in enumerate(cycle((n_row, n_col))):
         ir, ic = iric
         if ij < len(repeat):
             for ik in xrange(repeat[ij]):
                 yield ii, ir, ic
                 ii += 1
示例#2
0
文件: log.py 项目: mikegraham/sfepy
    def make_axes(self):
        self.fig.clf()
        self.ax = []

        n_col = min(5.0, nm.fix(nm.sqrt(self.n_gr)))
        if int(n_col) == 0:
            n_row = 0
        else:
            n_row = int(nm.ceil(self.n_gr / n_col))
            n_col = int(n_col)

        for ii, (ir, ic) in enumerate(cycle((n_col, n_row))):
            if ii == self.n_gr: break
            self.ax.append(self.fig.add_subplot(n_row, n_col, ii+1))
            self.vlines.setdefault(ii, [])
示例#3
0
文件: log.py 项目: sdurve/sfepy
    def make_axes(self):
        self.fig.clf()
        self.ax = []

        n_col = min(5.0, nm.fix(nm.sqrt(self.n_gr)))
        if int(n_col) == 0:
            n_row = 0
        else:
            n_row = int(nm.ceil(self.n_gr / n_col))
            n_col = int(n_col)

        for ii, (ir, ic) in enumerate(cycle((n_col, n_row))):
            if ii == self.n_gr: break
            self.ax.append(self.fig.add_subplot(n_row, n_col, ii + 1))
            self.vlines.setdefault(ii, [])
示例#4
0
def read_spline_box_hdf5(filename):
    if not pt.isHDF5File(filename):
        raise ValueError, 'not a HDF5 file! (%s)' % filename

    fd = pt.openFile(filename, mode='r')
    boxes = fd.listNodes('/box')
    n_box = len(boxes)
    dim = len(fd.listNodes(boxes[0].ax))

    sp_boxes = SplineBoxes(dim=dim,
                           n_box=n_box,
                           n_vertex=0,
                           spbs=OneTypeList(SplineBox))
    for box in boxes:
        spb = SplineBox()
        sp_boxes.spbs.append(spb)

        spb.ib = int(box._v_name)
        spb.cpi = nm.asarray(box.cpi.read()) - 1
        spb.gpi = nm.asarray(box.gpi.read()) - 1
        spb.cxyz = nm.asarray(box.cxyz.read()).transpose()
        spb.cxyz0 = spb.cxyz.copy()
        spb.ax = []
        for axi in fd.listNodes(box.ax):
            spb.ax.append(nm.asarray(axi.bsc.read()))

        sp_boxes.n_vertex = max(sp_boxes.n_vertex, nm.amax(spb.gpi) + 1)
        print nm.amin(spb.gpi), nm.amax(spb.gpi)

        ##
        # Fix cpi by rebuilding :).
        off = 0
        n0, n1, n2 = spb.cpi.shape
        aux = nm.arange(n0 * n1).reshape(n1, n0).transpose()
        for ii in xrange(n2):
            spb.cpi[:, :, ii] = aux + off
            off += n0 * n1

    fd.close()

    for perm in cycle([n_box] * 2):
        if perm[0] == perm[1]: continue
        gpi1 = sp_boxes.spbs[perm[0]].gpi
        gpi2 = sp_boxes.spbs[perm[1]].gpi
        assert_(len(nm.intersect1d(gpi1, gpi2)) == 0)

    return sp_boxes
示例#5
0
def read_spline_box_hdf5( filename ):
    if not pt.isHDF5File( filename ):
        raise ValueError, 'not a HDF5 file! (%s)' % filename

    fd = pt.openFile( filename, mode = 'r' )
    boxes = fd.listNodes( '/box' )
    n_box = len( boxes )
    dim = len( fd.listNodes( boxes[0].ax ) )

    sp_boxes = SplineBoxes( dim = dim, n_box = n_box, n_vertex = 0,
                           spbs = OneTypeList( SplineBox ) )
    for box in boxes:
        spb = SplineBox()
        sp_boxes.spbs.append( spb )

        spb.ib = int( box._v_name )
        spb.cpi = nm.asarray( box.cpi.read() ) - 1
        spb.gpi = nm.asarray( box.gpi.read() ) - 1
        spb.cxyz = nm.asarray( box.cxyz.read() ).transpose()
        spb.cxyz0 = spb.cxyz.copy()
        spb.ax = []
        for axi in fd.listNodes( box.ax ):
            spb.ax.append( nm.asarray( axi.bsc.read() ) )

        sp_boxes.n_vertex = max( sp_boxes.n_vertex, nm.amax( spb.gpi ) + 1 )
        print nm.amin( spb.gpi ), nm.amax( spb.gpi )

        ##
        # Fix cpi by rebuilding :).
        off = 0
        n0, n1, n2 = spb.cpi.shape
        aux = nm.arange( n0 * n1 ).reshape( n1, n0 ).transpose()
        for ii in xrange( n2 ):
            spb.cpi[:,:,ii] = aux + off
            off += n0 * n1

    fd.close()

    for perm in cycle( [n_box] * 2 ):
        if perm[0] == perm[1]: continue
        gpi1 = sp_boxes.spbs[perm[0]].gpi
        gpi2 = sp_boxes.spbs[perm[1]].gpi
        assert_( len( nm.intersect1d( gpi1, gpi2 ) ) == 0 )
    
    return sp_boxes
示例#6
0
    def __call__(self, u=None, v=None, w=None, field=None):
        """
        Igakit-like interface for NURBS evaluation.
        """
        pars = [u]
        if v is not None: pars += [v]
        if w is not None: pars += [w]

        indices = []
        uks = []
        rcs = []
        for ia, par in enumerate(pars):
            uk, indx, rc = self._get_ref_coors_1d(par, ia)
            indices.append(indx)
            uks.append(uk)
            rcs.append(rc)

        shape = [len(ii) for ii in pars]
        n_vals = nm.prod(shape)

        if field is None:
            out = nm.zeros((n_vals, self.dim), dtype=nm.float64)

        else:
            out = nm.zeros((n_vals, field.shape[1]), dtype=nm.float64)

        for ip, igrid in enumerate(cycle(shape)):
            iis = [indices[ii][igrid[ii]] for ii in xrange(self.dim)]
            ie = iga.get_raveled_index(iis, self.n_els)

            rc = [rcs[ii][igrid[ii]] for ii in xrange(self.dim)]

            bf, bfg, det = iga.eval_nurbs_basis_tp(rc, ie, self.cps,
                                                   self.weights, self.degrees,
                                                   self.cs, self.conn)
            ec = self.conn[ie]

            if field is None:
                out[ip, :] = nm.dot(bf, self.cps[ec])

            else:
                out[ip, :] = nm.dot(bf, field[ec])

        return out
示例#7
0
def main():
    parser = OptionParser(usage=usage, version='%prog')
    parser.add_option('-b', '--basis', metavar='name',
                      action='store', dest='basis',
                      default='lagrange', help=help['basis'])
    parser.add_option('-d', '--derivative', metavar='d', type=int,
                      action='store', dest='derivative',
                      default=0, help=help['derivative'])
    parser.add_option('-n', '--max-order', metavar='order', type=int,
                      action='store', dest='max_order',
                      default=2, help=help['max_order'])
    parser.add_option('-g', '--geometry', metavar='name',
                      action='store', dest='geometry',
                      default='2_4', help=help['geometry'])
    parser.add_option('-m', '--mesh', metavar='mesh',
                      action='store', dest='mesh',
                      default=None, help=help['mesh'])
    parser.add_option('', '--permutations', metavar='permutations',
                      action='store', dest='permutations',
                      default=None, help=help['permutations'])
    parser.add_option('', '--dofs', metavar='dofs',
                      action='store', dest='dofs',
                      default=None, help=help['dofs'])
    parser.add_option('-l', '--lin-options', metavar='options',
                      action='store', dest='lin_options',
                      default='min_level=2,max_level=5,eps=1e-3',
                      help=help['lin_options'])
    parser.add_option('', '--plot-dofs',
                      action='store_true', dest='plot_dofs',
                      default=False, help=help['plot_dofs'])
    options, args = parser.parse_args()

    if len(args) == 1:
        output_dir = args[0]
    else:
        parser.print_help(),
        return

    output('polynomial space:', options.basis)
    output('max. order:', options.max_order)

    lin = Struct(kind='adaptive', min_level=2, max_level=5, eps=1e-3)
    for opt in options.lin_options.split(','):
        key, val = opt.split('=')
        setattr(lin, key, eval(val))

    if options.mesh is None:
        dim, n_ep = int(options.geometry[0]), int(options.geometry[2])
        output('reference element geometry:')
        output('  dimension: %d, vertices: %d' % (dim, n_ep))

        gel = GeometryElement(options.geometry)
        gps = PolySpace.any_from_args(None, gel, 1,
                                      base=options.basis)
        ps = PolySpace.any_from_args(None, gel, options.max_order,
                                     base=options.basis)

        n_digit, _format = get_print_info(ps.n_nod, fill='0')
        name_template = os.path.join(output_dir, 'bf_%s.vtk' % _format)
        for ip in get_dofs(options.dofs, ps.n_nod):
            output('shape function %d...' % ip)

            def eval_dofs(iels, rx):
                if options.derivative == 0:
                    bf = ps.eval_base(rx).squeeze()
                    rvals = bf[None, :, ip:ip+1]

                else:
                    bfg = ps.eval_base(rx, diff=True)
                    rvals = bfg[None, ..., ip]

                return rvals

            def eval_coors(iels, rx):
                bf = gps.eval_base(rx).squeeze()
                coors = nm.dot(bf, gel.coors)[None, ...]
                return coors

            (level, coors, conn,
             vdofs, mat_ids) = create_output(eval_dofs, eval_coors, 1,
                                             ps, min_level=lin.min_level,
                                             max_level=lin.max_level,
                                             eps=lin.eps)
            out = {
                'bf' : Struct(name='output_data',
                              mode='vertex', data=vdofs,
                              var_name='bf', dofs=None)
            }

            mesh = Mesh.from_data('bf_mesh', coors, None, [conn], [mat_ids],
                                  [options.geometry])

            name = name_template % ip
            ensure_path(name)
            mesh.write(name, out=out)

            output('...done (%s)' % name)

    else:
        mesh = Mesh.from_file(options.mesh)
        output('mesh geometry:')
        output('  dimension: %d, vertices: %d, elements: %d'
               % (mesh.dim, mesh.n_nod, mesh.n_el))

        if options.permutations:
            if options.permutations == 'all':
                from sfepy.linalg import cycle
                gel = GeometryElement(mesh.descs[0])
                n_perms = gel.get_conn_permutations().shape[0]
                all_permutations = [ii for ii in cycle(mesh.n_el * [n_perms])]

            else:
                all_permutations = [int(ii)
                                    for ii in options.permutations.split(',')]
                all_permutations = nm.array(all_permutations)
                np = len(all_permutations)
                all_permutations.shape = (np / mesh.n_el, mesh.n_el)

            output('using connectivity permutations:\n', all_permutations)

        else:
            all_permutations = [None]

        for ip, permutations in enumerate(all_permutations):
            if permutations is None:
                suffix = ''

            else:
                suffix = '_' + '_'.join('%d' % ii for ii in permutations)

            save_basis_on_mesh(mesh, options, output_dir, lin, permutations,
                               suffix)
示例#8
0
def gen_cylinder_mesh(dims, shape, centre, axis='x', force_hollow=False,
                      is_open=False, open_angle=0.0, non_uniform=False,
                      name='cylinder', verbose=True):
    """
    Generate a cylindrical mesh along an axis. Its cross-section can be
    ellipsoidal.

    Parameters
    ----------
    dims : array of 5 floats
        Dimensions of the cylinder: inner surface semi-axes a1, b1, outer
        surface semi-axes a2, b2, length.
    shape : array of 3 ints
        Shape (counts of nodes in radial, circumferential and longitudinal
        directions) of the cylinder mesh.
    centre : array of 3 floats
        Centre of the cylinder.
    axis: one of 'x', 'y', 'z'
        The axis of the cylinder.
    force_hollow : boolean
        Force hollow mesh even if inner radii a1 = b1 = 0.
    is_open : boolean
        Generate an open cylinder segment.
    open_angle : float
        Opening angle in radians.
    non_uniform : boolean
        If True, space the mesh nodes in radial direction so that the element
        volumes are (approximately) the same, making thus the elements towards
        the outer surface thinner.
    name : string
        Mesh name.
    verbose : bool
        If True, show progress of the mesh generation.

    Returns
    -------
    mesh : Mesh instance
    """
    dims = nm.asarray(dims, dtype=nm.float64)
    shape = nm.asarray(shape, dtype=nm.int32)
    centre = nm.asarray(centre, dtype=nm.float64)

    a1, b1, a2, b2, length = dims
    nr, nfi, nl = shape
    origin = centre - nm.array([0.5 * length, 0.0, 0.0])

    dfi = 2.0 * (nm.pi - open_angle) / nfi
    if is_open:
        nnfi = nfi + 1
    else:
        nnfi = nfi

    is_hollow = force_hollow or not (max(abs(a1), abs(b1)) < 1e-15)

    if is_hollow:
        mr = 0
    else:
        mr = (nnfi - 1) * nl

    grid = nm.zeros((nr, nnfi, nl), dtype=nm.int32)

    n_nod = nr * nnfi * nl - mr
    coors = nm.zeros((n_nod, 3), dtype=nm.float64)

    angles = nm.linspace(open_angle, open_angle+(nfi)*dfi, nfi+1)
    xs = nm.linspace(0.0, length, nl)
    if non_uniform:
        ras = nm.zeros((nr,), dtype=nm.float64)
        rbs = nm.zeros_like(ras)
        advol = (a2**2 - a1**2) / (nr - 1)
        bdvol = (b2**2 - b1**2) / (nr - 1)
        ras[0], rbs[0] = a1, b1
        for ii in range(1, nr):
            ras[ii] = nm.sqrt(advol + ras[ii-1]**2)
            rbs[ii] = nm.sqrt(bdvol + rbs[ii-1]**2)
    else:
        ras = nm.linspace(a1, a2, nr)
        rbs = nm.linspace(b1, b2, nr)

    # This is 3D only...
    output('generating %d vertices...' % n_nod, verbose=verbose)
    ii = 0
    for ix in range(nr):
        a, b = ras[ix], rbs[ix]
        for iy, fi in enumerate(angles[:nnfi]):
            for iz, x in enumerate(xs):
                grid[ix,iy,iz] = ii
                coors[ii] = origin + [x, a * nm.cos(fi), b * nm.sin(fi)]
                ii += 1

                if not is_hollow and (ix == 0):
                    if iy > 0:
                        grid[ix,iy,iz] = grid[ix,0,iz]
                        ii -= 1
    assert_(ii == n_nod)
    output('...done', verbose=verbose)

    n_el = (nr - 1) * nnfi * (nl - 1)
    conn = nm.zeros((n_el, 8), dtype=nm.int32)

    output('generating %d cells...' % n_el, verbose=verbose)
    ii = 0
    for (ix, iy, iz) in cycle([nr-1, nnfi, nl-1]):
        if iy < (nnfi - 1):
            conn[ii,:] = [grid[ix  ,iy  ,iz  ], grid[ix+1,iy  ,iz  ],
                          grid[ix+1,iy+1,iz  ], grid[ix  ,iy+1,iz  ],
                          grid[ix  ,iy  ,iz+1], grid[ix+1,iy  ,iz+1],
                          grid[ix+1,iy+1,iz+1], grid[ix  ,iy+1,iz+1]]
            ii += 1
        elif not is_open:
            conn[ii,:] = [grid[ix  ,iy  ,iz  ], grid[ix+1,iy  ,iz  ],
                          grid[ix+1,0,iz  ], grid[ix  ,0,iz  ],
                          grid[ix  ,iy  ,iz+1], grid[ix+1,iy  ,iz+1],
                          grid[ix+1,0,iz+1], grid[ix  ,0,iz+1]]
            ii += 1

    mat_id = nm.zeros((n_el,), dtype = nm.int32)
    desc = '3_8'

    assert_(n_nod == (conn.max() + 1))
    output('...done', verbose=verbose)

    if axis == 'z':
        coors = coors[:,[1,2,0]]
    elif axis == 'y':
        coors = coors[:,[2,0,1]]

    mesh = Mesh.from_data(name, coors, None, [conn], [mat_id], [desc])
    return mesh
示例#9
0
def gen_block_mesh(dims, shape, centre, name='block'):
    """
    Generate a 2D or 3D block mesh. The dimension is determined by the
    lenght of the shape argument.

    Parameters
    ----------
    dims : array of 2 or 3 floats
        Dimensions of the block.
    shape : array of 2 or 3 ints
        Shape (counts of nodes in x, y, z) of the block mesh.
    centre : array of 2 or 3 floats
        Centre of the block.

    name : string
        Mesh name.

    Returns
    -------
    mesh : Mesh instance
    """
    dims = nm.asarray(dims, dtype=nm.float64)
    shape = nm.asarray(shape, dtype=nm.int32)
    centre = nm.asarray(centre, dtype=nm.float64)

    dim = shape.shape[0]

    centre = centre[:dim]
    dims = dims[:dim]

    x0 = centre - 0.5 * dims
    dd = dims / (shape - 1)

    grid = nm.zeros(shape, dtype = nm.int32)
    n_nod = nm.prod(shape)
    coors = nm.zeros((n_nod, dim), dtype = nm.float64)

    bar = MyBar("       nodes:")
    bar.init(n_nod)
    for ii, ic in enumerate(cycle(shape)):
        grid[tuple(ic)] = ii
        coors[ii] = x0 + ic * dd
        if not (ii % 100):
            bar.update(ii)
    bar.update(ii + 1)

    n_el = nm.prod(shape - 1)
    mat_id = nm.zeros((n_el,), dtype = nm.int32)

    if (dim == 2):
        conn = nm.zeros((n_el, 4), dtype = nm.int32)
        bar = MyBar("       elements:")
        bar.init(n_el)
        for ii, (ix, iy) in enumerate(cycle(shape - 1)):
            conn[ii,:] = [grid[ix  ,iy], grid[ix+1,iy  ],
                          grid[ix+1,iy+1], grid[ix  ,iy+1]]
            if not (ii % 100):
                bar.update(ii)
        bar.update(ii + 1)
        desc = '2_4'

    else:
        conn = nm.zeros((n_el, 8), dtype = nm.int32)
        bar = MyBar("       elements:")
        bar.init(n_el)
        for ii, (ix, iy, iz) in enumerate(cycle(shape - 1)):
            conn[ii,:] = [grid[ix  ,iy  ,iz  ], grid[ix+1,iy  ,iz  ],
                          grid[ix+1,iy+1,iz  ], grid[ix  ,iy+1,iz  ],
                          grid[ix  ,iy  ,iz+1], grid[ix+1,iy  ,iz+1],
                          grid[ix+1,iy+1,iz+1], grid[ix  ,iy+1,iz+1]]
            if not (ii % 100):
                bar.update(ii)
        bar.update(ii + 1)
        desc = '3_8'

    mesh = Mesh.from_data(name, coors, None, [conn], [mat_id], [desc])
    return mesh
示例#10
0
def compose_periodic_mesh(mesh_in, scale, repeat, eps, check_mvd=False):
    """
    Create a new mesh from a periodic mesh by scaling it and repeating
    along each axis,

    Parameters
    ----------
    mesh_in : Mesh instance
        The input periodic mesh.
    scale : float
        The scale parameter.
    repeat : array
        The number of repetitions of `mesh_in` along each axis.
    eps : float
        Tolerance for finding matching mesh vertices.
    check_mvd : bool
        If True, verify periodicity by checking approximate minimum
        vertex distance and minimum edge length.

    Returns
    -------
    mesh_out : Mesh instance
        The composed periodic mesh.
    """
    dim = mesh_in.dim
    bbox = mesh_in.get_bounding_box()
    mscale = bbox[1] - bbox[0]
    output('bbox:\n', bbox)

    centre0 = 0.5 * (bbox[1] + bbox[0])
    output('centre:\n', centre0)

    scale = float(scale)
    if repeat is None:
        repeat = [scale] * dim

    repeat = nm.asarray(repeat)

    # Normalize original coordinates.
    coor0 = (mesh_in.coors - centre0) / (mscale)

    aux = fix_double_nodes(coor0, mesh_in.ngroups, mesh_in.conns, eps)
    coor0, ngroups0, mesh_in.conns = aux
    
    if check_mvd:
        mes0 = get_min_edge_size(coor0, mesh_in.conns)
        mvd0 = get_min_vertex_distance(coor0, mes0)
        if mes0 > (mvd0 + eps):
            output('          original min. "edge" length: %.5e' % mes0)
            output('original approx. min. vertex distance: %.5e' % mvd0)
            output('-> still double nodes in input mesh!')
            output('try increasing eps')
            raise ValueError('cannot fix double nodes!')

    output('composing periodic mesh...')
    for indx in cycle(repeat):
        aindx = nm.array(indx, dtype=nm.float64)
        centre = 0.5 * (2.0 * aindx - repeat + 1.0)
        output(indx, centre)

        if aindx.sum() == 0:
            coor = coor0 + centre
            ngroups = ngroups0
            conns = mesh_in.conns
        else:
            coor1 = coor0 + centre
            ngroups1 = ngroups0
            conns1 = mesh_in.conns

            cmap = find_map(coor, coor1, eps=eps)
            if not cmap.size:
                raise ValueError('non-periodic mesh!')

            else:
                output(cmap.size / 2)

            coor, ngroups, conns = merge_mesh(coor, ngroups, conns,
                                              coor1, ngroups1, conns1,
                                              cmap, eps=eps)

    if check_mvd:
        mes = get_min_edge_size( coor, conns )
        mvd = get_min_vertex_distance( coor, mes0 )

        output('          original min. "edge" length: %.5e' % mes0)
        output('             final min. "edge" length: %.5e' % mes)
        output('original approx. min. vertex distance: %.5e' % mvd0)
        output('   final approx. min. vertex distance: %.5e' % mvd)
        if mvd < 0.99999 * mvd0:
            if mvd0 < (mes0 - eps):
                output('-> probably non-periodic input mesh!')
                output('   - adjacent sides were not connected!')
                output('   try increasing eps')
            else:
                output('-> input mesh might be periodic')
                output('   try increasing eps')
        else:
            output('-> input mesh looks periodic')
    else:
        output('non-periodic input mesh detection skipped!')

    # Renormalize.
    coor = (coor * mscale) / scale
    mesh_out = make_mesh(coor, ngroups, conns, mesh_in)
    output('...done')

    return mesh_out
示例#11
0
def main():

    parser = OptionParser(usage=usage, version="%prog 42")
    parser.add_option(
        "-s", "--scale", type=int, metavar="scale", action="store", dest="scale", default=2, help=help["scale"]
    )
    parser.add_option(
        "-e", "--eps", type=float, metavar="eps", action="store", dest="eps", default=1e-8, help=help["eps"]
    )
    parser.add_option("-t", "--test", action="store_true", dest="test", default=False, help=help["test"])
    parser.add_option("-n", "--no-mvd", action="store_true", dest="nomvd", default=False, help=help["nomvd"])
    (options, args) = parser.parse_args()

    if options.test:
        test()
        return

    if len(args) == 2:
        filename_in = args[0]
        filename_out = args[1]
    else:
        parser.print_help()
        return

    print "scale:", options.scale
    print "eps:", options.eps

    mesh_in = Mesh.from_file(filename_in)
    bbox = mesh_in.get_bounding_box()
    print "bbox:\n", bbox
    mscale = bbox[1] - bbox[0]
    centre0 = 0.5 * (bbox[1] + bbox[0])
    print "centre:\n", centre0

    scale = nm.array(options.scale, dtype=nm.float64)

    # Normalize original coordinates.
    coor0 = (mesh_in.coors - centre0) / (mscale)
    dim = mesh_in.dim

    aux = fix_double_nodes(coor0, mesh_in.ngroups, mesh_in.conns, options.eps)
    coor0, ngroups0, mesh_in.conns = aux

    if not options.nomvd:
        mes0 = get_min_edge_size(coor0, mesh_in.conns)
        mvd0 = get_min_vertex_distance(coor0, mes0)
        if mes0 > (mvd0 + options.eps):
            print '          original min. "edge" length: %.5e' % mes0
            print "original approx. min. vertex distance: %.5e" % mvd0
            print "-> still double nodes in input mesh!"
            print "try increasing eps..."
            raise ValueError

    for indx in cycle([options.scale] * dim):
        aindx = nm.array(indx, dtype=nm.float64)
        centre = 0.5 * (2.0 * aindx - scale + 1.0)
        print indx, centre

        if aindx.sum() == 0:
            coor = coor0 + centre
            ngroups = ngroups0
            conns = mesh_in.conns
        else:
            coor1 = coor0 + centre
            ngroups1 = ngroups0
            conns1 = mesh_in.conns

            cmap = find_map(coor, coor1, eps=options.eps)
            if not cmap.size:
                print "non-periodic mesh!"
            #                raise ValueError
            else:
                print cmap.size / 2
            coor, ngroups, conns = merge_mesh(coor, ngroups, conns, coor1, ngroups1, conns1, cmap, eps=options.eps)

    if not options.nomvd:
        mes = get_min_edge_size(coor, conns)
        mvd = get_min_vertex_distance(coor, mes0)

        print '          original min. "edge" length: %.5e' % mes0
        print '             final min. "edge" length: %.5e' % mes
        print "original approx. min. vertex distance: %.5e" % mvd0
        print "   final approx. min. vertex distance: %.5e" % mvd
        if mvd < 0.99999 * mvd0:
            if mvd0 < (mes0 - options.eps):
                print "-> probably non-periodic input mesh!"
                print "   ... adjacent sides were not connected!"
                print "   try increasing eps..."
            else:
                print "-> input mesh might be periodic"
                print "   try increasing eps..."
        else:
            print "-> input mesh looks periodic"
    else:
        print "non-periodic input mesh detection skipped!"

    print "renormalizing..."
    coor = (coor * mscale) / scale
    print "saving..."
    mesh_out = make_mesh(coor, ngroups, conns, mesh_in)
    mesh_out.write(filename_out, io="auto")
    print "done."