示例#1
0
def makeVectors():
    '''return two unit vectors that are randomly distributed on a sphere
    with the condition that they are mutually perpendicular'''
    p1, p2 = [[gauss(0, 1) for i in range(3)] for j in range(2)]
    p3 = cross(p1, p2)
    norm1 = norm(p1)
    norm3 = norm(p3)
    p1 = [x / norm1 for x in p1]
    p3 = [x / norm3 for x in p3]
    return p1, p3
示例#2
0
    def offset(self, o):
        b = deepcopy(self)

        pt0 = perp2(b.t0)
        pt1 = perp2(b.t1)

        c1 = proj(b.bp[0])
        c2 = proj(b.bp[1])
        c3 = proj(b.bp[2])

        t2 = unit(c3 - c1)
        pt2 = perp2(t2)

        cc1 = unit(c2 - b.p0)
        cc2 = unit(b.p1 - c2)

        dp1 = dot(b.t0, cc1)
        dp2 = dot(b.t1, cc2)

        #t2  = unit(pt0 + refl(pt0,cc1))
        #t3  = unit(pt1 + refl(pt1,cc2))
        t2 = perp2(cc1)
        t3 = perp2(cc2)

        b.p0 = b.p0 + o * pt0
        b.p1 = b.p1 + o * pt1

        c2 = c2 + o * pt2
        c1 = c1 + o / dp1 * t2
        c3 = c3 + o / dp2 * t3

        w1 = b.bp[0][2]  #dot( b.t0,unit(c2 - b.p0))
        w2 = b.bp[2][2]  #dot( b.t1,unit(b.p1 - c2))
        w1 = dot(b.t0, cc1)
        w2 = dot(b.t1, cc2)

        alpha = norm(c1 - c2)
        beta = norm(c3 - c2)
        b.r = alpha / beta

        b.bp = (hom(c1, w1), hom(c2, 1), hom(c3, w2), alpha, beta)

        b.h1 = [hom(b.p0, 1), b.bp[0], b.bp[1]]
        b.h2 = [b.bp[1], b.bp[2], hom(b.p1, 1)]

        return b
示例#3
0
    def __enter__(self):
        self.f = self.func(self.X)
        f = array([self.f]).T
        self.J = self.Dfun(self.X)
        self.A = self.J.T.dot(self.J)
        self.g = -self.J.T.dot(f)
        I = identity(len(self.A))
        self.mu = self.tau*diag(self.A)*I        
        self.F0 = 0.5*f.T.dot(f)[0][0]
        self.append((self.iter, self.X, norm(self.f)))
	return self
示例#4
0
 def normalize_spfs(self):
     """Normalizes the spf vectors
     """
     for i in range(self.nel):
         ind = self.psistart[1,i]
         for j in range(self.nmodes):
             nspf = self.nspfs[i,j]
             npbf = self.npbfs[j]
             for k in range(nspf):
                 nrm = LA.norm(self.psi[ind:ind+npbf])
                 if abs(nrm) > 1.e-30:
                     self.psi[ind:ind+npbf] /= nrm
                 ind += npbf
示例#5
0
    def __enter__(self):
        self.f = self.func(self.X)
        f = array([self.f]).T
        self.J = self.Dfun(self.X)
        self.A = self.J.T.dot(self.J)
        self.g = -self.J.T.dot(f)
        self.mu = self.tau
        self.F0 = 0.5*f.T.dot(f)[0][0]
	
	X = self.X
	if len(self.bounds)<>0:
	    X = type(X)([f(x) for x, f in zip(X, self.box_contraints_transformation)])
	if len(self.scaling_of_variables)<>0:
	    X = [f.inverse(x) for x, f in zip(X, self.scaling_transformation)]
	self.append((self.iter, X, norm(self.f)))
	return self
示例#6
0
def biarc_r_from_arcs(a1, a2):
    alpha = norm(a1[0] - proj(a1[1]))
    beta = norm(a1[3] - proj(a1[4]))
    return alpha / beta
示例#7
0
 def check_qmr(self):
     bx0 = self.x0.copy()
     x, info = qmr(self.A, self.b, self.x0, callback=callback)
     assert_array_equal(bx0, self.x0)
     assert norm(dot(self.A, x) - self.b) < 5*self.tol
