1 /* 2 * Jalview - A Sequence Alignment Editor and Viewer (2.11.1.4) 3 * Copyright (C) 2021 The Jalview Authors 4 * 5 * This file is part of Jalview. 6 * 7 * Jalview is free software: you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation, either version 3 10 * of the License, or (at your option) any later version. 11 * 12 * Jalview is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty 14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 15 * PURPOSE. See the GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>. 19 * The Jalview Authors are detailed in the 'AUTHORS' file. 20 */ 21 package jalview.io.vamsas; 22 23 import jalview.datamodel.AlignedCodonFrame; 24 import jalview.datamodel.AlignmentI; 25 import jalview.datamodel.Mapping; 26 import jalview.datamodel.SequenceI; 27 import jalview.gui.Desktop; 28 import jalview.io.VamsasAppDatastore; 29 30 import java.util.Vector; 31 32 import uk.ac.vamsas.objects.core.AlignmentSequence; 33 import uk.ac.vamsas.objects.core.DataSet; 34 import uk.ac.vamsas.objects.core.Sequence; 35 import uk.ac.vamsas.objects.core.SequenceMapping; 36 import uk.ac.vamsas.objects.core.SequenceType; 37 38 /** 39 * binds a vamsas sequence mapping object from the vamsas document to a maplist 40 * object associated with a mapping in the Jalview model. We use the maplist 41 * object because these are referred to both in the Mapping object associated 42 * with a jalview.datamodel.DBRefEntry and in the array of 43 * jalview.datamodel.AlCodonFrame objects that Jalview uses to propagate 44 * sequence mapping position highlighting across the views. 45 * 46 * @author JimP 47 * 48 */ 49 public class Sequencemapping extends Rangetype 50 { Sequencemapping(VamsasAppDatastore datastore, SequenceMapping sequenceMapping)51 public Sequencemapping(VamsasAppDatastore datastore, 52 SequenceMapping sequenceMapping) 53 { 54 super(datastore, sequenceMapping, jalview.util.MapList.class); 55 doJvUpdate(); 56 } 57 58 private SequenceType from; 59 60 private DataSet ds; 61 62 private Mapping mjvmapping; 63 64 /** 65 * create or update a vamsas sequence mapping corresponding to a jalview 66 * Mapping between two dataset sequences 67 * 68 * @param datastore 69 * @param mjvmapping 70 * @param from 71 * @param ds 72 */ Sequencemapping(VamsasAppDatastore datastore, jalview.datamodel.Mapping mjvmapping, uk.ac.vamsas.objects.core.SequenceType from, uk.ac.vamsas.objects.core.DataSet ds)73 public Sequencemapping(VamsasAppDatastore datastore, 74 jalview.datamodel.Mapping mjvmapping, 75 uk.ac.vamsas.objects.core.SequenceType from, 76 uk.ac.vamsas.objects.core.DataSet ds) 77 { 78 super(datastore, mjvmapping.getMap(), SequenceMapping.class); 79 this.from = from; 80 this.ds = ds; 81 this.mjvmapping = mjvmapping; 82 validate(); 83 doSync(); 84 } 85 86 /** 87 * local check that extant mapping context is valid 88 */ validate()89 public void validate() 90 { 91 92 SequenceMapping sequenceMapping = (SequenceMapping) vobj; 93 if (sequenceMapping == null) 94 { 95 return; 96 } 97 if (from != null && sequenceMapping.getLoc() != from) 98 { 99 jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from 100 + " doesn't match the local mapping sequence."); 101 } 102 if (ds != null && sequenceMapping.is__stored_in_document() 103 && sequenceMapping.getV_parent() != ds) 104 { 105 jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + ds 106 + " doesn't match the parent of the bound sequence mapping object."); 107 } 108 } 109 addToDocument()110 public void addToDocument() 111 { 112 add(mjvmapping, from, ds); 113 } 114 addFromDocument()115 public void addFromDocument() 116 { 117 add((SequenceMapping) vobj); 118 } 119 conflict()120 public void conflict() 121 { 122 conflict(mjvmapping, (SequenceMapping) vobj); 123 124 } 125 updateToDoc()126 public void updateToDoc() 127 { 128 update(mjvmapping, (SequenceMapping) vobj); 129 } 130 updateFromDoc()131 public void updateFromDoc() 132 { 133 update((SequenceMapping) vobj, (jalview.datamodel.Mapping) jvobj); 134 } 135 conflict(Mapping mjvmapping, SequenceMapping sequenceMapping)136 private void conflict(Mapping mjvmapping, SequenceMapping sequenceMapping) 137 { 138 System.err.println("Conflict in update of sequenceMapping " 139 + sequenceMapping.getVorbaId()); 140 } 141 add(Mapping mjvmapping, uk.ac.vamsas.objects.core.SequenceType from, DataSet ds)142 private void add(Mapping mjvmapping, 143 uk.ac.vamsas.objects.core.SequenceType from, DataSet ds) 144 { 145 SequenceI jvto = mjvmapping.getTo(); 146 while (jvto.getDatasetSequence() != null) 147 { 148 jvto = jvto.getDatasetSequence(); 149 } 150 SequenceType to = (SequenceType) getjv2vObj(jvto); 151 if (to == null) 152 { 153 jalview.bin.Cache.log.warn( 154 "FIXME NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object"); 155 return; 156 } 157 SequenceMapping sequenceMapping = new SequenceMapping(); 158 sequenceMapping.setLoc(from); 159 sequenceMapping.setMap(to); 160 boolean dnaToProt = false, sense = false; 161 // ensure that we create a mapping with the correct sense 162 if (((Sequence) sequenceMapping.getLoc()).getDictionary().equals( 163 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA)) 164 { 165 if (((Sequence) sequenceMapping.getMap()).getDictionary().equals( 166 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA)) 167 { 168 dnaToProt = true; 169 sense = true; 170 } 171 } 172 else 173 { 174 if (((Sequence) sequenceMapping.getMap()).getDictionary().equals( 175 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA)) 176 { 177 dnaToProt = true; 178 sense = false; 179 } 180 } 181 182 if (!dnaToProt) 183 { 184 jalview.bin.Cache.log.warn( 185 "Ignoring Mapping - don't support protein to protein mapping in vamsas document yet."); 186 return; 187 } 188 if (ds == null) 189 { 190 // locate dataset for storage of SequenceMapping 191 if (sense) 192 { 193 ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping 194 .getLoc()).getV_parent(); 195 } 196 else 197 { 198 ds = (DataSet) ((uk.ac.vamsas.client.Vobject) sequenceMapping 199 .getMap()).getV_parent(); 200 } 201 } 202 if (sense) 203 { 204 this.initMapType(sequenceMapping, mjvmapping.getMap(), true); 205 } 206 else 207 { 208 this.initMapType(sequenceMapping, mjvmapping.getMap().getInverse(), 209 true); 210 } 211 ds.addSequenceMapping(sequenceMapping); 212 sequenceMapping.setProvenance( 213 this.dummyProvenance("user defined coding region translation")); // TODO: 214 // correctly 215 // construct 216 // provenance 217 // based 218 // on 219 // source 220 // of 221 // mapping 222 bindjvvobj(mjvmapping.getMap(), sequenceMapping); 223 224 jalview.bin.Cache.log.debug( 225 "Successfully created mapping " + sequenceMapping.getVorbaId()); 226 } 227 228 // private void update(jalview.util.MapList mjvmapping, 229 // SequenceMapping sequenceMapping) 230 { 231 jalview.bin.Cache.log 232 .error("Not implemented: Jalview Update Alcodon Mapping:TODO!"); 233 } 234 update(SequenceMapping sequenceMapping, jalview.datamodel.Mapping mjvmapping)235 private void update(SequenceMapping sequenceMapping, 236 jalview.datamodel.Mapping mjvmapping) 237 { 238 jalview.bin.Cache.log 239 .error("Not implemented: Update DBRef Mapping from Jalview"); 240 } 241 update(jalview.datamodel.Mapping mjvmapping, SequenceMapping sequenceMapping)242 private void update(jalview.datamodel.Mapping mjvmapping, 243 SequenceMapping sequenceMapping) 244 { 245 jalview.bin.Cache.log.error( 246 "Not implemented: Jalview Update Sequence DBRef Mapping"); 247 } 248 249 /** 250 * bind a SequenceMapping to a live AlCodonFrame element limitations: 251 * Currently, jalview only deals with mappings between dataset sequences, and 252 * even then, only between those that map from DNA to Protein. 253 * 254 * @param sequenceMapping 255 */ add(SequenceMapping sequenceMapping)256 private void add(SequenceMapping sequenceMapping) 257 { 258 Object mobj; 259 SequenceI from = null, to = null; 260 boolean dnaToProt = false, sense = false; 261 Sequence sdloc = null, sdmap = null; 262 if (sequenceMapping.getLoc() instanceof AlignmentSequence) 263 { 264 sdloc = (Sequence) ((AlignmentSequence) sequenceMapping.getLoc()) 265 .getRefid(); 266 } 267 else 268 { 269 sdloc = ((Sequence) sequenceMapping.getLoc()); 270 } 271 if (sequenceMapping.getMap() instanceof AlignmentSequence) 272 { 273 sdmap = (Sequence) ((AlignmentSequence) sequenceMapping.getMap()) 274 .getRefid(); 275 } 276 else 277 { 278 sdmap = ((Sequence) sequenceMapping.getMap()); 279 } 280 if (sdloc == null || sdmap == null) 281 { 282 jalview.bin.Cache.log.info("Ignoring non sequence-sequence mapping"); 283 return; 284 } 285 mobj = this.getvObj2jv(sdloc); 286 if (mobj instanceof SequenceI) 287 { 288 from = (SequenceI) mobj; 289 } 290 mobj = this.getvObj2jv(sdmap); 291 if (mobj instanceof SequenceI) 292 { 293 to = (SequenceI) mobj; 294 } 295 if (from == null || to == null) 296 { 297 298 jalview.bin.Cache.log.error( 299 "Probable Vamsas implementation error : unbound dataset sequences involved in a mapping are being parsed!"); 300 return; 301 } 302 303 if (sdloc.getDictionary().equals( 304 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA)) 305 { 306 if (sdmap.getDictionary().equals( 307 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA)) 308 { 309 dnaToProt = true; 310 sense = true; 311 } 312 // else { 313 314 // } 315 } 316 else 317 { 318 if (sdmap.getDictionary().equals( 319 uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA)) 320 { 321 dnaToProt = true; 322 sense = false; 323 } 324 } 325 // create mapping storage object and make each dataset alignment reference 326 // it. 327 AlignmentI dsLoc = (AlignmentI) getvObj2jv(sdloc.getV_parent()); 328 AlignmentI dsMap = (AlignmentI) getvObj2jv(sdmap.getV_parent()); 329 AlignedCodonFrame acf = new AlignedCodonFrame(); 330 331 if (dsLoc != null && dsLoc != dsMap) 332 { 333 dsLoc.addCodonFrame(acf); 334 } 335 if (dsMap != null) 336 { 337 dsMap.addCodonFrame(acf); 338 } 339 // create and add the new mapping to (each) dataset's codonFrame 340 341 jalview.util.MapList mapping = null; 342 if (dnaToProt) 343 { 344 if (!sense) 345 { 346 mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense 347 mapping = new jalview.util.MapList(mapping.getToRanges(), 348 mapping.getFromRanges(), mapping.getToRatio(), 349 mapping.getFromRatio()); 350 acf.addMap(to, from, mapping); 351 } 352 else 353 { 354 mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense 355 acf.addMap(from, to, mapping); 356 } 357 } 358 else 359 { 360 mapping = this.parsemapType(sequenceMapping, 1, 1); // correct sense 361 acf.addMap(from, to, mapping); 362 } 363 bindjvvobj(mapping, sequenceMapping); 364 jalview.structure.StructureSelectionManager 365 .getStructureSelectionManager(Desktop.instance) 366 .registerMapping(acf); 367 // Try to link up any conjugate database references in the two sequences 368 // matchConjugateDBRefs(from, to, mapping); 369 // Try to propagate any dbrefs across this mapping. 370 371 } 372 373 /** 374 * Complete any 'to' references in jalview.datamodel.Mapping objects 375 * associated with conjugate DBRefEntry under given mapping 376 * 377 * @param from 378 * sequence corresponding to from reference for sequence mapping 379 * @param to 380 * sequence correspondeing to to reference for sequence mapping 381 * @param smap 382 * maplist parsed in same sense as from and to 383 */ matchConjugateDBRefs(SequenceI from, SequenceI to, jalview.util.MapList smap)384 private void matchConjugateDBRefs(SequenceI from, SequenceI to, 385 jalview.util.MapList smap) 386 { 387 if (from.getDBRefs() == null && to.getDBRefs() == null) 388 { 389 if (jalview.bin.Cache.log.isDebugEnabled()) 390 { 391 jalview.bin.Cache.log.debug("Not matching conjugate refs for " 392 + from.getName() + " and " + to.getName()); 393 } 394 return; 395 } 396 if (jalview.bin.Cache.log.isDebugEnabled()) 397 { 398 jalview.bin.Cache.log.debug("Matching conjugate refs for " 399 + from.getName() + " and " + to.getName()); 400 } 401 jalview.datamodel.DBRefEntry[] fdb = from.getDBRefs(); 402 jalview.datamodel.DBRefEntry[] tdb = new jalview.datamodel.DBRefEntry[to 403 .getDBRefs().length]; 404 int tdblen = to.getDBRefs().length; 405 System.arraycopy(to.getDBRefs(), 0, tdb, 0, tdblen); 406 Vector matched = new Vector(); 407 jalview.util.MapList smapI = smap.getInverse(); 408 for (int f = 0; f < fdb.length; f++) 409 { 410 jalview.datamodel.DBRefEntry fe = fdb[f]; 411 jalview.datamodel.Mapping fmp = fe.getMap(); 412 boolean fmpnnl = fmp != null; 413 // if (fmpnnl && fmp.getTo()!=null) 414 // { 415 // jalview.bin.Cache.log.debug("Not overwriting existing To reference in 416 // "+fe); 417 // continue; 418 // } 419 // smap from maps from fe.local to fe.map 420 boolean smapfromlocal2fe = (fmpnnl) ? smap.equals(fmp.getMap()) 421 : false; 422 // smap from maps from fe.map to fe.local. 423 boolean smapfromfemap2local = (fmpnnl) ? smapI.equals(fmp.getMap()) 424 : false; 425 for (int t = 0; t < tdblen; t++) 426 { 427 jalview.datamodel.DBRefEntry te = tdb[t]; 428 if (te != null) 429 { 430 if (fe.getSource().equals(te.getSource()) 431 && fe.getAccessionId().equals(te.getAccessionId())) 432 { 433 jalview.datamodel.Mapping tmp = te.getMap(); 434 boolean tmpnnl = tmp != null; 435 if (tmpnnl && tmp.getTo() != null) 436 { 437 438 } 439 // smap to maps from te.local to te.map 440 boolean smaptolocal2tm = (tmpnnl) ? smap.equals(tmp.getMap()) 441 : false; 442 // smap to maps from te.map to te.local 443 boolean smaptotemap2local = (tmpnnl) 444 ? smapI.equals(fmp.getMap()) 445 : false; 446 if (smapfromlocal2fe && smaptotemap2local) 447 { 448 // smap implies mapping from to to from 449 fmp.setTo(to); 450 tmp.setTo(from); 451 } 452 else if (smapfromfemap2local && smaptolocal2tm) 453 { 454 fmp.setTo(to); 455 } 456 } 457 458 } 459 } 460 } 461 } 462 } 463