1 |
package proteinstructure; |
2 |
|
3 |
import java.util.HashMap; |
4 |
import java.util.TreeMap; |
5 |
|
6 |
import edu.uci.ics.jung.graph.util.EdgeType; |
7 |
import edu.uci.ics.jung.graph.util.Pair; |
8 |
|
9 |
/** |
10 |
* An Atom Interaction Graph |
11 |
* |
12 |
*/ |
13 |
public class AIGraph extends ProtStructGraph<AIGNode,AIGEdge> { |
14 |
|
15 |
private static final long serialVersionUID = 1L; |
16 |
|
17 |
private boolean crossed; // true if this AIGraph has been obtained from a cross contact type (the ones with "/") |
18 |
private double distCutoff; |
19 |
|
20 |
public AIGraph() { |
21 |
super(); |
22 |
this.crossed = false; |
23 |
this.distCutoff = 0; |
24 |
} |
25 |
|
26 |
public double getCutoff() { |
27 |
return distCutoff; |
28 |
} |
29 |
|
30 |
public void setCutoff(double distCutoff) { |
31 |
this.distCutoff = distCutoff; |
32 |
} |
33 |
|
34 |
public boolean isCrossed() { |
35 |
return crossed; |
36 |
} |
37 |
|
38 |
public void setCrossed(boolean crossed) { |
39 |
this.crossed = crossed; |
40 |
} |
41 |
|
42 |
/** |
43 |
* Returns a RIGraph by collapsing atom contacts into residue contacts, |
44 |
* using the number of atom edges per residue as the atom weights for the RIGEdges |
45 |
* TODO eventually we can pass a parameter for other ways of assigning atom contact weights |
46 |
* @return |
47 |
*/ |
48 |
public RIGraph getRIGraph(boolean directed) { |
49 |
EdgeType et = EdgeType.UNDIRECTED; |
50 |
|
51 |
if (directed) { |
52 |
et = EdgeType.DIRECTED; |
53 |
} |
54 |
RIGraph resGraph = new RIGraph(); |
55 |
resGraph.setPdbCode(this.pdbCode); |
56 |
resGraph.setChainCode(this.chainCode); |
57 |
resGraph.setPdbChainCode(this.pdbChainCode); |
58 |
resGraph.setModel(this.model); |
59 |
resGraph.setSequence(this.sequence); |
60 |
resGraph.setSecondaryStructure(this.secondaryStructure); |
61 |
|
62 |
TreeMap<Integer,RIGNode> rignodes = new TreeMap<Integer,RIGNode>(); |
63 |
for (AIGNode atomNode:this.getVertices()) { |
64 |
RIGNode resNode = atomNode.getParent(); |
65 |
int resser = resNode.getResidueSerial(); |
66 |
rignodes.put(resser, resNode); // we put in the map each RIGNode several times, that should be fine |
67 |
} |
68 |
|
69 |
// putting the RIGnodes into the RIGraph |
70 |
for (int resser:rignodes.keySet()){ |
71 |
resGraph.addVertex(rignodes.get(resser)); |
72 |
} |
73 |
|
74 |
resGraph.setSerials2NodesMap(rignodes); |
75 |
|
76 |
// collapsing atomPairs into resPairs and counting atom contacts to assign atom weights |
77 |
HashMap<Pair<RIGNode>,Integer> pairs2weights = new HashMap<Pair<RIGNode>, Integer>(); |
78 |
HashMap<Pair<RIGNode>,Double> pairs2distances = new HashMap<Pair<RIGNode>,Double>(); |
79 |
for (AIGEdge atomEdge: this.getEdges()){ |
80 |
Pair<AIGNode> atomPair = this.getEndpoints(atomEdge); |
81 |
RIGNode v1 = atomPair.getFirst().getParent(); |
82 |
RIGNode v2 = atomPair.getSecond().getParent(); |
83 |
Pair<RIGNode> resPair = new Pair<RIGNode>(v1,v2); |
84 |
if (v1!=v2) { |
85 |
if (!pairs2weights.containsKey(resPair)) { |
86 |
//NOTE the pairs2weights map takes care of eliminating duplicate residue pairs (Maps don't accept duplicate as keys) |
87 |
pairs2weights.put(resPair, 1); |
88 |
pairs2distances.put(resPair, atomEdge.getDistance()); |
89 |
} else { |
90 |
pairs2weights.put(resPair,pairs2weights.get(resPair)+1); |
91 |
pairs2distances.put(resPair, Math.min(pairs2distances.get(resPair), atomEdge.getDistance())); |
92 |
} |
93 |
} |
94 |
} |
95 |
|
96 |
// putting the RIGEdges in the resGraph |
97 |
for (Pair<RIGNode> resPair:pairs2weights.keySet()) { |
98 |
// if undirected and edge already exists |
99 |
if (!directed && (resGraph.findEdge(resPair.getFirst(), resPair.getSecond())!=null)) { |
100 |
//increase weight |
101 |
RIGEdge e = resGraph.findEdge(resPair.getFirst(), resPair.getSecond()); |
102 |
e.setAtomWeight(e.getAtomWeight()+pairs2weights.get(resPair)); |
103 |
e.setDistance(Math.min(e.getDistance(), pairs2distances.get(resPair))); |
104 |
} else { |
105 |
//add edge |
106 |
RIGEdge e = new RIGEdge(pairs2weights.get(resPair)); |
107 |
e.setDistance(pairs2distances.get(resPair)); |
108 |
resGraph.addEdge(e, resPair, et);//(e, pair, et); |
109 |
} |
110 |
} |
111 |
|
112 |
return resGraph; |
113 |
} |
114 |
|
115 |
public int getContactRange(AIGEdge edge) { |
116 |
Pair<AIGNode> pair = this.getEndpoints(edge); |
117 |
return Math.abs(pair.getFirst().getParent().getResidueSerial()-pair.getSecond().getParent().getResidueSerial()); |
118 |
} |
119 |
|
120 |
public boolean addGraph(AIGraph graph) { |
121 |
//NOTE:The checks below would make sense only for adding RIGraphs |
122 |
//In AIGraphs we have as nodes only the selected atoms and not all atoms |
123 |
/* |
124 |
if (this.getVertexCount()!=graph.getVertexCount()) { |
125 |
return false; |
126 |
} |
127 |
Iterator<Integer> it = graph.getSerials().iterator(); |
128 |
for (int serial:this.getSerials()) { |
129 |
AIGNode node = this.getNodeFromSerial(serial); |
130 |
AIGNode node2 = graph.getNodeFromSerial(it.next()); |
131 |
if (!node.equals(node2)){ |
132 |
return false; |
133 |
} |
134 |
}*/ |
135 |
|
136 |
boolean change = false; |
137 |
|
138 |
TreeMap<Integer,RIGNode> rignodes = new TreeMap<Integer,RIGNode>(); |
139 |
for (AIGNode atomNode : this.getVertices()) { |
140 |
rignodes.put(atomNode.getParent().getResidueSerial(), atomNode.getParent()); |
141 |
} |
142 |
|
143 |
for (AIGNode atomNode : graph.getVertices()) { |
144 |
RIGNode v = null; |
145 |
if (!rignodes.containsKey(atomNode.getParent().getResidueSerial())) { |
146 |
v = atomNode.getParent(); |
147 |
rignodes.put(v.getResidueSerial(), v); |
148 |
change = true; |
149 |
} else { |
150 |
v = rignodes.get(atomNode.getParent().getResidueSerial()); |
151 |
} |
152 |
if (!this.serials2nodes.containsKey(atomNode.getAtomSerial())) { |
153 |
change = true; |
154 |
AIGNode v1 = new AIGNode (atomNode.getAtomSerial(), atomNode.getAtomName(), v); |
155 |
this.addVertex(v1); |
156 |
this.serials2nodes.put(atomNode.getAtomSerial(), v1); |
157 |
} |
158 |
} |
159 |
|
160 |
for (AIGEdge atomEdge: graph.getEdges()){ |
161 |
Pair<AIGNode> atomPair = graph.getEndpoints(atomEdge); |
162 |
AIGNode v1 = this.getNodeFromSerial(atomPair.getFirst().getAtomSerial()); |
163 |
AIGNode v2 = this.getNodeFromSerial(atomPair.getSecond().getAtomSerial()); |
164 |
// This condition is to take care of not adding multiple instances of the same atomic edge |
165 |
if (this.findEdge(v1, v2)==null) { |
166 |
change = true; |
167 |
this.addEdge(atomEdge.copy(), v1, v2, graph.getEdgeType(atomEdge)); |
168 |
} |
169 |
} |
170 |
this.setCrossed((this.crossed || graph.crossed)); |
171 |
return change; |
172 |
} |
173 |
} |