示例#8
0
		              (1.0 / self[k][k] * (A[i][k]  - s))
        except ValueError:
            raise LinAlgError('Matrix is not positive definite - Cholesky decomposition cannot be computed')
    def solve(self, b):
        n = len(b)
        c = [0.0 for i in xrange(n)]
        for i in xrange(n):
            c[i] = (b[i] - sum( self[i][k] * c[k] for k in xrange(i) )) / self[i][i]
        x = [0.0 for i in xrange(n)]
        for i in xrange(n-1, -1, -1):
            x[i] = (c[i] - sum( self[k][i] * x[k] for k in xrange(i+1, n) )) / self[i][i]
        return x
        	   
        
if __name__ == '__main__':
    
    A = array([[2, 1, 1, 3, 2],
               [1, 2, 2, 1, 1],    
               [1, 2, 9, 1, 5],    
               [3, 1, 1, 7, 1],    
               [2, 1, 5, 1, 8]], dtype=float)
    b = array([1, 1, 1, 1, 1], dtype=float)
    L = cholesky( A )

    X =  L.solve(b)
    from linalg import norm
    from libarray import *

    print 'Must be near 0: ', norm(A.dot(array([X]).T)- b)

示例#9
0
def fmin(func, x0, Dfun=None, gtol=1.0e-06, xtol=1.0e-04, maxfev=1000, maxiter=50, epsfcn=1e-6, damping=(10e-3, 2.0), verbose=True):
        with levmar(func, x0, Dfun=Dfun, gtol=gtol, xtol=xtol, maxfev=maxfev, maxiter=maxiter, epsfcn=epsfcn, damping=damping) as opt:
            if verbose:
                print 'Start Levenberg Marquart Optimizer...'
	        print '{step:>7}{x}{residual:>13}'.format(step='step', x='{:>13}'*len(x0), residual='residual').format(*('X[%d]'%i for i in xrange(len(x0))))
	        print '{step:>7}{x}{residual:>13.3e}'.format(step=0, x='{:>13.3e}'*len(x0), residual=norm(opt.f)).format(*x0)
	    while 1:
	        iter=0
	        try:
		    iter, X, residual = opt.next()
                    if verbose:
	                print '{step:>7}{x}{residual:>13.3e}'.format(step=iter, x='{:>13.3e}'*len(X), residual=residual).format(*X)
		except StopIteration, exit_message:
		    if verbose:
		        print '---------'
		        print 'Optimization terminated successfully.'
		        print '         Exit Message: %s'%(exit_message)
		        print '         Iterations: %d'%(iter)
			print '         Function evaluations: %d'%(opt.ifev)
		    break
示例#10
0
    def next(self):

	isJnull = self.checkJacobian()
	for i, f in enumerate(self.f):
	    if f == float('nan'):
	        raise LevMarError('The point %d is a Nan. The optimizer has been stopped.'%i)
	    
    
        # stopping criteria
        if norm(self.g.T[0])<self.gtol:
            raise StopIteration('Magnitude of gradient smaller than the \'gtol\' tolerance.')
        # increment iter
        self.iter += 1
        if self.iter>self.maxiter:
            raise StopIteration('Number of iterations exceeded \'maxiter\' or number of function evaluations exceeded \'maxfev\'.')
     
        
        # save previous state
        self.X0, self.A0, self.g0, self.f0 = self.X.copy(), self.A.copy(), self.g.copy(), self.f.copy(), 
	
        # compute dX
        I = identity(len(self.A))
        self.dX = array(solve(self.A + self.mu, self.g.T[0], verbose=False))
	
        # stopping criteria
        #if norm(self.dX)<self.xtol*(norm(self.X)+self.xtol):
        #    raise StopIteration()
	if not(False in [a<b for a, b in zip(abs(self.dX), self.xtol*(abs(self.X)+self.xtol))]):
            raise StopIteration('Change in x smaller than the \'xtol\' tolerance.')

        self.X = self.X + self.dX
        
        # compute f using the new X
        self.f = self.func(self.X)
        f = array([self.f]).T
        
        self.Fn = 0.5*f.T.dot(f)[0][0]
        
        dX = array([self.dX]).T
        self.dL = (0.5*(dX.T.dot(self.mu.dot(dX) + self.g)))[0][0]
	self.dF = self.F0-self.Fn
	
	if len(self.bounds):
	    isStepAcceptable = not(False in [min(bound)<=x<=max(bound) for x, bound in zip(self.X, self.bounds)])
	else:
	    isStepAcceptable = True
        
        # if step acceptable
        if ((self.dF>0 and self.dL>0) or (self.dF<0 and self.dL<0)) and isStepAcceptable:
            # compute jacobian, A and g
            self.J = self.Dfun(self.X)
            self.A = self.J.T.dot(self.J)
            self.g = -self.J.T.dot(f)

            # damp mu and update F0 parameter
            self.mu = self.mu*max(0.333333333, (1.0-(2.0*(self.dF/self.dL)-1.0)**3)/2.0)
            self.nu = self.damping[1]
            self.F0 = self.Fn
         
        else:
            # restore
            self.X, self.A, self.g, self.f = self.X0.copy(), self.A0.copy(), self.g0.copy(), self.f0.copy(), 
            # damp mu
            self.mu = self.mu*self.nu
            self.nu = 2.0*self.nu
                
        # save and return X and residual
        residual = norm(self.f)
        self.append((self.iter, self.X, residual))
        return self.iter, self.X, residual
