Files
PlantAI-dev/tools/pymol-open-source/modules/chempy/charge.py
T
2026-08-03 18:42:47 +08:00

136 lines
4.0 KiB
Python

#A* -------------------------------------------------------------------
#B* This file contains source code for the PyMOL computer program
#C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific.
#D* -------------------------------------------------------------------
#E* It is unlawful to modify or remove this copyright notice.
#F* -------------------------------------------------------------------
#G* Please see the accompanying LICENSE file for further information.
#H* -------------------------------------------------------------------
#I* Additional authors of this source file include:
#-*
#-*
#-*
#Z* -------------------------------------------------------------------
import copy
def combine_fragments(*arg,**kw):
'''
merge_fragments(target,source1,source2,source3,...)
WARNING: This is not how you *should* combine fragments,
rather this is just a convenient kludge for getting
something remotely realistic in a big hurry.
NOTE: atom names must be unique throughout -- especially
including the "capping" atoms used during the ab-initio
calculations (you can use PyMOL to rename these if they
happen to coincide).
'''
if 'net_charge' in kw:
net_charge = kw['net_charge']
else:
net_charge = None
if len(arg)<1:
raise TypeError('invalid arguments')
dst = copy.deepcopy(arg[0])
frg_lst = arg[1:]
n_frg = len(frg_lst)
n_dst_atm = len(dst.atom)
# create dictionary/indices for shared atoms
n_tot = 0
dst_dict = {}
for a in dst.atom:
sig = a.name
dst_dict[sig] = n_tot
n_tot = n_tot + 1
# create fragment membership list for destination atoms
members = []
for a in range(n_tot):
members.append([])
# create indices for unique atoms
for fragment in frg_lst:
c = 0
for a in fragment.atom:
sig = a.name
if sig in dst_dict:
a.chg_index = dst_dict[sig]
members[a.chg_index].append(fragment)
else:
# find an attached atom that *is* in the destination structure
attached_index = None
for b in fragment.bond:
attached = None
if b.index[0]==c:
attached = fragment.atom[b.index[1]]
elif b.index[1]==c:
attached = fragment.atom[b.index[0]]
if attached is not None:
if attached.name in dst_dict:
attached_index = dst_dict[attached.name]
break
a.chg_index = n_tot
if attached_index is not None:
a.attached_index = attached_index
n_tot = n_tot + 1
c = c + 1
# create array for charges
chg = []
for a in range(n_frg):
chg.append([0.0] * n_tot)
# now load and count measurements
cnt = [0] * n_tot
c = 0
for fragment in frg_lst:
for a in fragment.atom:
index = a.chg_index
if (index < n_dst_atm):
chg[c][index] = chg[c][index] + a.partial_charge
cnt[index] = cnt[index] + 1
else:
aindex = a.attached_index
chg[c][aindex] = chg[c][aindex] + a.partial_charge
c = c + 1
# now compute average charges for each destination atom
avg = []
for index in range(n_dst_atm):
if cnt[index]:
tmp_lst = []
for a in chg:
tmp_lst.append(a[index])
avg.append(sum(tmp_lst)/cnt[index])
else:
avg.append(0.0)
# correct total charge
chg_sum = sum(avg)
print("chg_sum",chg_sum)
if net_charge is not None:
chg_diff = net_charge - chg_sum
chg_adjust = chg_diff / n_dst_atm
else:
chg_adjust = 0.0
c = 0
for a in dst.atom:
a.partial_charge = avg[c] + chg_adjust
c = c + 1
return dst