ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/owl/trunk/proteinstructure/Graph.java
Revision: 206
Committed: Tue Jun 26 17:01:48 2007 UTC (17 years, 8 months ago) by duarte
File size: 22256 byte(s)
Log Message:
Major refactoring:
 accode -> pdbCode
 chaincode -> pdbChainCode
 chain -> chainCode
Major change of signatures (publics to privates)
Implemented getters for needed member variables
Major clean up
Line File contents
1 package proteinstructure;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.FileReader;
8 import java.io.PrintStream;
9 import java.io.IOException;
10 import java.sql.ResultSet;
11 import java.sql.SQLException;
12 import java.sql.Statement;
13 import java.util.Collections;
14 import java.util.TreeMap;
15 import java.util.HashMap;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18 import tools.MySQLConnection;
19
20
21 public class Graph {
22
23 private final static String MYSQLSERVER="white";
24 private final static String MYSQLUSER=getUserName();
25 private final static String MYSQLPWD="nieve";
26
27 public final static String GRAPHFILEFORMATVERSION = "1.0";
28
29 public ContactList contacts; // kept it public to be able to re-reference the object directly (getContacts() copies it)
30
31 // nodes is a TreeMap of residue serials to residue types (3 letter code)
32 private TreeMap<Integer,String> nodes;
33 private String sequence; // the full sequence (with unobserved residues and non-standard aas ='X')
34 private String pdbCode;
35 private String chainCode;
36 private String pdbChainCode="";
37 private double cutoff;
38 private String ct; // the contact type
39 private boolean directed=false;
40
41 // fullLength is length of full sequence or:
42 // -if sequence not provided (when reading from db): length of everything except possible unobserved residues at end of chain
43 // -if sequence and nodes not provided (when reading from file and sequence field missing): length except possible unobserved residues at end of chain and possible nodes without contacts at end of chain
44 private int fullLength;
45 private int obsLength; // length without unobserved, non standard aas
46
47 private int numContacts;
48
49 private boolean modified;
50
51 // these 2 fields only used when reading from db
52 private int graphid=0;
53 //private int sm_id=0; // for future use
54
55 /**
56 * Constructs Graph object by passing ArrayList with contacts and TreeMap with nodes (res serials and types)
57 * Must also pass contact type, cutoff, pdbCode and chainCode
58 * @param contacts
59 * @param nodes
60 * @param sequence
61 * @param cutoff
62 * @param ct
63 * @param pdbCode
64 * @param chainCode
65 */
66 public Graph (ContactList contacts, TreeMap<Integer,String> nodes, String sequence, double cutoff,String ct, String pdbCode, String chainCode, String pdbChainCode) {
67 this.contacts=contacts;
68 this.cutoff=cutoff;
69 this.nodes=nodes;
70 this.sequence=sequence;
71 this.pdbCode=pdbCode;
72 this.chainCode=chainCode;
73 this.pdbChainCode=pdbChainCode;
74 this.ct=ct;
75 this.fullLength=sequence.length();
76 this.obsLength=nodes.size();
77 this.numContacts=contacts.size();
78 this.modified=false;
79 if (ct.contains("/")){
80 directed=true;
81 }
82 }
83
84 /**
85 * Constructs Graph object from graph db, given the dbname, pdbCode, pdbChainCode (classic pdb chain code), ct and cutoff
86 * @param dbname
87 * @param pdbCode
88 * @param pdbChainCode
89 * @param cutoff
90 * @param ct
91 * @throws GraphIdNotFoundError
92 * @throws SQLException
93 */
94 public Graph(String dbname, String pdbCode, String pdbChainCode, double cutoff, String ct) throws GraphIdNotFoundError, SQLException{
95 this.cutoff=cutoff;
96 this.pdbCode=pdbCode;
97 this.ct=ct;
98 // we set the sequence to empty when we read from graph db. We don't have the full sequence in graph db
99 // when we pass the sequence in getCM to the ContactMap constructor we want to have either a full sequence (with unobserveds) or a blank in case we don't have the info
100 this.sequence="";
101 //TODO graphs in db are never directed, so this doesn't really apply here. Must solve all this!
102 if (ct.contains("/")){
103 directed=true;
104 }
105 MySQLConnection conn = new MySQLConnection(MYSQLSERVER,MYSQLUSER,MYSQLPWD,dbname);
106 getgraphid(conn, pdbChainCode); // initialises graphid, sm_id and chainCode
107 read_graph_from_db(conn); // gets contacts, nodes and sequence
108 conn.close();
109 this.obsLength=nodes.size();
110 if (!sequence.equals("")){
111 this.fullLength=sequence.length();
112 } else {
113 // if nodes TreeMap has correct residue numbering then this should get the right full length,
114 // we will only miss: gaps (unobserved residues) at the end of the sequence. Those we can't know unless full sequence is given
115 this.fullLength=Collections.max(nodes.keySet());
116 }
117 this.numContacts=contacts.size();
118 this.modified=false;
119 }
120
121 /**
122 * Constructs Graph object from graph db, given the graphid
123 * @param dbname
124 * @param graphid
125 * @throws GraphIdNotFoundError
126 * @throws SQLException
127 */
128 public Graph(String dbname,int graphid) throws GraphIdNotFoundError, SQLException{
129 this.graphid=graphid;
130 // we set the sequence to empty when we read from graph db. We don't have the full sequence in graph db
131 // when we pass the sequence in getCM to the ContactMap constructor we want to have either a full sequence (with unobserveds) or a blank in case we don't have the info
132 this.sequence="";
133 MySQLConnection conn = new MySQLConnection(MYSQLSERVER,MYSQLUSER,MYSQLPWD,dbname);
134 read_graph_from_db(conn); // gets contacts, nodes and sequence
135 get_db_graph_info(conn); // gets pdbCode, pdbChainCode, chainCode, ct and cutoff from db (from graph_id)
136 conn.close();
137 //TODO graphs in db are never directed, so this doesn't really apply here. Must solve all this!
138 if (ct.contains("/")){
139 directed=true;
140 }
141 this.obsLength=nodes.size();
142 if (!sequence.equals("")){
143 this.fullLength=sequence.length();
144 } else {
145 // if nodes TreeMap has correct residue numbering then this should get the right full length,
146 // we will only miss: gaps (unobserved residues) at the end of the sequence. Those we can't know unless full sequence is given
147 this.fullLength=Collections.max(nodes.keySet());
148 }
149 this.numContacts=contacts.size();
150 this.modified=false;
151 }
152
153 /**
154 * Constructs Graph object by reading a file with contacts
155 * If the contacts file doesn't have the sequence then the graph object won't have sequence or nodes
156 * That means it won't be possible to get a ContactMap from it using getCM because CM needs both sequence and nodes
157 * @param contactsfile
158 * @throws IOException
159 * @throws FileNotFoundException
160 */
161 public Graph (String contactsfile) throws IOException, FileNotFoundException{
162 // we set the sequence to blank when we read from file as we don't have the full sequence
163 // if sequence is present in contactsfile then is read from there
164 this.sequence="";
165 this.ct="";
166 this.cutoff=0.0;
167 // we initialise pdbCode, chainCode and pdbChainCode to empty strings in case the file doesn't specify then
168 this.pdbCode="";
169 this.chainCode="";
170 this.pdbChainCode="";
171 if (ct.contains("/")){
172 directed=true;
173 }
174 read_graph_from_file(contactsfile); // initialises contacts, and nodes (only if sequence is given)
175 if (!sequence.equals("")){
176 this.fullLength=sequence.length();
177 this.obsLength=nodes.size();
178 } else {
179 // if contacts have correct residue numbering then this should get the right full length up to the maximum node that makes a contact,
180 // we will miss: nodes without contacts at the end of sequence and gaps (unobserved residues) at the end of the sequence.
181 // We don't know more without nodes and sequence
182 this.fullLength=contacts.getMaxNode();
183 // in this case nodes has not been initialised so we set obsLength=fullLength as we don't have the information
184 this.obsLength=fullLength;
185 }
186 this.numContacts=contacts.size();
187 this.modified=false;
188 }
189
190 //TODO implement (from python) write_graph_to_db, do we really need it here??
191
192 /** get user name from operating system (for use as database username) */
193 private static String getUserName() {
194 String user = null;
195 user = System.getProperty("user.name");
196 if(user == null) {
197 System.err.println("Could not get user name from operating system. Exiting");
198 System.exit(1);
199 }
200 return user;
201 }
202
203 public void read_graph_from_file (String contactsfile) throws FileNotFoundException, IOException {
204 contacts = new ContactList();
205 //System.out.println("Reading contacts from file "+contactsfile);
206 BufferedReader fcont = new BufferedReader(new FileReader(new File(contactsfile)));
207 String line;
208 while ((line = fcont.readLine() ) != null ) {
209 Pattern p = Pattern.compile("^#");
210 Matcher m = p.matcher(line);
211 if (m.find()){
212 // Pattern ps = Pattern.compile("^#VER: (\\d\\.\\d)");
213 // Matcher ms = ps.matcher(line);
214 // if (ms.find()){
215 // if (!ms.group(1).equals(GRAPHFILEFORMATVERSION)){
216 // throw new GraphFileFormatError("The graph file "+contactsfile+" can't be read, wrong file format version");
217 // }
218 // }
219 Pattern ps = Pattern.compile("^#SEQUENCE:\\s*(\\w+)$");
220 Matcher ms = ps.matcher(line);
221 if (ms.find()){
222 sequence=ms.group(1);
223 }
224 ps = Pattern.compile("^#PDB:\\s*(\\w+)");
225 ms = ps.matcher(line);
226 if (ms.find()){
227 pdbCode=ms.group(1);
228 }
229 ps = Pattern.compile("^#PDB CHAIN CODE:\\s*(\\w)");
230 ms = ps.matcher(line);
231 if (ms.find()){
232 pdbChainCode=ms.group(1);
233 }
234 ps = Pattern.compile("^#CHAIN:\\s*(\\w)");
235 ms = ps.matcher(line);
236 if (ms.find()){
237 chainCode=ms.group(1);
238 }
239 ps = Pattern.compile("^#CT:\\s*([a-zA-Z/]+)");
240 ms = ps.matcher(line);
241 if (ms.find()){
242 ct=ms.group(1);
243 }
244 ps = Pattern.compile("^#CUTOFF:\\s*(\\d+\\.\\d+)");
245 ms = ps.matcher(line);
246 if (ms.find()){
247 cutoff=Double.parseDouble(ms.group(1));
248 }
249 }
250 else{
251 int i = Integer.parseInt(line.split("\\s+")[0]);
252 int j = Integer.parseInt(line.split("\\s+")[1]);
253 contacts.add(new Contact(i,j));
254 }
255 }
256 fcont.close();
257 // if sequence was given we take nodes from it
258 nodes = new TreeMap<Integer, String>();
259 for (int i=0;i<sequence.length();i++){
260 String letter = String.valueOf(sequence.charAt(i));
261 nodes.put(i+1, AA.oneletter2threeletter(letter));
262 }
263
264 }
265
266 /**
267 * Reads contacts and nodes from db.
268 * The db must be a graph db following our standard format, i.e. must have tables:
269 * chain_graph, single_model_graph, single_model_node, single_model_edge
270 * We don't care here about the origin of the data (msdsd, pdbase, predicted) for the generation of the graph as long as it follows our data format
271 * We read both edges and nodes from single_model_edge and single_model_node.
272 * The sequence is set to blank, as we can't get the full sequence from graph db
273 * @param conn
274 */
275 public void read_graph_from_db(MySQLConnection conn){
276 contacts = new ContactList();
277 nodes = new TreeMap<Integer, String>();
278 try {
279 // we read only half of the matrix (contacts in one direction only) so that we have the same type of contacts as when creating Graph from Pdb object
280 String sql="SELECT i_num,j_num FROM single_model_edge WHERE graph_id="+graphid+" AND j_num>i_num ORDER BY i_num,j_num ";
281 Statement stmt = conn.createStatement();
282 ResultSet rsst = stmt.executeQuery(sql);
283 while (rsst.next()) {
284 int i=rsst.getInt(1);
285 int j=rsst.getInt(2);
286 contacts.add(new Contact(i,j));
287 }
288 rsst.close();
289 stmt.close();
290 sql="SELECT num,res FROM single_model_node WHERE graph_id="+graphid+" ORDER BY num ";
291 stmt = conn.createStatement();
292 rsst = stmt.executeQuery(sql);
293 while (rsst.next()){
294 int num=rsst.getInt(1);
295 String res=rsst.getString(2);
296 nodes.put(num, AA.oneletter2threeletter(res));
297 }
298 rsst.close();
299 stmt.close();
300 } catch (SQLException e) {
301 e.printStackTrace();
302 }
303
304 }
305
306 public void getgraphid (MySQLConnection conn, String pdbChainCode) throws GraphIdNotFoundError{
307 // input is pdbChainCode i.e. pdb chain code
308 // we take chainCode (internal chain identifier, pchain_code for msdsd and asym_id for pdbase) from pchain_code field in chain_graph
309 // (in the chain_graph table the internal chain identifier is called 'pchain_code')
310 int pgraphid=0;
311 String chainstr="='"+pdbChainCode+"' ";
312 if (pdbChainCode.equals("NULL")){
313 chainstr=" IS NULL ";
314 }
315 try {
316 String sql="SELECT graph_id, pchain_code FROM chain_graph WHERE accession_code='"+pdbCode+"' AND chain_pdb_code"+chainstr+" AND dist="+cutoff;
317 Statement stmt = conn.createStatement();
318 ResultSet rsst = stmt.executeQuery(sql);
319 int check=0;
320 while (rsst.next()) {
321 check++;
322 pgraphid=rsst.getInt(1);
323 chainCode=rsst.getString(2);
324 }
325 if (check!=1){
326 System.err.println("No pgraph_id match or more than 1 match for accession_code="+pdbCode+", chain_pdb_code="+pdbChainCode+", dist="+cutoff);
327 }
328 rsst.close();
329 stmt.close();
330 // we set the ctstr to the same as ct except in ALL case, where it is BB+SC+BB/SC
331 String ctstr=ct;
332 if (ct.equals("ALL")){
333 ctstr="BB+SC+BB/SC";
334 }
335 sql="SELECT graph_id,single_model_id FROM single_model_graph WHERE pgraph_id="+pgraphid+" AND CT='"+ctstr+"' AND dist="+cutoff+" AND CR='(true)' AND CW=1";
336 stmt = conn.createStatement();
337 rsst = stmt.executeQuery(sql);
338 check=0;
339 while (rsst.next()){
340 check++;
341 graphid=rsst.getInt(1);
342 //sm_id=rsst.getInt(2); // we might want to use it in the future
343 }
344 if (check!=1){
345 System.err.println("No graph_id match or more than 1 match for pgraph_id="+pgraphid+", CT="+ctstr+" and cutoff="+cutoff);
346 throw new GraphIdNotFoundError("No graph_id match or more than 1 match for pgraph_id="+pgraphid+", CT="+ctstr+" and cutoff="+cutoff);
347 }
348 } catch (SQLException e) {
349 e.printStackTrace();
350 }
351
352 }
353
354 public void get_db_graph_info(MySQLConnection conn) throws GraphIdNotFoundError {
355 try {
356 int pgraphid=0;
357 String sql="SELECT pgraph_id,CT,dist FROM single_model_graph WHERE graph_id="+graphid;
358 Statement stmt = conn.createStatement();
359 ResultSet rsst = stmt.executeQuery(sql);
360 int check=0;
361 while (rsst.next()) {
362 check++;
363 pgraphid=rsst.getInt(1);
364 ct=rsst.getString(2);
365 if (ct.equals("BB+SC+BB/SC")) ct="ALL";
366 cutoff=rsst.getDouble(3);
367 }
368 if (check!=1){
369 System.err.println("No pgraph_id match or more than 1 match for graph_id="+graphid);
370 throw new GraphIdNotFoundError("No pgraph_id match or more than 1 match for graph_id="+graphid+" in db"+conn.getDbname());
371 }
372 rsst.close();
373 stmt.close();
374 sql="SELECT accession_code, chain_pdb_code, pchain_code FROM chain_graph WHERE graph_id="+pgraphid;
375 stmt = conn.createStatement();
376 rsst = stmt.executeQuery(sql);
377 check=0;
378 while (rsst.next()){
379 check++;
380 pdbCode=rsst.getString(1);
381 pdbChainCode=rsst.getString(2);
382 // java returns a null if the field is a database null, we want actually the "NULL" string in that case
383 if (pdbChainCode==null) pdbChainCode="NULL";
384 chainCode=rsst.getString(3);
385 }
386 if (check!=1){
387 System.err.println("No accession_code+chain_pdb_code+pchain_code match or more than 1 match for graph_id="+pgraphid+" in chain_graph table");
388 }
389 rsst.close();
390 stmt.close();
391 } catch (SQLException e) {
392 e.printStackTrace();
393 }
394
395 }
396
397 public void write_contacts_to_file (String outfile) throws IOException {
398 PrintStream Out = new PrintStream(new FileOutputStream(outfile));
399 for (Contact pair:contacts){
400 int i_resser=pair.i;
401 int j_resser=pair.j;
402 Out.println(i_resser+"\t"+j_resser);
403 }
404 Out.close();
405 }
406
407 public void write_graph_to_file (String outfile) throws IOException {
408 PrintStream Out = new PrintStream(new FileOutputStream(outfile));
409 Out.println("#VER: "+GRAPHFILEFORMATVERSION);
410 Out.println("#SEQUENCE: "+sequence);
411 Out.println("#PDB: "+pdbCode);
412 Out.println("#PDB CHAIN CODE: "+pdbChainCode);
413 Out.println("#CHAIN: "+chainCode);
414 Out.println("#CT: "+ct);
415 Out.println("#CUTOFF: "+cutoff);
416 for (Contact pair:contacts){
417 int i_resser=pair.i;
418 int j_resser=pair.j;
419 Out.println(i_resser+"\t"+j_resser);
420 }
421 Out.close();
422 }
423
424 /**
425 * Gets list of contacts as a new ContactList (deep copied)
426 *
427 */
428 public ContactList getContacts(){
429 ContactList newContacts = new ContactList();
430 for (Contact cont:contacts){
431 newContacts.add(new Contact(cont.i,cont.j));
432 }
433 return newContacts;
434 }
435
436 /**
437 * Gets TreeMap of nodes, deep copying
438 *
439 */
440 public TreeMap<Integer,String> getNodes(){
441 TreeMap<Integer,String> newNodes = new TreeMap<Integer,String>();
442 for (int resser:nodes.keySet()){
443 newNodes.put(resser, nodes.get(resser));
444 }
445 return newNodes;
446 }
447
448 /**
449 * Deep copies this Graph object returning new one
450 * @return
451 */
452 public Graph copy(){
453 return new Graph(getContacts(),getNodes(),sequence,cutoff,ct,pdbCode,chainCode,pdbChainCode);
454 }
455
456 /**
457 * Returns an int matrix with 1s for contacts and 0s for non contacts, i.e. the contact map
458 * In non-crossed cases this should give us the upper half matrix (contacts are only j>i)
459 * In crossed cases this gives us a full matrix (contacts are both j>i and i>j since they are directed)
460 * @return
461 */
462 public int[][] getIntMatrix(){
463 // this initialises the matrix to 0 (i.e. no contact)
464 int[][] cm = new int[fullLength][fullLength];
465 // we put a 1 for all given contacts
466 for (Contact cont:contacts){
467 int i_resser = cont.i;
468 int j_resser = cont.j;
469 cm[i_resser-1][j_resser-1]=1;
470 }
471 return cm;
472 }
473
474 /**
475 * Gets a node's residue type given the residue serial
476 * @param resser
477 * @return
478 */
479 public String getResType(int resser){
480 return nodes.get(resser);
481 }
482
483 /**
484 * Gets node neighbourhood given a residue serial
485 * @param resser
486 * @return
487 */
488 public NodeNbh getNodeNbh(int resser){
489 NodeNbh nbh = new NodeNbh(resser, getResType(resser));
490 //this could be implemented using the contact map matrix and scanning through 1 column/row
491 //it would be just slightly faster, here we do 2*numContacts iterations, using matrix would be only fullLength iterations
492 //however we would then have the overhead of creating the matrix
493 for (Contact cont:contacts){
494 if (cont.i==resser) nbh.put(cont.j, nodes.get(cont.j));
495 if (cont.j==resser) nbh.put(cont.i, nodes.get(cont.i));
496 }
497 return nbh;
498 }
499
500 /**
501 * Gets edge neighbourhood (common neighbourhood) given a residue serial pair
502 * @param i_resser
503 * @param j_resser
504 * @return
505 */
506 public EdgeNbh getEdgeNbh(int i_resser, int j_resser){
507 EdgeNbh nbh = new EdgeNbh(i_resser, getResType(i_resser), j_resser, getResType(j_resser));
508 NodeNbh i_nbhd = getNodeNbh(i_resser);
509 NodeNbh j_nbhd = getNodeNbh(j_resser);
510 if (j_nbhd.size()>=i_nbhd.size()) { //with this we will be slightly faster, always iterating through smallest TreeMap
511 for (int resser:i_nbhd.keySet()) {
512 if (j_nbhd.containsKey(resser)) nbh.put(resser, i_nbhd.get(resser));
513 }
514 } else {
515 for (int resser:j_nbhd.keySet()) {
516 if (i_nbhd.containsKey(resser)) nbh.put(resser, j_nbhd.get(resser));
517 }
518 }
519 return nbh;
520 }
521
522 public void addEdge(Contact cont){
523 contacts.add(cont);
524 numContacts++;
525 modified=true;
526 }
527
528 public void delEdge(Contact cont){
529 contacts.remove(cont);
530 numContacts--;
531 modified=true;
532 }
533
534 public void restrictContactsToMaxRange(int range){
535 ContactList edgesToDelete = new ContactList();
536 for (Contact cont:contacts){
537 if (cont.getRange()>range) edgesToDelete.add(cont);
538 }
539 for (Contact cont:edgesToDelete){
540 delEdge(cont);
541 }
542 }
543
544 public void restrictContactsToMinRange(int range){
545 ContactList edgesToDelete = new ContactList();
546 for (Contact cont:contacts){
547 if (cont.getRange()<range) edgesToDelete.add(cont);
548 }
549 for (Contact cont:edgesToDelete){
550 delEdge(cont);
551 }
552 }
553
554 /**
555 * Returns a HashMap with all edge neighbourhood sizes (if they are >0) for each cell in the contact map
556 * @return
557 */
558 public HashMap<Contact,Integer> getAllEdgeNbhSizes() {
559 HashMap<Contact,Integer> sizes = new HashMap<Contact, Integer>();
560 if (!directed) {
561 for (int i=1; i<fullLength;i++){
562 for (int j=i+1; j<fullLength;j++){
563 int size = getEdgeNbh(i, j).size();
564 if (size>0) sizes.put(new Contact(i,j), size);
565 }
566 }
567 } else {
568 for (int i=1; i<fullLength;i++){
569 for (int j=1; j<fullLength;j++){
570 if (i!=j){
571 int size = getEdgeNbh(i, j).size();
572 if (size>0) sizes.put(new Contact(i,j), size);
573 }
574 }
575 }
576 }
577 return sizes;
578 }
579
580 //TODO not sure what kind of return we want, for now is a HashMap with three graph objects
581 public HashMap<String,Graph> compare(Graph other) throws Exception{
582 //first check that other has same sequence than this, otherwise throw exception
583 if (!this.sequence.equals(other.sequence)){
584 //TODO throw specific exception
585 throw new Exception("Sequence of 2 graphs to compare differ, can't compare them.");
586 }
587 ContactList common = new ContactList();
588 ContactList onlythis = new ContactList();
589 ContactList onlyother = new ContactList();
590 for (Contact cont:this.contacts){
591 if (other.contacts.contains(cont)) {
592 common.add(cont);
593 } else{
594 onlythis.add(cont);
595 }
596 }
597 for (Contact cont:other.contacts){
598 if (!this.contacts.contains(cont)){
599 onlyother.add(cont);
600 }
601 }
602 Graph commongraph = new Graph (common,getNodes(),sequence,cutoff,ct,pdbCode,chainCode,pdbChainCode);
603 Graph onlythisgraph = new Graph (onlythis,getNodes(),sequence,cutoff,ct,pdbCode,chainCode,pdbChainCode);
604 Graph onlyothergraph = new Graph (onlyother,getNodes(),sequence,cutoff,ct,other.pdbCode,other.chainCode,other.pdbChainCode);
605 HashMap<String,Graph> result = new HashMap<String,Graph>();
606 result.put("common", commongraph);
607 result.put("onlythis", onlythisgraph);
608 result.put("onlyother",onlyothergraph);
609 return result;
610 }
611
612 public boolean isModified(){
613 return modified;
614 }
615
616 public boolean isDirected(){
617 return directed;
618 }
619
620 public String getPdbCode() {
621 return pdbCode;
622 }
623
624 public String getPdbChainCode(){
625 return pdbChainCode;
626 }
627
628 public String getChainCode(){
629 return chainCode;
630 }
631
632 public String getSequence(){
633 return sequence;
634 }
635
636 public int getFullLength(){
637 return fullLength;
638 }
639
640 public int getObsLength(){
641 return obsLength;
642 }
643
644 public int getNumContacts(){
645 // in theory we could return just numContacts, because we have taken care of updating it every time contacts changed
646 // however we call directly contacts.size() as I feel is safer
647 return contacts.size();
648 }
649
650 public String getContactType() {
651 return ct;
652 }
653
654 public double getCutoff(){
655 return cutoff;
656 }
657 }