示例#11
0
		except StopIteration, exit_message:
		    if verbose:
		        print '---------'
		        print 'Optimization terminated successfully.'
		        print '         Exit Message: %s'%(exit_message)
		        print '         Iterations: %d'%(iter)
			print '         Function evaluations: %d'%(opt.ifev)
		    break
        if verbose:
            print '         Best step:'
	    if len(opt):
	        iter, X, residual  = min(list(opt[i] for i in xrange(len(opt))), key=lambda step: step[2])
                print '{step:>7}{x}{residual:>13.3e}'.format(step=iter, x='{:>13.3e}'*len(X), residual=residual).format(*X)
	    else:
	        iter = 0; residual = 0.0; X=x0
                print '{step:>7}{x}{residual:>13}'.format(step=0, x='{:>13.3e}'*len(x0), residual=norm(opt.f)).format(*x0)
	if opt.traceback:
	    print 'LevMarError:', opt.traceback[1]
	if verbose:
	    print 
        return iter, X, residual


def fit(func, x0, xmeas, ymeas, gtol=1.0e-08, xtol=1.0e-06, maxfev=100, epsfcn=1e-8, damping=(10e-3, 2.0), verbose=True):
    def f(X, xmeas, ymeas):
        return array([(ymeas-func(x, *X))/ymeas for x in xmeas])
    return fmin(f, x0, Dfun=None, gtol=gtol, xtol=xtol, maxfev=maxfev, epsfcn=epsfcn, damping=damping, verbose=verbose)
    
    
        
    
示例#12
0
def makeRand():
    '''return a single unit vector randomly distributed on a sphere'''
    v1 = [gauss(0, 1) for i in range(3)]
    return [x / norm(v1) for x in v1]
示例#13
0
def makePerp(v1):
    '''return a random unit vector on a circle perpendicular to v1'''
    v2 = [gauss(0, 1) for i in range(3)]
    v3 = cross(v1, v2)
    return [x / norm(v3) for x in v3]
