001package org.biopax.paxtools.io.sif.level2; 002 003import org.biopax.paxtools.io.sif.BinaryInteractionType; 004import org.biopax.paxtools.io.sif.InteractionSet; 005import org.biopax.paxtools.io.sif.SimpleInteraction; 006import org.biopax.paxtools.model.Model; 007import org.biopax.paxtools.model.level2.*; 008import org.biopax.paxtools.util.ClassFilterSet; 009 010import java.util.*; 011 012import static org.biopax.paxtools.io.sif.BinaryInteractionType.SEQUENTIAL_CATALYSIS; 013 014/** 015 * This class creates an interaction between two entities if they are catalyzing 016 * consecutive conversions. Conversions are considered consecutive if one of the 017 * RIGHT participants of one reaction is the LEFT of the other and if the 018 * directions of catalysis and control matches. User: demir Date: Dec 28, 2007 019 * Time: 10:40:01 PM 020 */ 021public class ConsecutiveCatalysisRule extends InteractionRuleL2Adaptor 022{ 023 /** 024 * Supported interaction types. 025 */ 026 private static List<BinaryInteractionType> binaryInteractionTypes = 027 Arrays.asList(SEQUENTIAL_CATALYSIS); 028 029 /** 030 * Infers using the given physicalEntity as source. 031 * @param interactionSet to be populated 032 * @param pe source of the interaction 033 * @param model BioPAX model 034 */ 035 public void inferInteractionsFromPE(InteractionSet interactionSet, physicalEntity pe, Model model) 036 { 037 Set<catalysis> catalyses = pe.getAllInteractions(catalysis.class); 038 for (catalysis aCatalysis : catalyses) 039 { 040 processCatalysis(interactionSet, pe, aCatalysis); 041 } 042 } 043 044 /** 045 * Continues inference through the given catalysis. 046 * @param interactionSet to populate 047 * @param pe source 048 * @param aCatalysis catalysis to process 049 */ 050 private void processCatalysis(InteractionSet interactionSet, physicalEntity pe, catalysis aCatalysis) 051 { 052 //We have to consider two direction statements 053 //Catalysis.direction and Conversion.spontaneous 054 //This method maps the former to the compatible latter 055 //null means reversible or unknown, both are treated in the same way. 056 SpontaneousType catalysisDirection = mapDirectionToSpontaneous(aCatalysis.getDIRECTION()); 057 //get the conversions and process them. 058 Set<process> controlled = aCatalysis.getCONTROLLED(); 059 for (process process : controlled) 060 { 061 conversion aConversion = (conversion) process; 062 //let's find the direction that is compatible with catalysis direction 063 SpontaneousType direction = findConsensusDirection(catalysisDirection, aConversion.getSPONTANEOUS()); 064 assert direction != null; 065 //and let's get the interacting physical entities 066 createInteractions(aConversion, direction, pe, aCatalysis, interactionSet); 067 } 068 } 069 070 /** 071 * This method finds the compatible conversion and catalysis direction. 072 * @param direction1 type implied by catalysis 073 * @param direction2 type of the conversion 074 * @return consensus direction 075 */ 076 private SpontaneousType findConsensusDirection(SpontaneousType direction1, SpontaneousType direction2) 077 { 078 SpontaneousType consensus; 079 boolean first = isReversible(direction1); 080 boolean second = isReversible(direction2); 081 // If any one of them is not-spontaneous than consensus is the other direction. 082 // If both of them are spontaneous, then consensus is null if they are spontenous 083 // in opposite directions. 084 if (first) 085 { 086 if (second) 087 { 088 consensus = SpontaneousType.NOT_SPONTANEOUS; 089 } else 090 { 091 consensus = direction2; 092 } 093 } else 094 { 095 if (second) 096 { 097 consensus = direction1; 098 } else 099 { 100 consensus = direction1.equals(direction2) ? direction1 : null; 101 } 102 } 103 return consensus; 104 } 105 106 /** 107 * Checks if the direction can be treated as reversible. 108 * @param direction1 direction to check 109 * @return true if reversible or null 110 */ 111 private boolean isReversible(SpontaneousType direction1) 112 { 113 return direction1 == null || direction1.equals(SpontaneousType.NOT_SPONTANEOUS); 114 } 115 116 /** 117 * Continues inference with the given conversion, catalysis and direction. 118 * @param centerConversion first conversion 119 * @param direction direction of the center conversion traversed 120 * @param pe source of interaction 121 * @param aCatalysis catalysis where source is the controller 122 * @param interactionSet 123 */ 124 private void createInteractions(conversion centerConversion, SpontaneousType direction, 125 physicalEntity pe, catalysis aCatalysis, InteractionSet interactionSet) 126 { 127 //get the peps at the correct side of the conversion. 128 Set<physicalEntityParticipant> peps = getCompatiblePEPs(direction, centerConversion); 129 //for these set of peps find compatible conversions 130 Set<conversion> conversions = getCompatibleConversions(peps, direction); 131 132 // for each conversion find pes that catalyze them and add an interaction 133 for (conversion neighbor : conversions) 134 { 135 findAndAddCatalysts(neighbor, direction, pe, aCatalysis, interactionSet); 136 } 137 } 138 139 /** 140 * This method returns the PEPs that are on the correct side of the conversion. 141 * @param direction determining the side 142 * @param aConversion conversion to get PEPs 143 * @return PEPs that are at the desired side 144 */ 145 private Set<physicalEntityParticipant> getCompatiblePEPs(SpontaneousType direction, conversion aConversion) 146 { 147 switch (direction) 148 { 149 case L_R: 150 return aConversion.getRIGHT(); 151 case R_L: 152 return aConversion.getLEFT(); 153 default: 154 return mergedSet(aConversion); 155 } 156 } 157 158 /** 159 * Gets left and right participants of the conversion. 160 * @param aConversion conversion to get left and right participants 161 * @return left and right participants of the conversion 162 */ 163 private HashSet<physicalEntityParticipant> mergedSet(conversion aConversion) 164 { 165 HashSet<physicalEntityParticipant> hashSet = new HashSet<physicalEntityParticipant>(); 166 hashSet.addAll(aConversion.getLEFT()); 167 hashSet.addAll(aConversion.getRIGHT()); 168 return hashSet; 169 } 170 171 /** 172 * Gets the second conversions compatible with the current elements already traversed. 173 * @param peps PEP that are input or output to the conversion 174 * @param direction traversed direction of the first conversion 175 * @return compatible conversions 176 */ 177 private Set<conversion> getCompatibleConversions(Set<physicalEntityParticipant> peps, SpontaneousType direction) 178 { 179 Set<conversion> compatibleConversions = new HashSet<conversion>(); 180 for (physicalEntityParticipant pep : peps) 181 { 182 Set<physicalEntityParticipant> npeps = pep.getPHYSICAL_ENTITY().isPHYSICAL_ENTITYof(); 183 for (physicalEntityParticipant npep : npeps) 184 { 185 if (!pep.equals(npep) && pep.isInEquivalentState(npep)) 186 { 187 if (!npep.isPARTICIPANTSof().isEmpty()) 188 { 189 assert npep.isPARTICIPANTSof().size() == 1; 190 interaction anI = npep.isPARTICIPANTSof().iterator().next(); 191 192 if (anI instanceof conversion) 193 { 194 conversion aConversion = (conversion) anI; 195 196 if (findConsensusDirection(direction, aConversion.getSPONTANEOUS()) != null && 197 participantIsAtACompatibleSide(direction, npep, aConversion)) 198 { 199 compatibleConversions.add(aConversion); 200 } 201 } 202 } 203 } 204 } 205 } 206 return compatibleConversions; 207 } 208 209 /** 210 * Checks if the placement of participant is compatible with the traversal direction. 211 * @param direction direction traversed 212 * @param npep participant to check 213 * @param aConversion the conversion 214 * @return true if the participant is at a compatible side 215 */ 216 private boolean participantIsAtACompatibleSide(SpontaneousType direction, 217 physicalEntityParticipant npep, conversion aConversion) 218 { 219 switch (direction) 220 { 221 case L_R: 222 return aConversion.getLEFT().contains(npep); 223 case R_L: 224 return aConversion.getRIGHT().contains(npep); 225 default: 226 return aConversion.getRIGHT().contains(npep) || aConversion.getLEFT().contains(npep); 227 } 228 } 229 230 /** 231 * Creates interactions with the catalysis of the second conversion. 232 * @param aConversion second conversion 233 * @param direction direction of the second conversion traversed 234 * @param pe source 235 * @param aCatalysis catalysis of the second conversion 236 * @param interactionSet to populate 237 */ 238 private void findAndAddCatalysts(conversion aConversion, SpontaneousType direction, 239 physicalEntity pe, catalysis aCatalysis, InteractionSet interactionSet) 240 { 241 Set<control> controls = aConversion.isCONTROLLEDOf(); 242 for (catalysis consequentCatalysis : new ClassFilterSet<control, catalysis>(controls, catalysis.class)) 243 { 244 if (findConsensusDirection(direction, mapDirectionToSpontaneous(consequentCatalysis.getDIRECTION())) != 245 null) 246 { 247 for (physicalEntityParticipant pepi : consequentCatalysis.getCONTROLLER()) 248 { 249 //create interactions and add to set 250 SimpleInteraction si = new SimpleInteraction(pe, pepi.getPHYSICAL_ENTITY(), SEQUENTIAL_CATALYSIS); 251 si.addMediator(aCatalysis); 252 si.addMediator(consequentCatalysis); 253 interactionSet.add(si); 254 } 255 } 256 } 257 } 258 259 /** 260 * Converts directions. 261 * @param direction direction to convert 262 * @return equivalent direction 263 */ 264 private SpontaneousType mapDirectionToSpontaneous(Direction direction) 265 { 266 if (direction != null) 267 { 268 switch (direction) 269 { 270 case IRREVERSIBLE_LEFT_TO_RIGHT: 271 case PHYSIOL_LEFT_TO_RIGHT: 272 return SpontaneousType.L_R; 273 case IRREVERSIBLE_RIGHT_TO_LEFT: 274 case PHYSIOL_RIGHT_TO_LEFT: 275 return SpontaneousType.R_L; 276 } 277 } 278 return null; 279 } 280 281 /** 282 * Gets supported interaction types. 283 * @return supported interaction types 284 */ 285 public List<BinaryInteractionType> getRuleTypes() 286 { 287 return binaryInteractionTypes; 288 } 289}