5
$\begingroup$
114

Ge 11.184091389011632 8.1000459052469 7.912778504608498 0.7601333333333333
Ge 8.15544869153235 6.003103511684641 4.013838014930662 0.7568333333333334
Ge 9.485968612508206 8.750636482182767 3.89712476883384 0.5934333333333334
....

I want to change the number of atoms, preferably using Python where it will automatically find the number atom. Such as here, we have 8 atoms but it shows 114. Any lead how to do this edit automatically for different input files.

$\endgroup$
11
  • 2
    $\begingroup$ Please show the full xyz file. This has only 3 atoms, not 8. Also it has 4 columns of numbers rather than 3 (x,y,z). You want a program that takes an xyz file, and based on the number of rows representing atoms, puts the correct number at the top? $\endgroup$ Sep 6 at 4:33
  • 2
    $\begingroup$ Using bash script for these kind of tasks should be a lot easier. This can be done with bash by: nlines=`wc -l test.xyz | awk '{print $1}'`; natoms=$((nlines-2)); sed -i "1s/.*/$natoms/" test.xyz $\endgroup$ Sep 6 at 6:31
  • $\begingroup$ It seems that this question, with a little rephrasing, might find better and more numerous answers on a SE specifically dedicated to coding. It involves no specific molecular modeling knowledge and could be easily described as a generic coding problem $\endgroup$ Sep 7 at 5:39
  • 2
    $\begingroup$ @BarbaudJulien I disagree with this statement. Matter modeling SE is all matters modeling, which includes computer programming. If you seek to understand more about the chemistry of the topic then I might suggest Chemistry SE. However, only if you have a fundamental and obscure computer programming question, or if the question isn’t receiving enough attention would I recommend SO. $\endgroup$
    – Cody Aldaz
    Sep 7 at 9:08
  • 1
    $\begingroup$ @NikeDattani Done! $\endgroup$ Sep 9 at 9:47
5
$\begingroup$

You could do this by just modifying the first line of the file.

But here are some more general purpose utilities you could use (note it requires the re module)

def read_xyz(
    filename, 
    scale=1.):

    """ Read xyz file

    Params:
        filename (str) - name of xyz file to read

    Returns:
        geom ((natoms,4) np.ndarray) - system geometry (atom symbol, x,y,z)

    """
    
    lines = open(filename).readlines()
    lines = lines[2:]
    geom = []
    for line in lines:
        mobj = re.match(r'^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$', line)
        geom.append((
            mobj.group(1),
            scale*float(mobj.group(2)),
            scale*float(mobj.group(3)),
            scale*float(mobj.group(4)),
            ))
    return geom
def write_xyz(
    filename, 
    geom, 
    comment=0,
    scale=1.0 #(1.0/units.ANGSTROM_TO_AU),
    ):

    """ Writes xyz file with single frame

    Params:
        filename (str) - name of xyz file to write
        geom ((natoms,4) np.ndarray) - system geometry (atom symbol, x,y,z)

    """
    fh = open(filename,'w')
    fh.write('%d\n' % len(geom))
    fh.write('{}\n'.format(comment))
    for atom in geom:
        fh.write('%-2s %14.6f %14.6f %14.6f\n' % (
            atom[0],
            scale*atom[1],
            scale*atom[2],
            scale*atom[3],
            ))

If you read the file and then write the file it will automatically save it with the correct number of atoms.

$\endgroup$
2
  • 2
    $\begingroup$ isn't using regex a little overkill when you could just do line.split()? $\endgroup$
    – will
    Sep 6 at 12:05
  • 2
    $\begingroup$ I'd recommend the line.split() version. I'd also point out that this particular file includes what I suspect are partial charges in the last column, and the poster may want to preserve that. $\endgroup$ Sep 7 at 16:07
3
$\begingroup$

More a comment than an answer, note that e.g., for methane

5

C          0.92745       -0.05402        0.04264
H          2.01965       -0.05402        0.04264
H          0.56338        0.81142        0.60065
H          0.56338       -0.96998        0.51313
H          0.56338       -0.00348       -0.98585

the first line including 5 (in this example) announces how many atoms will follow past the second line which may be used for comments (like the name of structure/molecular weight as a label-like e.g., OpenBabel does). Thus keep this integer consistent with the content.

$\endgroup$
3
$\begingroup$

It should be easy to achieve what you want with a bash script. For a file named test.xyz, it can be achieved with:

fname=test.xyz
nlines=`wc -l $fname | awk '{print $1}'`
natoms=$((nlines-2))
sed -i "1s/.*/$natoms/" $fname

This follows the logic given in the answer by @Prasanta. It should be easy to change this to a script taking the filename as input so that you can do the same with many input files.

$\endgroup$
2
$\begingroup$

This is a strange type question. First, there is something wrong with the xyz file having total 5 columns. For you answer,

  1. Find total row number (let it be r)
  2. calculate r-2 (since the format of the xyz is that after the total number of atoms, there is a gap followed by atomic coordinates. The end of atomic coordinate specifications ends the file)
  3. replace first line(row) with r-2 value.

You either do it with bash or python you like.

$\endgroup$
2
  • 4
    $\begingroup$ There are plenty of "extensions" to XYZ through adding extra columns. If I had to guess, this is "symbol, x, y, z, partial charge" which is one of the more common variants. $\endgroup$ Sep 7 at 16:05
  • $\begingroup$ I am sorry, I did not have any idea about that. $\endgroup$ Sep 13 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.