示例#14
0
def main(argv):

    # MPI init
    comm = MPI.COMM_WORLD

    rank = comm.Get_rank()
    size = comm.Get_size()

    # discretization object
    data.discretization = data.Discretization()
    discretization = data.discretization

    # arguments processing
    readcmdline(argv)

    # remove old files generated by write_binary function
    clean_directory(rank)
    comm.Barrier()

    # domain object (object per SubDomain)
    data.domain = data.SubDomain(rank, size, discretization, comm)
    domain = data.domain

    # redefine variables for shortening the code
    nx = domain.nx
    ny = domain.ny
    nt = discretization.nt

    # iteration parameters
    max_cg_iters = 200
    max_newton_iters = 50
    tolerance = 1.e-6

    # message of beginning
    if domain.rank == 0:
        print(
            "========================================================================"
        )
        print("Welcome to mini-stencil!")
        print("Version   :: Python 3 with MPI4Py: " + str(domain.size) +
              " MPI ranks")
        print("Mesh      :: " + str(discretization.nx) + " * " +
              str(discretization.ny) + " dx = " + str(discretization.dx))
        print("Iteration :: " + "CG " + str(max_cg_iters) + ", Newton " +
              str(max_newton_iters) + ", tolerance " + str(tolerance))
        print(
            "========================================================================"
        )

    # details of the cartesian division of the processors
    if domain.rank == 0:
        print("Cartesian division details for each processor (subdomain)\n")
    domain.print()

    if domain.rank == 0 and data.verbose_output:
        print(
            "========================================================================"
        )
        print("Verbose output\n")

    # solution matrices
    # ny = ROW and nx = COLUMN (!! VERY IMPORTANT !!)
    data.x_new = np.zeros((ny, nx), dtype=np.float64)
    data.x_old = np.zeros((ny, nx), dtype=np.float64)

    # boundary vectors
    # initialized on 0 (dirichlet boundary condition)
    data.bndN = np.zeros((1, nx), dtype=np.float64)
    data.bndS = np.zeros((1, nx), dtype=np.float64)
    data.bndE = np.zeros((1, ny), dtype=np.float64)
    data.bndW = np.zeros((1, ny), dtype=np.float64)

    # buffer vectors for exchanging boundary information
    # they act as temporary dataholders for exchange
    data.buffN = np.zeros((1, nx), dtype=np.float64)
    data.buffS = np.zeros((1, nx), dtype=np.float64)
    data.buffE = np.zeros((1, ny), dtype=np.float64)
    data.buffW = np.zeros((1, ny), dtype=np.float64)

    # Ax = b with b being 0 in the initial condition
    b = np.zeros((ny, nx), dtype=np.float64)
    # solution for conjugate gradient function
    deltax = np.zeros((ny, nx), dtype=np.float64)

    # convergence
    if domain.rank == 0:
        con = np.zeros((0),
                       dtype=np.float64)  # convergence of the last iteration
        res = np.empty((nt), dtype=np.float64)  # residual of each timestep

    if (data.custom_init):

        for i in data.discretization.points:

            x = i[0]
            y = i[1]
            s = i[2]

            if (x >= (domain.startx) and x <= (domain.endx) and y >=
                (domain.starty) and y <= (domain.endy)):
                x -= (domain.startx)
                y -= (domain.starty)

                data.x_new[y, x] = s

    else:

        # Default initial condition (!! PROPORTIONAL TO THE GRID SIZE !!)
        # A circle of concentration 0.1 centred at (xdim/4, ydim/4)
        # with radius no larger than 1/8 of both xdim and ydim
        # x lenght is always one while y lenght is variable depending on the dimensions
        xc = 1.0 / 4.0
        yc = (discretization.ny - 1) * discretization.dx / 4.0
        # min ensure that radius will be not larger than 1/8 of xdim or ydim
        radius = min(xc, yc) / 2.0

        # Startx and starty begins artificially to count from 1 but it is actually 0
        for j in range(domain.starty, domain.endy + 1):

            # (j - 1) displace the circle slightly on the upper right of the domain
            # instead of being in the corner
            y = (j) * discretization.dx

            for i in range(domain.startx, domain.endx + 1):

                # (i - 1) displace the circle slightly on the upper right of the domain
                # instead of being in the corner
                x = (i) * discretization.dx

                # Test if grid point is inside circle
                # Actually the circle only lies in the (0, 0) domain
                if ((x - xc) * (x - xc) + (y - yc) *
                    (y - yc)) < (radius * radius):
                    data.x_new[j - domain.starty][i - domain.startx] = 0.1

    # Start time before solving the system
    start_time = time.time()

    # Main timeloop
    for timestep in range(1, nt + 1):

        # x_old = x_new
        # get back the solution of previous timestep
        # to compute the solution of the actual timestep
        data.x_old[:] = data.x_new

        # new residual at each time step
        residual = 0.0
        converged = False

        # newton iterations used to solve a system of non linear equations
        it = 0
        for it in range(0, max_newton_iters):

            # we get b in Ax = b by using the diffusion function
            # b = f(x_n)
            operators.diffusion(data.x_new, b, timestep, it)

            # residual of newton methods
            residual = linalg.norm(b)

            # for plotting convergence of the newton methods
            if domain.rank == 0 and timestep == nt:
                con = np.append(con, residual)

            if residual < tolerance:
                converged = True
                break

            # solve linear system to get deltax
            # Ax = b where A is J(x) and x deltax (we already have b)
            # we have to calculate the Jacobian and then solve to get deltax
            # J(x) * deltax = f(x)
            cg_converged = False
            cg_converged = linalg.cg_solver(deltax, b, max_cg_iters, tolerance,
                                            cg_converged)

            # Check that the CG solver converged
            if not cg_converged:
                break

            # x_new = x_new - deltax
            # deltax = f(x_n)/f'(x_n) = f(x_n) * J^-1(x)
            # deltax got from cg_converged function
            data.x_new -= deltax

        # stats for printing results
        data.iters_newton += it + 1

        # Verbose mode (output stats at each Newton iteration)
        if converged and data.verbose_output:
            print("Step " + str(timestep) + " required " + str(it) +
                  " iterations for residual " + str(residual))

        if not converged:
            print("Step " + str(timestep) +
                  " ERROR : nonlinear iterations failed to converge")
            break

        # final residual for a series of newton iteration for each timestep
        if domain.rank == 0:
            res[timestep - 1] = residual

    # total computational time for getting the solution
    timespent = time.time() - start_time

    # Avoid polluating printed output
    time.sleep(0.2)

    # final results printed
    if (domain.rank == 0):
        print(
            "--------------------------------------------------------------------------------"
        )
        print("Simulation took " + str(timespent) + " seconds")
        print(
            str(data.iters_cg) +
            " conjugate gradient iterations, at rate of " +
            str(data.iters_cg / timespent) + " iters/second")
        print(str(data.iters_newton) + " newton iterations")
        print(str(data.flops_count) + " floating point operations")
        print(
            "--------------------------------------------------------------------------------"
        )
        print("Goodbye !")

    # write final solution to BIN file for visualization
    # wld way used in the old c version
    # wept and modified for showing how to write in one file with MPI
    if data.printed_output:
        filename = write_binary("output", data.x_old, domain, discretization)
        read_binary(filename, domain, discretization)

    # interactive visualization of the final solution
    # all the subdomains solutions are merged into one matrix using MPI
    if data.interactive_output or data.printed_matrix:

        # merged results from all subdomains
        result = merge_solution(discretization, domain)

        # print final matrix result in txt file
        if data.printed_matrix and domain.rank == 0:
            print("output.txt generated in current directory !")
            np.savetxt("./output.txt", result)

        # generate interactive visualization
        if data.interactive_output and domain.rank == 0:
            print(
                "(Close the python interactive windows to stop the program.)")
            plot_solution(result)
            plot_convergence(con)
