Coverage for model_workflow/tools/get_charges.py: 65%
69 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 10:54 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 10:54 +0000
1import pytraj as pt
3from json import load
5from model_workflow.utils.auxiliar import MISSING_TOPOLOGY, MISSING_CHARGES, load_json
6from model_workflow.utils.constants import STANDARD_TOPOLOGY_FILENAME, RAW_CHARGES_FILENAME
7from model_workflow.utils.gmx_spells import get_tpr_charges as get_tpr_charges_gromacs
8from model_workflow.utils.type_hints import *
10from MDAnalysis.topology.TPRParser import TPRParser
11from MDAnalysis.topology.TOPParser import TOPParser
13def get_charges (topology_file : Union['File', Exception],
14 resorted_charges_file : Optional['File'] = None) -> List[float]:
15 """
16 Extract charges from a source file.
18 Returns:
19 List[float]: A list of atomic charges if extraction is successful,
20 otherwise None if the file does not exist.
22 """
23 # If we have a resorted file then use it
24 # Note that this is very excepcional
25 if resorted_charges_file and resorted_charges_file.exists:
26 print(' Using resorted atom charges')
27 return load_json(resorted_charges_file.path)
28 # If there is no topology at all
29 if topology_file == MISSING_TOPOLOGY or not topology_file.exists:
30 print(' No charges source file available')
31 return MISSING_CHARGES
32 print(f' Charges in the "{topology_file.path}" file will be used')
33 charges = None
34 # If we have the standard topology then get charges from it
35 if topology_file.filename == STANDARD_TOPOLOGY_FILENAME:
36 with open(topology_file.path, 'r') as file:
37 standard_topology = load(file)
38 charges = standard_topology['atom_charges']
39 # In some ocasions, charges may come inside a raw charges file
40 elif topology_file.filename == RAW_CHARGES_FILENAME:
41 charges = get_raw_charges(topology_file.path)
42 # In some ocasions, charges may come inside a topology which can be parsed through pytraj
43 elif topology_file.is_pytraj_supported():
44 charges = get_topology_charges(topology_file.path)
45 # DANI: De momento ya no generaré más charges.txt ahora que las cargas estan en la topologia json
46 #generate_raw_energies_file(charges)
47 elif topology_file.format == 'tpr':
48 charges = get_tpr_charges(topology_file.path)
49 else:
50 raise ValueError(f'Charges source file ({topology_file.path}) is in a non supported format')
51 return charges
53# Given a topology which includes charges
54# Extract those charges and save them in a list to be returned
55# Use different tools, since ones may fail where others success
56# Note that this not a matter of the format only, but also of the format version
57# There are different versions of .top files, for instance
58def get_topology_charges (topology_filename : str) -> list:
59 try:
60 topology_charges = get_topology_charges_pytraj(topology_filename)
61 except Exception as err:
62 print(err)
63 print('The canonical charges mining (pytraj) failed. Retrying with alternative mining (mdanalysis)')
64 topology_charges = get_topology_charges_mdanalysis(topology_filename)
65 return topology_charges
67# Get topology charges using pytraj
68# Supported formats (tested): prmtop, top, psf (standard psf, not from DESRES)
69# Supported formats (not tested): mol2, cif, sdf
70# Non supported formats: mae, tpr, pdb (has no charges)
71def get_topology_charges_pytraj (topology_filename : str) -> list:
72 topology = pt.load_topology(filename=topology_filename)
73 # WARNING: We must convert this numpy ndarray to a normal list
74 # Otherwise the search by index is extremly ineficient
75 topology_charges = list(topology.charge)
76 return topology_charges
78# Get topology charges using mdanalysis
79def get_topology_charges_mdanalysis (topology_filename : str) -> list:
80 parser = TOPParser(topology_filename)
81 topology = parser.parse()
82 charges = list(topology.charges.values)
83 return charges
85# Write the raw charges file from a list of charges
86def generate_raw_energies_file (charges : list, filename : str = RAW_CHARGES_FILENAME):
87 with open(filename, 'w') as file:
88 for charge in charges:
89 file.write("{:.6f}".format(charge) + '\n')
91# Given a raw file with listed charges
92# Extract those charges and save them in a list to be returned
93def get_raw_charges (topology_filename : str) -> list:
94 charges = []
95 with open(topology_filename, 'r') as file:
96 lines = file.readlines()
97 for line in lines:
98 charges.append(float(line))
99 return charges
101# Given a tpr file, extract charges in a list
102# Try 2 different methods and 1 of them should work
103def get_tpr_charges (topology_filename : str) -> list:
104 try:
105 charges = get_tpr_charges_mdanalysis(topology_filename)
106 except:
107 print(' MDAnalysis failed to extract charges. Using manual extraction...')
108 charges = get_tpr_charges_gromacs(topology_filename)
109 return charges
111# This works for the old tpr format (tested in 112)
112def get_tpr_charges_mdanalysis (topology_filename : str) -> list:
113 parser = TPRParser(topology_filename)
114 topology = parser.parse()
115 charges = list(topology.charges.values)
116 return charges