Icon representing a recipe

Recipe: ListNetworks1

created by jeff101

Profile


Name
ListNetworks1
ID
104741
Shared with
Public
Parent
None
Children
None
Created on
April 18, 2021 at 19:11 PM UTC
Updated on
April 18, 2021 at 19:11 PM UTC
Description

*1c.txt 4/18/2021 1246pm noon code

Best for


Code


-- HBonds1 begun 4/17/2021 by jeff101. -- Renamed to ListNetworks1 4/18/2021. -- Last updated 4/18/2021 1246pm noon. -- -- Below lists all global variables. aas={} -- will hold 3-letter codes -- and full names for each aa aas.a={'ala','alanine'} aas.c={'cys','cysteine'} aas.d={'asp','aspartate'} aas.e={'glu','glutamate'} aas.f={'phe','phenylalanine'} aas.g={'gly','glycine'} aas.h={'his','histidine'} aas.i={'ile','isoleucine'} aas.k={'lys','lysine'} aas.l={'leu','leucine'} aas.m={'met','methionine'} aas.n={'asn','asparagine'} aas.p={'pro','proline'} aas.q={'gln','glutamine'} aas.r={'arg','arginine'} aas.s={'ser','serine'} aas.t={'thr','threonine'} aas.v={'val','valine'} aas.w={'trp','tryptophan'} aas.x={'unk','unknown'} aas.y={'tyr','tyrosine'} bbstr='ncco' -- atoms 1-4 for most AA's. scstr={} -- will hold single-letter atom names -- for atom #'s 5 and up (not including H's) -- on non-terminal amino acids. -- atoms 1-4 for all AA's should be ncco -- (atom 1 is nitrogen, 2 is the alpha-carbon) -- (3 is the carbonyl carbon in C=O, 4 is oxygen). -- atom 5 for C-terminal (highest seg #) is O, -- so the ones listed below become 6 and up. -- seg #1 (N-terminal) has 2 extra H's, but -- they don't matter here. scstr.a='c' scstr.c='cs' scstr.d='ccoo' scstr.e='cccoo' scstr.f='ccccccc' scstr.g='' -- has backbone + atom 5 = h scstr.h='ccnccn' -- correct for both his types? scstr.i='cccc' scstr.k='ccccn' scstr.l='cccc' scstr.m='ccsc' scstr.n='ccon' scstr.p='ccc' scstr.q='cccon' scstr.r='cccncnn' scstr.s='co' scstr.t='coc' scstr.v='ccc' scstr.w='ccccnccccc' scstr.x='?' -- for unknown sc's. not really used scstr.y='ccccccco' -- Above lists all global variables. -- -- Below lists all functions. -- Main() below was inspired by the sample code given at: -- https://foldit.fandom.com/wiki/Foldit_Lua_Function_structure.GetHBonds -- For more details about other Foldit Lua Functions see: -- https://foldit.fandom.com/wiki/Foldit_Lua_Functions -- function Main() local nmon,nseg,aa1,ss1,aa2,ss2 local seg1,seg2,seg2o,atom1,atom2,mon1,mon2 local isdis,score1,score2,dist,width local atype1,atype2,btype1,btype2,bway,listit local fnams,fison,nf,ff,scoreA,scoreB local mssg,bonds,nbonds,bnum,tots -- nmon is number of monomers nmon=structure.GetSymCount() -- nseg is number of segments/monomer nseg=structure.GetCount() bonds=structure.GetHBonds() nbonds=(#bonds) -- # of bonds -- print('Running some tests:') print(' round2( 3.445)='..round2( 3.445)..'.') print(' round2( 3.444)='..round2( 3.444)..'.') print(' round2(-3.444)='..round2(-3.444)..'.') print(' round2(-3.445)='..round2(-3.445)..'.') print(' round3( 3.4475)='..round3( 3.4475)..'.') print(' round3( 3.4474)='..round3( 3.4474)..'.') print(' round3(-3.4474)='..round3(-3.4474)..'.') print(' round3(-3.4475)='..round3(-3.4475)..'.') print(' ') -- -- below records settings of filters -- then enables them all. can it record -- which filters are showing too? fnams=filter.GetNames() -- get names of filters nf=(#fnams) -- # of filters fison={} -- 1 for enabled filters, 0 for disabled ones for ff=1,nf do if filter.IsEnabled(fnams[ff]) then fison[ff]=1 else -- filter is disabled fison[ff]=0 end -- if filter end -- for ff filter.EnableAll() -- below gets score with all bonuses scoreA=current.GetEnergyScore() -- below disables all filters filter.DisableAll() -- below gets score with no bonuses scoreB=current.GetEnergyScore() -- below restores to original filter settings. -- can it restore which filters were shown too? -- 4/18/2021 seems disabling a filter quits -- displaying it, but re-enabling a filter -- does not re-display it. for ff=1,nf do if fison[ff]==1 then filter.Enable(fnams[ff]) end -- if fison end -- for ff -- print(string.format('Score=%.3f Bonus=%.3f=%.3f HBN=%.3f has', trunc3(scoreA), round3(scoreA-scoreB),round3(filter.GetBonusTotal()), round3(filter.GetBonus('Hydrogen Bond Network')))) print(string.format(' %d monomers (original + %d copies), each w/%d segments.', nmon+1,nmon,nseg)) print('There are '..nbonds..' bonds involving copy 0') print(' (the original monomer), as listed below.') print('Width (wid) = 0.25 A (bad) to 0.75 A (good).') print(' {') tots={} for bway=1,3 do tots[bway]=0 if bway==1 then print('Ones between 2 backbone atoms on the same monomer (bway=1):') elseif bway==2 then print('Ones involving 1-2 sidechain atoms on the same monomer (bway=2):') else print('Ones between atoms on 2 different monomers (bway==3):') print('Some bonds between monomers are repeats by symmetry.') end print(' {') for bnum=1,nbonds do seg1=bonds[bnum]["res1"] seg2o=bonds[bnum]["res2"] -- 4/17/2021 It seems like seg1 <= seg2o always holds. atom1=bonds[bnum]["atom1"] atom2=bonds[bnum]["atom2"] width=bonds[bnum]["width"] -- 0.25 A (bad) to 0.75 A (good) mon1=0 -- This should always hold -- since the original monomer is copy 0. mon2,seg2=getmonsig(seg2o,nseg) -- If mon2 > 0, seg2 < seg1 <= seg2o can hold. -- 4/17/2021 Seems can get seg1 seg2 in any -- order vs each other, and some pairs -- can even be repeats of each other. aa1=structure.GetAminoAcid(seg1) aa2=structure.GetAminoAcid(seg2) atype1,btype1=gettype(nseg,seg1,atom1,aa1) atype2,btype2=gettype(nseg,seg2,atom2,aa2) listit=0 if mon1~=mon2 then -- bond is between atoms on 2 diff monomers if bway==3 then listit=1 end -- if bway elseif btype1=='sc' or btype2=='sc' then -- bond is between 1 or more sc atoms on the same monomer if bway==2 then listit=1 end -- if bway else -- btype1=='bb' and btype2=='bb' -- bond is between 2 bb atoms on the same monomer if bway==1 then listit=1 end -- if bway end -- if mon1 if listit==1 then tots[bway]=tots[bway]+1 bonds[bnum].bway=bway ss1=structure.GetSecondaryStructure(seg1) ss2=structure.GetSecondaryStructure(seg2) dist=getdist(seg1,atom1,mon2,seg2,atom2) bonds[bnum].dist=dist bonds[bnum].mons={mon1,mon2} bonds[bnum].segs={seg1,seg2} bonds[bnum].sss={ss1,ss2} bonds[bnum].aas={aa1,aa2} bonds[bnum].atoms={atom1,atom2} bonds[bnum].atypes={atype1,atype2} bonds[bnum].btypes={btype1,btype2} mssg=string.format(' (%d) Bond %d ', tots[bway],bnum) isdis=bonds[bnum]["bond_type"] -- 0 for hbonds, 1 for disulfides bonds[bnum].isdis=isdis if isdis==0 then -- for hbonds mssg=(mssg..'(hbond)') score1=current.GetSegmentEnergySubscore(seg1,'Bonding') score2=current.GetSegmentEnergySubscore(seg2,'Bonding') else -- for disulfides mssg=(mssg..'(disulfide)') score1=current.GetSegmentEnergySubscore(seg1,'Disulfides') score2=current.GetSegmentEnergySubscore(seg2,'Disulfides') end -- if isdis bonds[bnum].scores={score1,score2} print(string.format('%s %d%s%d%s%d%s-%d%s%d%s%d%s %s-%s len %.2f A wid %.2f A w/scores %.3f %.3f.', mssg,mon1,ss1,seg1,aas[aa1][1],atom1,atype1, mon2,ss2,seg2,aas[aa2][1],atom2,atype2, btype1,btype2,round2(dist),round2(width), round3(score1),round3(score2))) end -- if listit end -- for bnum print(' }') end -- for bway print(' }') print(string.format('%d + %d + %d = %d should equal %d.', tots[1],tots[2],tots[3],tots[1]+tots[2]+tots[3],nbonds)) print(' ') getnets(bonds,nbonds,nseg) print(' ') print('All done.') end -- Main() -- Below finds monomer # mon2 -- and segment # seg2 given -- a raw segment # seg2o -- and nseg, the # of segments -- per monomer. -- For a monomer, mon2 = 0 (orig monomer). -- For a dimer, mon2 = 0 to 1 (purple is 1). -- For a trimer, mon2 = 0 to 2 (teal is 2). -- For a tetramer, mon2 = 0 to 3 (brown is 3). -- For a pentamer, mon2 = 0 to 4. -- function getmonsig(seg2o,nseg) local mon2,seg2,nsegp1 nsegp1=nseg+1 -- includes 1 pseudo-residue -- at the end of each monomer. mon2=math.ceil(seg2o/nsegp1)-1 -- seg2o=0*nsegp1+1 to 1*nsegp1 gives mon2=0 -- seg2o=1*nsegp1+1 to 2*nsegp1 gives mon2=1 -- seg2o=2*nsegp1+1 to 3*nsegp1 gives mon2=2 -- seg2o=3*nsegp1+1 to 4*nsegp1 gives mon2=3 seg2=seg2o-mon2*nsegp1 return mon2,seg2 end -- getmonsig() -- Below finds distance dist between -- atom atom1 of segment seg1 of monomer 0 and -- atom atom2 of segment seg2 of monomer mon2. -- It returns -1 if no distance is found. -- function getdist(seg1,atom1,mon2,seg2,atom2) local dist= -1 local btmp,bold bold=band.GetCount() -- # bands at start of getdist btmp=band.AddBetweenSegments(seg1,seg2,atom1,atom2,mon2) -- In above, seg1 atom1 is on monomer mon1 = 0 -- while seg2 atom2 is on monomer mon2. if btmp>bold then -- is btmp a new band? dist=band.GetLength(btmp) band.Delete(btmp) end -- if btmp return dist end -- getdist() -- Below returns btype & atype -- where btype='bb' for backbone atoms -- and btype='sc' for sidechain atoms -- while atype='o' for oxygen atoms -- and atype='n' for nitrogen atoms. -- function gettype(nseg,seg,atom,aa) local atype,btype -- below will crash if the atom is an H if aa=='x' then -- AA is unknown atype='?' btype='?' else -- AA is one of the 20 standard AA's if atom<=4 then -- it's a backbone atom atype=getchar(bbstr,atom) btype='bb' elseif seg==nseg then -- doing C-terminal if atom==5 then -- atom 5 is an extra backbone O atype='o' btype='bb' else -- it's a sidechain atom atype=getchar(scstr[aa],atom-5) btype='sc' end -- if atom else -- it's a normal sidechain's atom atype=getchar(scstr[aa],atom-4) btype='sc' end -- if atom end -- if aa return atype,btype end -- gettype() -- Below returns the num-th -- character in the string str. -- function getchar(str,num) return string.sub(str,num,num) -- -- below might work too -- return string.char(string.byte(str,num)) end -- getchar() -- Below rounds inval to 2 digits -- after the decimal point so that -- 0.035-0.039 rounds up to 0.04 and -- 0.031-0.034 rounds down to 0.03. -- function round2(inval) return roundn(inval,2) end -- round2() -- Below rounds inval to 3 digits -- after the decimal point so that -- 0.0075-0.0079 rounds up to 0.008 and -- 0.0071-0.0074 rounds down to 0.007. -- function round3(inval) return roundn(inval,3) end -- round3() -- Below rounds inval to n digits -- after the decimal point. -- function roundn(inval,n) local tmpval,outval local tfac=10^n tmpval=tfac*inval if tmpval>0 then outval=math.floor(tmpval) if tmpval-outval>=0.5 then outval=outval+1 end -- if tmpval else -- below handles negative numbers outval=math.ceil(tmpval) if outval-tmpval>=0.5 then outval=outval-1 end -- if outval end -- if tmpval return (outval/tfac) end -- roundn() -- Below is meant to round total -- scores like Foldit does. -- Does it work right for -- negative scores? -- function trunc3(inval) return truncn(inval,3) end -- trunc3() -- Below truncates the number -- inval to the nth digit after -- the decimal place. -- function truncn(inval,n) local tfac=10^n return (math.floor(inval*tfac)/tfac) end -- truncn() -- Below is to break up the groups -- of bands into networks. -- function getnets(bonds,nbonds,nseg) local nets={} local bondnets={} -- which nets each bond is in local segnets={} -- which nets each segment is in local bnum,bnum1 local nnets,net1,segn,seg,seg1,seg2 local bway,isold,mssg,jmax,ii nnets=0 for segn=1,nseg do segnets[segn]={} end -- for segn for bnum=1,nbonds do bondnets[bnum]={} if bonds[bnum].isdis==0 then -- do below for hbonds not disulfide bonds bway=bonds[bnum].bway if bway>1 then -- hbond is not between 2 bb atoms on the same monomer seg1=bonds[bnum].segs[1] seg2=bonds[bnum].segs[2] isold=0 -- means seg1,seg2 aren't in networks 1 to nnets. -- 1 means just found a network for bnum seg1 seg2. -- 2 means already put bnum seg1 seg2 into a network. for net1=1,nnets do if isold==0 then for segn=1,(#(nets[net1].segs)) do if isold==0 then seg=nets[net1].segs[segn] if seg==seg1 or seg==seg2 then -- will add bnum seg1 seg2 to network net1 isold=1 end -- if seg end -- if isold end -- for segn end -- if isold if isold==1 then -- add bnum seg1 seg2 to network net1 segnets[seg1]=add2vec(segnets[seg1],net1) segnets[seg2]=add2vec(segnets[seg2],net1) bondnets[bnum]=add2vec(bondnets[bnum],net1) nets[net1].bonds=add2vec(nets[net1].bonds,bnum) nets[net1].segs=add2vec(nets[net1].segs,seg1) nets[net1].segs=add2vec(nets[net1].segs,seg2) -- Larger bway is better, and -- overall bway is decided by the best bway so far. if bway > nets[net1].bway then nets[net1].bway=bway end -- if bway isold=2 -- won't put bnum seg1 seg2 in another network end -- if isold end -- for net1 if isold==0 then -- add a new network to end of nets, -- and put bnum seg1 seg2 in it. nnets=nnets+1 nets[nnets]={} nets[nnets].bonds={} nets[nnets].segs={} segnets[seg1]=add2vec(segnets[seg1],nnets) segnets[seg2]=add2vec(segnets[seg2],nnets) bondnets[bnum]=add2vec(bondnets[bnum],nnets) nets[nnets].bonds=add2vec(nets[nnets].bonds,bnum) nets[nnets].segs=add2vec(nets[nnets].segs,seg1) nets[nnets].segs=add2vec(nets[nnets].segs,seg2) nets[nnets].bway=bway end -- if isold -- -- Below checks if any nets contain the same -- bonds or segments. If they do, it merges -- the nets into one. for bnum1=1,bnum do if (#(bondnets[bnum1]))>1 then -- bond bnum1 is in more than one network mssg,jmax=listvec(bondnets[bnum1]) print(string.format('Bond %d is in %d networks%s.', bnum1,jmax,mssg)) print(' so merge these networks below:') nets,nnets=mergenets(nets,bondnets[bnum1]) -- below updates segnets & bondnets segnets=newnets(nets,nnets,nseg,1) bondnets=newnets(nets,nnets,bnum,0) print(' ') end -- if end -- for bnum1 for segn=1,nseg do if (#(segnets[segn]))>1 then -- segment segn is in more than one network mssg,jmax=listvec(segnets[segn]) print(string.format('Segment %d is in %d networks%s,', segn,jmax,mssg)) print(' so merge these networks below:') nets,nnets=mergenets(nets,segnets[segn]) -- below updates segnets & bondnets segnets=newnets(nets,nnets,nseg,1) bondnets=newnets(nets,nnets,bnum,0) print(' ') end -- if end -- for segn end -- if bway end -- if bonds[bnum].isdis end -- for bnum -- -- below outputs the nets found above print('Found '..nnets..' different networks:') for netn=1,nnets do print(string.format(' Network %d w/bway=%d contains', netn,nets[netn].bway)) mssg,jmax=listvec(nets[netn].bonds) print(string.format(' %d bonds%s and',jmax,mssg)) mssg,jmax=listvec(nets[netn].segs) print(string.format(' %d segments%s or',jmax,mssg)) mssg,jmax=listvecNaas(nets[netn].segs) print(string.format(' %s.',mssg)) end -- for netn end -- getnets() -- Below find segnets based on the -- latest contents of nets. -- sflag=1 does for segments, -- sflag=0 does for bonds. -- function newnets(nets,nnets,nseg,sflag) local segnets={} local seg1,net1,vlen,ii for seg1=1,nseg do segnets[seg1]={} end -- for seg1 for net1=1,nnets do if sflag==1 then -- do for segments vlen=(#(nets[net1].segs)) else -- do for bonds vlen=(#(nets[net1].bonds)) end -- if sflag for ii=1,vlen do -- if sflag==1 then -- do for segments seg1=nets[net1].segs[ii] else -- do for bonds seg1=nets[net1].bonds[ii] end -- if sflag -- below adds network net1 to segnets[seg1], -- the list of networks containing segment seg1. segnets[seg1]=add2vec(segnets[seg1],net1) end -- for ii end -- for net1 return segnets end -- newnets() -- Below takes all the nets listed in nlist -- and merges them to make a new version of nets. -- If bway differs among the nets to be merged, -- the merged net will have the largest bway. -- function mergenets(nets,nlist) local mnets={} -- merged version of nets local inds={} -- mnets[inds[ii]] will include nets[ii] local ii,jj,lo,hi,mssg,jmax,net1 net1=nlist[1] hi=0 for ii=2,(#nlist) do lo=hi+1 hi=nlist[ii] for jj=lo,hi-1 do inds[jj]=jj-(ii-2) end -- for jj inds[hi]=net1 end -- for ii lo=hi+1 hi=(#nets) for jj=lo,hi do inds[jj]=jj-((#nlist)-1) end -- for jj mssg,jmax=listvec(nlist) print(string.format('For %d nets, nlist%s',(#nets),mssg)) mssg,jmax=listvec(inds) print(string.format(' gives inds%s.',mssg)) hi=(#nets)-((#nlist)-1) -- hi is now desired length for mnets for ii=1,hi do mnets[ii]={} mnets[ii].bonds={} mnets[ii].segs={} mnets[ii].bway=0 end -- for ii for ii=1,(#nets) do for jj=1,(#(nets[ii].bonds)) do mnets[inds[ii]].bonds=add2vec(mnets[inds[ii]].bonds,nets[ii].bonds[jj]) end -- for jj for jj=1,(#(nets[ii].segs)) do mnets[inds[ii]].segs=add2vec(mnets[inds[ii]].segs,nets[ii].segs[jj]) end -- for jj if mnets[inds[ii]].bway < nets[ii].bway then mnets[inds[ii]].bway = nets[ii].bway end -- if mnets end -- for ii return mnets,(#mnets) end -- mergenets() -- Below looks through the elements of ovec for val -- and if it doesn't find val, it puts val in numerical -- order to make nvec, which it returns. -- function add2vec(ovec,val) local nvec,vlen,ii,jj,qflag qflag=0 vlen=(#ovec) nvec={} for ii=1,vlen do if qflag==0 then -- don't quit yet if val<ovec[ii] then -- insert val into nvec -- so nvec[ii]=val. for jj=1,ii-1 do nvec[jj]=ovec[jj] end -- for jj nvec[ii]=val for jj=ii,vlen do nvec[jj+1]=ovec[jj] end -- for jj qflag=1 elseif val==ovec[ii] then -- val is already in ovec, -- so don't put a 2nd val into nvec. for jj=1,vlen do nvec[jj]=ovec[jj] end -- for jj qflag=1 end -- if val end -- if qflag end -- for ii if qflag==0 then -- val must be > ovec[vlen], -- so set nvec[vlen+1] to val. for jj=1,vlen do nvec[jj]=ovec[jj] end -- for jj nvec[vlen+1]=val end -- if qflag return nvec end -- add2vec() -- Below makes a string mssg -- containing the vlen elements -- of the vector vec with single -- spaces before each element. -- function listvec(vec) local mssg,vlen,ii vlen=(#vec) -- # of elements in vec mssg='' for ii=1,vlen do mssg=(mssg..' '..vec[ii]) end -- for ii return mssg,vlen end -- listvec() -- Below makes a string mssg -- containing the vlen elements -- of the vector vec with single -- spaces before each element. -- Assuming the elements of vec -- are segment #'s, it adds AA -- single-letter abbreviations -- to mssg for each element. -- function listvecNaas(vec) local mssg,vlen,ii,aa vlen=(#vec) -- # of elements in vec mssg='' for ii=1,vlen do aa=structure.GetAminoAcid(vec[ii]) mssg=(mssg..' '..aa..vec[ii]) end -- for ii return mssg,vlen end -- listvecNaas() -- Above lists all functions. Main() -- start program in Main() function.

Comments


jeff101 Lv 1

ListNetworks1 was made for Symmetry Puzzles (like 1974) with 
hydrogen bond networks (HBN's). It lists the bonds (both 
hydrogen and disulfide bonds), what monomers, segments, amino 
acids, secondary structures, atoms, & atom types they connect, 
whether each end is a backbone or sidechain atom, their 
Bonding or Disulfides subscores, their lengths, and their 
widths (how thick they appear in the Foldit gui). 

ListNetworks1 also attempts to group the bonds & segments into 
"Networks" by following which segments each bond connects. It 
ignores backbone to backbone bonds (like the ones holding 
helices or sheets together) within the same monomer in these 
"Networks" and gives a bway value of 3 for "Networks" with at 
least one bond connecting different monomers (a bit like the
red or blue HBN's the Foldit gui shows). 

Parts of ListNetworks1 were inspired by the sample code given at:
https://foldit.fandom.com/wiki/Foldit_Lua_Function_structure.GetHBonds

Please e-mail jeff101 if you think of ways to improve ListNetworks1.