示例#15
0
    def next(self):

	isJnull = self.checkJacobian()
	if 0 in isJnull:
	    print LevMarWarning('The Jacobian is rank deficient.')
	
	if nan in self.f:
            raise LevMarError('One point of \'f\' is a Nan. The optimizer has been stopped.')

        # stopping criteria
        if norm(self.g)<self.gtol:
            raise StopIteration('Magnitude of gradient smaller than the \'gtol\' tolerance.')
	
        # increment iter
        self.iter += 1
        if self.iter>self.maxiter:
            raise StopIteration('Number of iterations exceeded \'maxiter\' or number of function evaluations exceeded \'maxfev\'.')
     
        # save previous state
        self.X0 = self.X.copy()
	self.A0 = self.A.copy()
	self.g0 = self.g.copy()
	self.f0 = self.f.copy()
	
        # compute dX
        I = identity(len(self.A))
	A = self.A
	mu = self.mu
	g = self.g
	
	def geth(A, g, mu):
	    mA = max(abs(A.flatten()))
	    for i in xrange(5):
	        try:
		    I = identity(len(A))
		    L = chol(A + mu*diag(A)*I)
		    h = L.solve(g)
		    return array(h), mu
		except LinAlgError:
		    mu = max(10.0*mu, 1e-15*mA)
            raise LevMarError('The matrix A + mu*diag(A) is not positive. The optimizer has been stopped.')
	    
        #self.dX = array(solve(A + mu*diag(A)*I, g.T[0]))
	self.dX, self.mu = geth(A, g.T[0], mu)
	
        # stopping criteria
        if norm(self.dX)<self.xtol*(norm(self.X)+self.xtol):
            raise StopIteration('Change in x smaller than the \'xtol\' tolerance.')

        self.X = self.X + self.dX
        
        # compute f using the new X
        self.f = self.func(self.X)
        f = array([self.f]).T
        dX = array([self.dX]).T
	
        self.Fn = 0.5*f.T.dot(f)[0][0]
        
	# Using the state A, mu, g, h and considering a Taylor expansion model L, the trust region dL = L(h)-L(0) is calculated.
	# then dF/dL is the gain of the trust region. dL is positive
        self.dL = 0.5*dX.T.dot((self.mu*diag(self.A)*I).dot(dX) + self.g)[0][0]
	self.dF = self.F0-self.Fn
	
        # if step acceptable, dF is sometimes null due to machine accuracy
        if self.dF>0 and self.dL>0 :
            # compute jacobian, A and g
            self.J = self.Dfun(self.X)
            self.A = self.J.T.dot(self.J)
            self.g = -self.J.T.dot(f)

            # damp mu and update F0 parameter
            self.mu = self.mu*max(1.0/3.0, (1.0-(2.0*(self.dF/self.dL)-1.0)**3)/2.0)
            self.nu = self.damping[1]
            self.F0 = self.Fn
	    
	    if norm(self.g0-self.g) < self.gtol:
                raise StopIteration('Change in g smaller than the \'gtol\' tolerance.')

        else:
            # restore
            self.X = self.X0.copy()
	    self.A = self.A0.copy()
	    self.g = self.g0.copy()
	    self.f = self.f0.copy()
            # damp mu
            self.mu = self.mu*self.nu
            self.nu = 2.0*self.nu


        # save and return X and residual
        residual = norm(self.f)
	
	X = self.X
	if len(self.bounds)<>0:
	    X = type(X)([f(x) for x, f in zip(X, self.box_contraints_transformation)])
	if len(self.scaling_of_variables)<>0:
	    X = [f.inverse(x) for x, f in zip(X, self.scaling_transformation)]

	self.append((self.iter, X, residual))
	return self.iter, X, residual
