0

I have a file that looks like this:

;
[ atomtypes ]
  opls_BZCG BCG1    78.113999   0.000   A   2.9310E-01  1.9173E-01
[ moleculetype ]
; Name      nrexcl
BZCG        1
[ atoms ]
;   nr  type    resnr   residue atom    cgnr    charge  mass
    1   opls_BZCG   1       BZCG    BCG1        1       0       78.113999

I am trying to use python to change the values in the second last and last field under the [ atomtypes ] title. The deal is that I am running a code which iteratively updates this file, so I specifically want that field to be targeted, not the regular expression "2.931E-01" or "1.9173E-01". I know we can use things like awk, but I was wondering if this is possible from python itself.

This is what I am doing so far:

flag = 0
with open("file.itp") as f: 
  for line in f:
     iterable = line.strip().split()
        if flag:
            line.strip().split()[5] = sigma 
            line.strip().split()[6]) = eps 
            print("epsilon is {} and sigma is {}".format(eps, sigma))
        if "atomtypes" in iterable:
            flag = 1
        else:
            flag = 0

    f.close()

I am changing the value in python, but I am not able to send that change to the file itself. How do I pull this off?

Any advice you have would be appreciated!

megamence
  • 335
  • 2
  • 10
  • I'm not sure about the file format that you're trying to update. However, if you're dealing with a .txt file probably splitting each line may work in my opinion. – Ethan Mar 17 '21 at 23:09
  • So I load the entire file, change the 2 numbers, and move on?@TahaJaliliTATI – megamence Mar 17 '21 at 23:13
  • There is no need to load the entire file, you can parse it line by line: https://stackoverflow.com/a/8010133/2237151 – Pietro Mar 17 '21 at 23:21
  • @Pietro, so I go line by line, I perform line.strip().split(), I change the two numbers... but how do I send this information back to the file? I want to change the numbers and update the file itself. – megamence Mar 17 '21 at 23:41
  • You have to write it to a new file with a temporary name, then when you're done, delete the old and rename the new into place. – Tim Roberts Mar 17 '21 at 23:54

1 Answers1

1

Use enumerate on lines so we can access current line and next line

Code

def update_line(filenm, eps, sigma):
    with open(filenm, 'r') as fin:
        lines = fin.readlines()
        
        for idx, line in enumerate(lines):
            if "atomtypes" in line:
                # Current line has marker, so change next line (i.e. index idx + 1)
                #   Split next line into fields 
                #   split from end so so only have three fields, namely:
                #    1) everything before next to last field, 
                #    2) next to last field, 
                #    3) last field)
                arr = lines[idx+1].rsplit(' ', maxsplit = 3)
                arr[-3], arr[-1] = f"{eps:e}", f"{sigma:e}"
                lines[idx+1] = ' '.join(arr) + "\n"  # last_val dropped the '\n' so add back
                break
        
    with open(filenm, 'w') as fout:
        # Updated lines placed back into file
        fout.writelines(lines)
    

Test

update_line('test.txt', 4.573133E-02, 8.2737123E-01)

File test.txt prior:

;
[ atomtypes ]
  opls_BZCG BCG1    78.113999   0.000   A   2.9310E-01  1.9173E-01
[ moleculetype ]
; Name      nrexcl
BZCG        1
[ atoms ]
;   nr  type    resnr   residue atom    cgnr    charge  mass
    1   opls_BZCG   1       BZCG    BCG1        1       0       78.113999

File test.txt after

;
[ atomtypes ]
  opls_BZCG BCG1    78.113999   0.000   A   4.573133e-02  8.273712e-01
[ moleculetype ]
; Name      nrexcl
BZCG        1
[ atoms ]
;   nr  type    resnr   residue atom    cgnr    charge  mass
    1   opls_BZCG   1       BZCG    BCG1        1       0       78.113999
DarrylG
  • 16,732
  • 2
  • 17
  • 23