001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 * Created on 22.01.2007
021 *
022 */
023package org.biojava.nbio.structure;
024
025
026import org.biojava.nbio.structure.io.FileParsingParameters;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import java.io.Serializable;
031import java.util.ArrayList;
032import java.util.Collections;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.LinkedHashMap;
036import java.util.List;
037import java.util.Map;
038import java.util.Set;
039import java.util.TreeSet;
040
041/**
042 * An object to contain the info from the PDB header for a Molecule.
043 * In mmCIF dictionary, it is called an Entity. In the case of polymers it
044 * is defined as each group of sequence identical NCS-related chains
045 *
046 * Now PDB file format 3.2 aware - contains the new TAX_ID fields for the
047 * organism studied and the expression system.
048 *
049 * @author Jules Jacobsen
050 * @author Jose Duarte
051 * @author Anthony Bradley
052 * @since 1.5
053 */
054public class EntityInfo implements Serializable {
055
056        private final static Logger logger = LoggerFactory.getLogger(EntityInfo.class);
057
058
059        // TODO We could drop a lot of the stuff here that is PDB-file related (actually many PDB files don't contain many of these fields) - JD 2016-03-25
060        //     The only really essential part of a EntityInfo is the member chains and the entity_id/mol_id
061        // See also issue https://github.com/biojava/biojava/issues/219
062
063        private static final long serialVersionUID = 2991897825657586356L;
064
065        /**
066         * The list of chains that are described by this EntityInfo
067         */
068        private List<Chain> chains;
069
070        /**
071         * The Molecule identifier, called entity_id in mmCIF dictionary
072         */
073        private int molId;
074
075        /**
076         * A map to cache residue number mapping, between ResidueNumbers and index (1-based) in aligned sequences (SEQRES).
077         * Initialised lazily upon call to {@link #getAlignedResIndex(Group, Chain)}
078         * Keys are asym_ids of chains, values maps of residue numbers to indices.
079         */
080        private final Map<String, Map<ResidueNumber,Integer>> chains2pdbResNums2ResSerials;
081
082        private String refChainId;
083        private String description = null;
084        private String title = null;
085        /**
086         * The type of entity (polymer, non-polymer, water)
087         */
088        private EntityType type = null;
089        private List<String> synonyms = null;
090        private List<String> ecNums = null;
091        private String engineered = null;
092        private String mutation = null;
093        private String biologicalUnit = null;
094        private String details = null;
095        private String numRes = null;
096        private String resNames = null;
097        private String headerVars = null;
098        private String synthetic = null;
099        private String fragment = null;
100        private String organismScientific = null;
101        private String organismTaxId = null;
102        private String organismCommon = null;
103        private String strain = null;
104        private String variant = null;
105        private String cellLine = null;
106        private String atcc = null;
107        private String organ = null;
108        private String tissue = null;
109        private String cell = null;
110        private String organelle = null;
111        private String secretion = null;
112        private String gene = null;
113        private String cellularLocation = null;
114        private String expressionSystem = null;
115        private String expressionSystemTaxId = null;
116        private String expressionSystemStrain = null;
117        private String expressionSystemVariant = null;
118        private String expressionSystemCellLine = null;
119        private String expressionSystemAtccNumber = null;
120        private String expressionSystemOrgan = null;
121        private String expressionSystemTissue = null;
122        private String expressionSystemCell = null;
123        private String expressionSystemOrganelle = null;
124        private String expressionSystemCellularLocation = null;
125        private String expressionSystemVectorType = null;
126        private String expressionSystemVector = null;
127        private String expressionSystemPlasmid = null;
128        private String expressionSystemGene = null;
129        private String expressionSystemOtherDetails = null;
130
131        private Long id;
132
133        public EntityInfo () {
134                chains = new ArrayList<>();
135                chains2pdbResNums2ResSerials = new HashMap<>();
136                molId = -1;
137        }
138
139        /**
140         * Constructs a new EntityInfo copying all data from the given one
141         * but not setting the Chains
142         * @param c
143         */
144        public EntityInfo (EntityInfo c) {
145
146            this.id = c.id;
147
148                this.chains = new ArrayList<>();
149
150                this.chains2pdbResNums2ResSerials = new HashMap<>();
151
152                this.molId = c.molId;
153
154                this.type = c.type;
155
156                this.refChainId = c.refChainId;
157
158                this.description = c.description;
159                this.title = c.title;
160
161                if (c.synonyms!=null) {
162                        this.synonyms = new ArrayList<String>();
163                        synonyms.addAll(c.synonyms);
164                }
165                if (c.ecNums!=null) {
166                        this.ecNums = new ArrayList<String>();
167                        ecNums.addAll(c.ecNums);
168                }
169
170                this.engineered = c.engineered;
171                this.mutation = c.mutation;
172                this.biologicalUnit = c.biologicalUnit;
173                this.details = c.details;
174
175                this.numRes = c.numRes;
176                this.resNames = c.resNames;
177
178                this.headerVars = c.headerVars;
179
180                this.synthetic = c.synthetic;
181                this.fragment = c.fragment;
182                this.organismScientific = c.organismScientific;
183                this.organismTaxId = c.organismTaxId;
184                this.organismCommon = c.organismCommon;
185                this.strain = c.strain;
186                this.variant = c.variant;
187                this.cellLine = c.cellLine;
188                this.atcc = c.atcc;
189                this.organ = c.organ;
190                this.tissue = c.tissue;
191                this.cell = c.cell;
192                this.organelle = c.organelle;
193                this.secretion = c.secretion;
194                this.gene = c.gene;
195                this.cellularLocation = c.cellularLocation;
196                this.expressionSystem = c.expressionSystem;
197                this.expressionSystemTaxId = c.expressionSystemTaxId;
198                this.expressionSystemStrain = c.expressionSystemStrain;
199                this.expressionSystemVariant = c.expressionSystemVariant;
200                this.expressionSystemCellLine = c.expressionSystemCellLine;
201                this.expressionSystemAtccNumber = c.expressionSystemAtccNumber;
202                this.expressionSystemOrgan = c.expressionSystemOrgan;
203                this.expressionSystemTissue = c.expressionSystemTissue;
204                this.expressionSystemCell = c.expressionSystemCell;
205                this.expressionSystemOrganelle = c.expressionSystemOrganelle;
206                this.expressionSystemCellularLocation = c.expressionSystemCellularLocation;
207                this.expressionSystemVectorType = c.expressionSystemVectorType;
208                this.expressionSystemVector = c.expressionSystemVector;
209                this.expressionSystemPlasmid = c.expressionSystemPlasmid;
210                this.expressionSystemGene = c.expressionSystemGene;
211                this.expressionSystemOtherDetails = c.expressionSystemOtherDetails;
212
213
214        }
215
216        @Override
217        public String toString(){
218                StringBuilder buf = new StringBuilder();
219                buf.append("EntityInfo: ").append(molId).append(" ");
220                buf.append(description==null?"(no name)":"("+description+")");
221                buf.append(" asymIds: ");
222                if (chains!=null) {
223                        for (int i=0;i<chains.size();i++) {
224                                buf.append(chains.get(i).getId());
225                                if (i!=chains.size()-1) buf.append(",");
226                        }
227                } else {
228                        buf.append("no chains");
229                }
230                return buf.toString();
231        }
232
233        /**
234         * Get the representative Chain for this EntityInfo.
235         * We choose the Chain with the first asym_id chain identifier after
236         * lexicographical sorting (case insensitive),
237         * e.g. chain A if EntityInfo is composed of chains A,B,C,D,E
238         * @return
239         */
240        public Chain getRepresentative() {
241
242                List<String> chainIds = new ArrayList<>();
243                for (Chain chain:chains) {
244                        chainIds.add(chain.getId());
245                }
246
247                Collections.sort(chainIds, String.CASE_INSENSITIVE_ORDER);
248
249                for (Chain chain:chains) {
250                        if (chain.getId().equals(chainIds.get(0))) {
251                                return chain;
252                        }
253                }
254
255                logger.error("Could not find a representative chain for EntityInfo '{}'", this.toString());
256
257                return null;
258        }
259
260        /** get the ID used by Hibernate
261         *
262         * @return the ID used by Hibernate
263         */
264        public Long getId() {
265                return id;
266        }
267
268        /** set the ID used by Hibernate
269         *
270         * @param id
271         */
272        public void setId(Long id) {
273                this.id = id;
274        }
275
276        /**
277         * Return the list of member chain ids (asym ids) that are described by this EntityInfo,
278         * only unique chain IDs are contained in the list.
279         * Note that in the case of multimodel structures this will return just the unique
280         * chain identifiers whilst {@link #getChains()} will return a corresponding chain
281         * per model.
282         * @return the list of unique ChainIDs that are described by this EnityInfo
283         * @see #setChains(List)
284         * @see #getChains()
285         */
286        public List<String> getChainIds() {
287
288                Set<String> uniqChainIds = new TreeSet<>();
289                for (int i=0;i<getChains().size();i++) {
290                        uniqChainIds.add(getChains().get(i).getId());
291                }
292
293                return new ArrayList<>(uniqChainIds);
294        }
295
296        /**
297         * Given a Group g of Chain c (member of this EntityInfo) return the corresponding position in the
298         * alignment of all member sequences (1-based numbering), i.e. the index (1-based) in the SEQRES sequence.
299         * This allows for comparisons of residues belonging to different chains of the same EntityInfo (entity).
300         * <p>
301         * Note this method should only be used for entities of type {@link EntityType#POLYMER}
302         * <p>
303         * If {@link FileParsingParameters#setAlignSeqRes(boolean)} is not used or SEQRES not present, a mapping
304         * will not be available and this method will return {@link ResidueNumber#getSeqNum()} for all residues, which
305         * in some cases will be correctly aligned indices (when no insertion codes are
306         * used and when all chains within the entity are numbered in the same way), but
307         * in general they will be neither unique (because of insertion codes) nor aligned.
308         * </p>
309         * @param g the group
310         * @param c the chain
311         * @return the aligned residue index (1 to n), if no SEQRES groups are available at all then {@link ResidueNumber#getSeqNum()}
312         * is returned as a fall-back, if the group is not found in the SEQRES groups then -1 is returned
313         * for the given group and chain
314         * @throws IllegalArgumentException if the given Chain is not a member of this EntityInfo
315         * @see Chain#getSeqResGroup(int)
316         */
317        public int getAlignedResIndex(Group g, Chain c) {
318
319                boolean contained = false;
320                for (Chain member:getChains()) {
321                        if (c.getId().equals(member.getId())) {
322                                contained = true;
323                                break;
324                        }
325                }
326                if (!contained)
327                        throw new IllegalArgumentException("Given chain with asym_id "+c.getId()+" is not a member of this entity: "+getChainIds().toString());
328
329                if (!chains2pdbResNums2ResSerials.containsKey(c.getId())) {
330                        // we do lazy initialisation of the map
331                        initResSerialsMap(c);
332                }
333                // if no seqres groups are available at all the map will be null
334                Map<ResidueNumber,Integer> map = chains2pdbResNums2ResSerials.get(c.getId());
335                int serial;
336                if (map!=null) {
337
338                        ResidueNumber resNum = g.getResidueNumber();
339                        // the resNum will be null for groups that are SEQRES only and not in ATOM,
340                        // still it can happen that a group is in ATOM in one chain but not in other of the same entity.
341                        // This is what we try to find out here (analogously to what we do in initResSerialsMap() ):
342                        if (resNum==null && c.getSeqResGroups()!=null && !c.getSeqResGroups().isEmpty()) {
343
344                                int index = c.getSeqResGroups().indexOf(g);
345
346                                resNum = findResNumInOtherChains(index, c);
347
348                        }
349
350                        if (resNum == null) {
351                                // still null, we really can't map
352                                serial = -1;
353                        }
354                        else {
355
356                                Integer alignedSerial = map.get(resNum);
357
358                                if (alignedSerial==null) {
359                                        // the map doesn't contain this group, something's wrong: return -1
360                                        serial = -1;
361                                } else {
362                                        serial = alignedSerial;
363                                }
364                        }
365
366                } else {
367                        // no seqres groups available we resort to using the pdb residue numbers are given
368                        serial = g.getResidueNumber().getSeqNum();
369                }
370                return serial;
371        }
372
373        private void initResSerialsMap(Chain c) {
374                if (c.getSeqResGroups()==null || c.getSeqResGroups().isEmpty()) {
375                        logger.warn("No SEQRES groups found in chain with asym_id {}, will use residue numbers as given (no insertion codes, not necessarily aligned). "
376                                        + "Make sure your structure has SEQRES records and that you use FileParsingParameters.setAlignSeqRes(true)",
377                                        c.getId());
378                        // we add a explicit null to the map so that we flag it as unavailable for this chain
379                        chains2pdbResNums2ResSerials.put(c.getId(), null);
380                        return;
381                }
382
383                Map<ResidueNumber,Integer> resNums2ResSerials = new HashMap<ResidueNumber, Integer>();
384                chains2pdbResNums2ResSerials.put(c.getId(), resNums2ResSerials);
385
386                for (int i=0;i<c.getSeqResGroups().size();i++) {
387
388                        // The seqres group will have a null residue number whenever its corresponding atom group doesn't exist
389                        // because it is missing in the electron density.
390                        // However, it can be observed in the density in other chains of the same entity,
391                        // to be complete we go and look for the residue number in other chains, so that we have a
392                        // seqres to atom mapping as complete as possible (with all known atom groups of any chain of this entity)
393
394                        ResidueNumber resNum = c.getSeqResGroup(i).getResidueNumber();
395
396                        if (resNum==null) {
397                                resNum = findResNumInOtherChains(i,c);
398                        }
399
400                        // NOTE that resNum will still be null here for cases where the residue
401                        // is missing in atom groups (not observed in density) in all chains
402                        // Thus the mapping will not be possible for residues that are only in SEQRES groups
403                        resNums2ResSerials.put(resNum, i+1);
404                }
405        }
406
407        private ResidueNumber findResNumInOtherChains(int i, Chain chain) {
408
409                // note that getChains contains all chains from all models, we'll just use first model found and skip the others
410                for (Chain c: getFirstModelChains()) {
411
412                        if (c == chain) continue;
413
414                        Group seqResGroup = c.getSeqResGroup(i);
415
416                        if (seqResGroup==null) {
417                                logger.warn("The SEQRES group is null for index {} in chain with asym_id {}, whilst it wasn't null in chain with asym_id {}",
418                                                 i, c.getId(), chain.getId());
419                                continue;
420                        }
421
422                        if (seqResGroup.getResidueNumber()!=null) return seqResGroup.getResidueNumber();
423
424                }
425
426                return null;
427        }
428
429        /**
430         * Return the ref chain id value.
431         * @return the RefChainID
432         * @see #setRefChainId(String)
433         */
434        public String getRefChainId() {
435                return refChainId;
436        }
437
438        /**
439         * Return the ref chain id value.
440         * @param refChainId the RefChainID
441         * @see #getRefChainId()
442         */
443        public void setRefChainId(String refChainId) {
444                this.refChainId = refChainId;
445        }
446
447        /**
448         * Return the molecule identifier, called entity_id in mmCIF dictionary.
449         * @return the molecule id
450         * @see #setMolId(int)
451         */
452        public int getMolId() {
453                return molId;
454        }
455
456        /**
457         * Set the molecule identifier, called entity_id in mmCIF dictionary.
458         * @param molId the molecule id
459         * @see #getMolId()
460         */
461        public void setMolId(int molId) {
462                this.molId = molId;
463        }
464
465        public String getDescription() {
466                return description;
467        }
468
469        public void setDescription(String molName) {
470                this.description = molName;
471        }
472
473        public String getTitle() {
474                return title;
475        }
476
477        public void setTitle(String title) {
478                this.title = title;
479        }
480
481        public List<String> getSynonyms() {
482                return synonyms;
483        }
484
485        public void setSynonyms(List<String> synonyms) {
486                this.synonyms = synonyms;
487        }
488
489        public List<String> getEcNums() {
490                return ecNums;
491        }
492
493        public void setEcNums(List<String> ecNums) {
494                this.ecNums = ecNums;
495        }
496
497        public String getEngineered() {
498                return engineered;
499        }
500
501        public void setEngineered(String engineered) {
502                this.engineered = engineered;
503        }
504
505        public String getMutation() {
506                return mutation;
507        }
508
509        public void setMutation(String mutation) {
510                this.mutation = mutation;
511        }
512
513        public String getBiologicalUnit() {
514                return biologicalUnit;
515        }
516
517        public void setBiologicalUnit(String biologicalUnit) {
518                this.biologicalUnit = biologicalUnit;
519        }
520
521        public String getDetails() {
522                return details;
523        }
524
525        public void setDetails(String details) {
526                this.details = details;
527        }
528
529        public String getNumRes() {
530                return numRes;
531        }
532
533        public void setNumRes(String numRes) {
534                this.numRes = numRes;
535        }
536
537        public String getResNames() {
538                return resNames;
539        }
540
541        public void setResNames(String resNames) {
542                this.resNames = resNames;
543        }
544
545        public String getHeaderVars() {
546                return headerVars;
547        }
548
549        public void setHeaderVars(String headerVars) {
550                this.headerVars = headerVars;
551        }
552
553        public String getSynthetic() {
554                return synthetic;
555        }
556
557        public void setSynthetic(String synthetic) {
558                this.synthetic = synthetic;
559        }
560
561        public String getFragment() {
562                return fragment;
563        }
564
565        public void setFragment(String fragment) {
566                this.fragment = fragment;
567        }
568
569        public String getOrganismScientific() {
570                return organismScientific;
571        }
572
573        public void setOrganismScientific(String organismScientific) {
574                this.organismScientific = organismScientific;
575        }
576
577        public String getOrganismTaxId() {
578                return organismTaxId;
579        }
580
581        public void setOrganismTaxId(String organismTaxId) {
582                this.organismTaxId = organismTaxId;
583        }
584
585        public String getOrganismCommon() {
586                return organismCommon;
587        }
588
589        public void setOrganismCommon(String organismCommon) {
590                this.organismCommon = organismCommon;
591        }
592
593        public String getStrain() {
594                return strain;
595        }
596
597        public void setStrain(String strain) {
598                this.strain = strain;
599        }
600
601        public String getVariant() {
602                return variant;
603        }
604
605        public void setVariant(String variant) {
606                this.variant = variant;
607        }
608
609        public String getCellLine() {
610                return cellLine;
611        }
612
613        public void setCellLine(String cellLine) {
614                this.cellLine = cellLine;
615        }
616
617        public String getAtcc() {
618                return atcc;
619        }
620
621        public void setAtcc(String atcc) {
622                this.atcc = atcc;
623        }
624
625        public String getOrgan() {
626                return organ;
627        }
628
629        public void setOrgan(String organ) {
630                this.organ = organ;
631        }
632
633        public String getTissue() {
634                return tissue;
635        }
636
637        public void setTissue(String tissue) {
638                this.tissue = tissue;
639        }
640
641        public String getCell() {
642                return cell;
643        }
644
645        public void setCell(String cell) {
646                this.cell = cell;
647        }
648
649        public String getOrganelle() {
650                return organelle;
651        }
652
653        public void setOrganelle(String organelle) {
654                this.organelle = organelle;
655        }
656
657        public String getSecretion() {
658                return secretion;
659        }
660
661        public void setSecretion(String secretion) {
662                this.secretion = secretion;
663        }
664
665        public String getGene() {
666                return gene;
667        }
668
669        public void setGene(String gene) {
670                this.gene = gene;
671        }
672
673        public String getCellularLocation() {
674                return cellularLocation;
675        }
676
677        public void setCellularLocation(String cellularLocation) {
678                this.cellularLocation = cellularLocation;
679        }
680
681        public String getExpressionSystem() {
682                return expressionSystem;
683        }
684
685        public String getExpressionSystemTaxId() {
686                return expressionSystemTaxId;
687        }
688
689        public void setExpressionSystemTaxId(String expressionSystemTaxId) {
690                this.expressionSystemTaxId = expressionSystemTaxId;
691        }
692
693        public void setExpressionSystem(String expressionSystem) {
694                this.expressionSystem = expressionSystem;
695        }
696
697        public String getExpressionSystemStrain() {
698                return expressionSystemStrain;
699        }
700
701        public void setExpressionSystemStrain(String expressionSystemStrain) {
702                this.expressionSystemStrain = expressionSystemStrain;
703        }
704
705        public String getExpressionSystemVariant() {
706                return expressionSystemVariant;
707        }
708
709        public void setExpressionSystemVariant(String expressionSystemVariant) {
710                this.expressionSystemVariant = expressionSystemVariant;
711        }
712
713        public String getExpressionSystemCellLine() {
714                return expressionSystemCellLine;
715        }
716
717        public void setExpressionSystemCellLine(String expressionSystemCellLine) {
718                this.expressionSystemCellLine = expressionSystemCellLine;
719        }
720
721        public String getExpressionSystemAtccNumber() {
722                return expressionSystemAtccNumber;
723        }
724
725        public void setExpressionSystemAtccNumber(String expressionSystemAtccNumber) {
726                this.expressionSystemAtccNumber = expressionSystemAtccNumber;
727        }
728
729        public String getExpressionSystemOrgan() {
730                return expressionSystemOrgan;
731        }
732
733        public void setExpressionSystemOrgan(String expressionSystemOrgan) {
734                this.expressionSystemOrgan = expressionSystemOrgan;
735        }
736
737        public String getExpressionSystemTissue() {
738                return expressionSystemTissue;
739        }
740
741        public void setExpressionSystemTissue(String expressionSystemTissue) {
742                this.expressionSystemTissue = expressionSystemTissue;
743        }
744
745        public String getExpressionSystemCell() {
746                return expressionSystemCell;
747        }
748
749        public void setExpressionSystemCell(String expressionSystemCell) {
750                this.expressionSystemCell = expressionSystemCell;
751        }
752
753        public String getExpressionSystemOrganelle() {
754                return expressionSystemOrganelle;
755        }
756
757        public void setExpressionSystemOrganelle(String expressionSystemOrganelle) {
758                this.expressionSystemOrganelle = expressionSystemOrganelle;
759        }
760
761        public String getExpressionSystemCellularLocation() {
762                return expressionSystemCellularLocation;
763        }
764
765        public void setExpressionSystemCellularLocation(String expressionSystemCellularLocation) {
766                this.expressionSystemCellularLocation = expressionSystemCellularLocation;
767        }
768
769        public String getExpressionSystemVectorType() {
770                return expressionSystemVectorType;
771        }
772
773        public void setExpressionSystemVectorType(String expressionSystemVectorType) {
774                this.expressionSystemVectorType = expressionSystemVectorType;
775        }
776
777        public String getExpressionSystemVector() {
778                return expressionSystemVector;
779        }
780
781        public void setExpressionSystemVector(String expressionSystemVector) {
782                this.expressionSystemVector = expressionSystemVector;
783        }
784
785        public String getExpressionSystemPlasmid() {
786                return expressionSystemPlasmid;
787        }
788
789        public void setExpressionSystemPlasmid(String expressionSystemPlasmid) {
790                this.expressionSystemPlasmid = expressionSystemPlasmid;
791        }
792
793        public String getExpressionSystemGene() {
794                return expressionSystemGene;
795        }
796
797        public void setExpressionSystemGene(String expressionSystemGene) {
798                this.expressionSystemGene = expressionSystemGene;
799        }
800
801        public String getExpressionSystemOtherDetails() {
802                return expressionSystemOtherDetails;
803        }
804
805        public void setExpressionSystemOtherDetails(String expressionSystemOtherDetails) {
806                this.expressionSystemOtherDetails = expressionSystemOtherDetails;
807        }
808
809        /**
810         * Get the list of chains that are part of this EntityInfo. Note that for multi-model
811         * structures chains from all models are returned.
812         *
813         * @return a List of Chain objects
814         */
815        public List<Chain> getChains(){
816                return this.chains;
817        }
818
819        private List<Chain> getFirstModelChains() {
820
821                Map<String, Chain> firstModelChains = new LinkedHashMap<>();
822                Set<String> lookupChainIds = new HashSet<>(getChainIds());
823
824                for (Chain chain : chains) {
825                        if (lookupChainIds.contains(chain.getId())) {
826                                if (!firstModelChains.containsKey(chain.getId())) {
827                                        firstModelChains.put(chain.getId(), chain);
828                                }
829                        }
830                }
831
832                return new ArrayList<>(firstModelChains.values());
833        }
834
835         /**
836          * Add new Chain to this EntityInfo
837          * @param chain
838          */
839        public void addChain(Chain chain){
840                this.chains.add(chain);
841        }
842
843        /**
844         * Set the chains for this EntityInfo
845         * @param chains
846         */
847        public void setChains(List<Chain> chains){
848                this.chains = chains;
849        }
850
851        /**
852         * Get the type of entity this EntityInfo describes.
853         * Options are polymer, non-polymer or water.
854         * @return a string describing the type of entity. (polymer, non-polymer or water).
855         */
856        public EntityType getType() {
857                return this.type;
858        }
859
860        /**
861         * Set the type of entity this EntityInfo describes.
862         * Options are polymer, non-polymer or water.
863         * @param type a string describing the type of entity. (polymer, non-polymer or water).
864         */
865        public void setType(EntityType type) {
866                this.type = type;
867        }
868}