示例#16
0
def proc_orient(line, inFile, fragDict):
    '''
    This is called when a line containing '!!orient' is read from inFile.
    It continues reading inFile until reaching the line '!!oend'. It parses the
    arguments on the !!orient line, adds lines for the dummy atoms used to 
    orient the fragment, and then stores the rest of the lines in the !!orient
    block. If the centroid coordinates were not given, it calculates them from
    the atoms it reads. It returns a template with placeholders for the dummy
    atoms and a Namespace containing the !!orient arguments.
    '''

    # Process the !!orient line. Find the correct FRAG block from fragDict and
    # add dummy atoms to it. Store this modified FRAG block.
    orientArgs = parse_instructions(line)
    fragLines = make_frag(fragDict[orientArgs.frag])

    dummyAtoms = [
        'afix 99{}\n'.format(orientArgs.afix),
        'REM !! To remove the dummy atoms while preserving the rest of\n'
        'REM !! the model, simply refine this model in ShelXL and delete\n'
        'REM !! the lines from here through "PERP 1 ..." from the \n'
        'REM !! resulting .res file.\n'
        'part -1 10.0 !!ornt\n', 'cent 1 cent_xyz 10 10.02 !!ornt\n',
        'pivt 1 pivt_xyz 10 10.02 !!ornt\n',
        'perp 1 perp_xyz 10 10.02 !!ornt\n'
    ]

    # Read and process lines until !!oend. Atoms are saved to atomMatchList and
    # their coordinates are changed to 0 0 0. All other lines are unchanged.
    # All lines are written to the list orientLines.
    atomMatchList, orientLines = [], []
    while True:
        atomMatch = atomRE.match(line)
        if atomMatch and not line[0].upper() in shelxWords:
            atomMatchList.append(atomMatch)
            line = atomMatch.group(1) + ' 0 0 0 11 {}\n'.format(
                orientArgs.uiso)
        if line.lower().startswith('!!oend'):
            orientLines.append('afix 0\n')
            break
        orientLines.append(line)
        line = inFile.readline()

    # If the centroid was given on the !!orient line, then we name it here;
    # otherwise calculate it from the atoms within the orient...oend block.
    # If the centroid is on 0,0,0 then we nudge it slightly so that ShelXL
    # treats it as a real position.
    if orientArgs.x is not None:
        cent = [orientArgs.x, orientArgs.y, orientArgs.z]
    else:
        xyzArray = [[0, 0, 0] for i in range(len(atomMatchList))]
        for i in range(len(atomMatchList)):
            xyzArray[i] = [
                float(atomMatchList[i].group(j)) for j in range(2, 5)
            ]
        cent = centroid(xyzArray)
    if norm(cent) < 0.001: cent = vec_sum(cent, [.001, .001, .001])
    orientArgs.x, orientArgs.y, orientArgs.z = cent[0], cent[1], cent[2]
    orientArgs.cent = cent

    outLines = fragLines + dummyAtoms + orientLines
    return outLines, orientArgs