# -*- coding: utf-8 -*- # This software and supporting documentation are distributed by # Institut Federatif de Recherche 49 # CEA/NeuroSpin, Batiment 145, # 91191 Gif-sur-Yvette cedex # France # # This software is governed by the CeCILL license version 2 under # French law and abiding by the rules of distribution of free software. # You can use, modify and/or redistribute the software under the # terms of the CeCILL license version 2 as circulated by CEA, CNRS # and INRIA at the following URL "http://www.cecill.info". # # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited # liability. # # In this respect, the user's attention is drawn to the risks associated # with loading, using, modifying and/or developing or reproducing the # software by the user in light of its specific status of free software, # that may mean that it is complicated to manipulate, and that also # therefore means that it is reserved for developers and experienced # professionals having in-depth computer knowledge. Users are therefore # encouraged to load and test the software's suitability as regards their # requirements in conditions enabling the security of their systems and/or # data to be ensured and, more generally, to use and operate it in the # same conditions as regards security. # # The fact that you are presently reading this means that you have had # knowledge of the CeCILL license version 2 and that you accept its terms. from brainvisa.configuration import neuroConfig from brainvisa.data import neuroHierarchy from brainvisa.data.neuroDiskItems import getDiskItemType, isSameDiskItemType, DiskItem from brainvisa.processing.neuroException import HTMLMessage from brainvisa.data.writediskitem import WriteDiskItem from soma import uuid import threading #------------------------------------------------------------------------------ class DatabasesTransformationManager( object ): '''TransformationsManager linked with BrainVISA database system.''' def __init__( self ): self.lock = threading.RLock() def referential( self, diskItemOrId ): '''Return the referential object corresponding to the given diskItem or uuid. Return None if the diskItem has no referential or the referential is not in the manager.''' if isinstance( diskItemOrId, DiskItem ): if diskItemOrId.type is not None and diskItemOrId.type.isA( 'Referential' ): uuid = diskItemOrId.uuid() if uuid is not None: return diskItemOrId else: try: uuid = diskItemOrId.get( 'referential' ) except ( AttributeError, KeyError ): uuid = None else: uuid = diskItemOrId if uuid is None: return None return neuroHierarchy.databases.getDiskItemFromUuid( uuid, None ) def findPaths( self, source_referential, destination_referential, maxLength=None, bidirectional=False ): '''Return a generator object that iterate over all the transformation paths going from source_referential to destination_referential. A transformation path is a list of transformation objects. The paths are returned in increasing length order. If maxlength is set to a non null positive value, it limits the size of the paths returned. Source and destination referentials can be given either as string uuid or as referential object.''' ref = uuid.Uuid( source_referential ) if ref is not None: source_referential = ref else: source_referential = self.getObjectUuid( source_referential ) ref = uuid.Uuid( destination_referential ) if ref is not None: destination_referential = ref else: destination_referential = self.getObjectUuid( destination_referential ) for path in neuroHierarchy.databases.findTransformationPaths( source_referential, destination_referential, maxLength, bidirectional ): try: yield [ neuroHierarchy.databases.getDiskItemFromUuid( i[0] ) for i in path ] except neuroHierarchy.DatabaseError, e: print e print ' no transformation corresponds to this uuid: %s, used in a ' \ 'possible path to link refs %s (%s) and %s (%s)' % \ ( i[0], source_referential, neuroHierarchy.databases.getDiskItemFromUuid( source_referential ), destination_referential, neuroHierarchy.databases.getDiskItemFromUuid( destination_referential ) ) def setReferentialTo( self, diskItem, referential ): '''Assign to the given diskItem the given referential (as Referential object or uuid)''' ref = self.referential( referential ) if not ref: raise RuntimeError( 'Referential ' + str( referential ) + \ ' is not in a configured database' ) diskItem.readAndUpdateMinf() diskItem.setMinf( 'referential', ref.uuid() ) try: neuroHierarchy.databases.insertDiskItem( diskItem, update=True ) except: pass def createNewReferentialFor( self, diskItem, name = None, description = None, dimension_count = 3, referentialType = None, simulation = False, output_diskitem = None ): '''Create a new referential for an object stored in a DiskItem and record it in the database. Returns None if the referential has not been created because its location in the database cannot be found with ReadDiskItem( 'Referential', 'Referential' ).findValue( diskItem ).''' # Find a location for the referential in the database referential = output_diskitem if referentialType is None: try: if diskItem.type is not None: referentialType = getDiskItemType( 'Referential of ' + diskItem.type.name ) except ValueError: referentialType =None else: referentialType = getDiskItemType( referentialType ) while referential is None and referentialType is not None: wdi = WriteDiskItem( referentialType, 'Referential', exactType=True ) referential = wdi.findValue( diskItem ) referentialType = referentialType.parent if referential is None: wdi = WriteDiskItem( 'Referential', 'Referential', exactType=True ) referential = wdi.findValue( diskItem ) if referential is not None: if name is None: if referentialType is not None: name = referentialType.name elif diskItem.type is not None: name = diskItem.type.name else: name = referential.name referential.setMinf( 'dimension_count', dimension_count, saveMinf=False ) if name is not None: referential.setMinf( 'name', name, saveMinf=False ) if description is not None: referential.setMinf( 'description', description, saveMinf=False) if not simulation: diskItem.readAndUpdateMinf() referential.createParentDirectory() diskItem.setMinf( 'referential', referential.uuid() ) referential.saveMinf() neuroHierarchy.databases.insertDiskItem( referential, update=True ) neuroHierarchy.databases.insertDiskItem( diskItem, update=True ) # write a transformation between this referential and MNI template if needed if diskItem.get( 'normalized' ) == 'yes': from brainvisa.tools.aimsGlobals import aimsVolumeAttributes atts = aimsVolumeAttributes(diskItem) refs = atts.get( 'referentials' ) if refs: foundmni = False for i in range( len( refs ) ): r = refs[i] if r == 'Talairach-MNI template-SPM': foundmni = True break if not foundmni: # force target ref info since SPM doesn't set it i = 0 refs[0] = 'Talairach-MNI template-SPM' diskItem.setMinf( 'referentials', refs ) #diskItem.saveMinf() # write a .trm transformation to MNI space here trans = atts.get( 'transformations' ) if trans: tr = trans[i] dref = self.referential( talairachMNIReferentialId ) try: path = self.findTransformationPaths( referential.uuid(), dref.uuid(), maxLength=1 ).next() except StopIteration: tdi = self.createNewTransformation( 'Transformation Matrix', referential, dref ) else: tdi = self.transformation( path[ 0 ][ 0 ] ) if tdi: trm = open( tdi.fullPath(), 'w' ) print >> trm, tr[3], tr[7], tr[11] print >> trm, tr[0], tr[1], tr[2] print >> trm, tr[4], tr[5], tr[6] print >> trm, tr[8], tr[9], tr[10] trm.close() return referential def createNewReferential( self, referential ): """ Creates the file for the referential diskitem and add it to the database and to the transformation manager. """ try: referential.createParentDirectory() referential.saveMinf() neuroHierarchy.databases.insertDiskItem( referential, update=True ) except: referential=None return referential def removeReferential (self, db, diskItem, uuid, eraseFiles=False) : """ Test if there is no transformation with uuid then remove the diskItem """ val = neuroHierarchy.databases.findTransformationWith( uuid ) if val is None : db.removeDiskItem(diskItem, eraseFiles=eraseFiles) return True else : return False def copyReferential( self, sourceDiskItem, destinationDiskItem ): '''Copy the referential of sourceDiskItem to the one of destinationDiskItem. The minf file of destinationDiskItem is saved by this function.''' if destinationDiskItem is None or not destinationDiskItem.isReadable(): return # do not create a .minf file for a diskitem that doesn't exist refId = self.referential( sourceDiskItem ) from brainvisa.tools.aimsGlobals import aimsVolumeAttributes atts = aimsVolumeAttributes( sourceDiskItem, forceFormat=True ) uuid = None if refId is not None: if isinstance( refId, DiskItem ): uuid = refId.get( 'referential' ) if uuid is None: uuid = refId.uuid() else: # get ref uuid from source minf (maybe outside databases) uuid = atts.get( 'referential' ) if uuid is not None: destinationDiskItem.readAndUpdateMinf() destinationDiskItem.setMinf( 'referential', uuid ) refs = atts.get( 'referentials' ) trans = atts.get( 'transformations' ) if refs and trans: destinationDiskItem.setMinf( 'referentials', refs ) destinationDiskItem.setMinf( 'transformations', trans ) try: neuroHierarchy.databases.insertDiskItem( destinationDiskItem, update=True ) except: pass def createNewTransformation( self, format, sourceDiskItem, destDiskItem, name = None, description = None, simulation = False ): if isSameDiskItemType( sourceDiskItem.type, 'Referential' ): sourceRef = sourceDiskItem else: sourceRef = self.referential( sourceDiskItem.get( 'referential' ) ) if sourceRef is None: raise RuntimeError( HTMLMessage(_t_( 'Object %s does not have referential' ) % ( str( sourceDiskItem ), )) ) if isSameDiskItemType( destDiskItem.type, 'Referential' ): destRef = destDiskItem else: destRef = self.referential( destDiskItem.get( 'referential' ) ) if destRef is None: raise RuntimeError( HTMLMessage(_t_( 'Object %s does not have referential' ) % ( str( destDiskItem ), )) ) trType = None # try to find the transformation's type name with source and destination referentials sourceRefName = sourceRef.get( 'name' ) destRefName = destRef.get( 'name' ) sourceRefType=sourceRef.type.name if sourceRefType.startswith("Referential of "): sourceRefType=sourceRefType.replace("Referential of ", "") destRefType=destRef.type.name if destRefType.startswith("Referential of "): destRefType=destRefType.replace("Referential of ", "") # Transform sourceRefName to destRefName if sourceRefName is not None and destRefName is not None: trType = 'Transform ' + sourceRefName + ' to ' + destRefName try: trType = getDiskItemType( trType ) except ValueError: trType = None # Transform sourceRefType to destRefName if trType is None: if sourceRefType is not None and destRefName is not None: trType = 'Transform ' + sourceRefType + ' to ' + destRefName try: trType = getDiskItemType( trType ) except ValueError: trType = None # Transform sourceRefName to destRefType if trType is None: if sourceRefName is not None and destRefType is not None: trType = 'Transform ' + sourceRefName + ' to ' + destRefType try: trType = getDiskItemType( trType ) except ValueError: trType = None # Transform sourceRefType to destRefType if trType is None: if sourceRefType is not None and destRefType is not None: trType = 'Transform ' + sourceRefType + ' to ' + destRefName try: trType = getDiskItemType( trType ) except ValueError: trType = None if trType is None: trType = getDiskItemType( 'Transformation' ) wdi = WriteDiskItem( trType, format, exactType=True ) # it would be a good idea to take into account the source and destination diskitems but it is not # possible for the moment, these attributes source and destintation doesn't exist and are not used. # Moreover, this request can return a wrong transformation, if there is only one transformation of that type in the datbase. #transformation = wdi.findValue( { 'source': sourceDiskItem, #'destination': destDiskItem } ) #if transformation is None: transformation = wdi.findValue( sourceDiskItem ) if transformation is None: transformation = wdi.findValue( destDiskItem ) if transformation is not None: try: transformation.setMinf( 'source_referential', sourceRef.uuid(), saveMinf=False ) transformation.setMinf( 'destination_referential', destRef.uuid(), saveMinf=False ) except: return None if name is not None: transformation.setMinf( 'name', name, saveMinf=False ) if description is not None: transformation.setMinf( 'description', description, saveMinf=False ) if not simulation: transformation.createParentDirectory() transformation.saveMinf() neuroHierarchy.databases.insertDiskItem( transformation, update=True ) return transformation def setNewTransformationInfo( self, transformation, source_referential, destination_referential, name = None, description = None ): if name is None and isinstance( transformation, DiskItem ): if transformation.type is not None: name = transformation.type.name else: name = transformation.name source_referential = self.referential( source_referential ) destination_referential = self.referential( destination_referential ) transformation.createParentDirectory() if source_referential is not None: transformation.setMinf( 'source_referential', source_referential.uuid() ) if destination_referential is not None: transformation.setMinf( 'destination_referential', destination_referential.uuid() ) if name is not None: transformation.setMinf( 'name', name ) if description is not None: transformation.setMinf( 'description', description ) try: #transformation.saveMinf() neuroHierarchy.databases.insertDiskItem( transformation, update=True ) except: pass def findOrCreateReferential( self, referentialType, diskItem, name = None, description = None, dimension_count = 3, simulation = False, assign=False, output_diskitem = None ): """ Search a referential of type referentialType for the data diskitem. if simulation is false, the referential will be created and added to the database and transformation manager. if assign is True, the referential will be assign to the diskitem. """ try: oldref = diskItem.get( 'referential' ) except: oldref = None result = self.createNewReferentialFor( diskItem, name = name, description = description, dimension_count = dimension_count, referentialType = referentialType, simulation = True, output_diskitem = output_diskitem ) if result is not None: if not simulation: if not result.isReadable(): try: result.createParentDirectory() result.saveMinf() neuroHierarchy.databases.insertDiskItem( result, update=True ) except OSError: result = None else: # in case it is not inserted in a database result.saveMinf() try: neuroHierarchy.databases.insertDiskItem( result, update=True ) except: pass # not in a database if assign: if str(result.uuid()) != oldref and diskItem.isWriteable(): diskItem.setMinf( 'referential', result.uuid() ) #diskItem.saveMinf() try: neuroHierarchy.databases.insertDiskItem( diskItem, update=True ) except: pass # not in a database return result #------------------------------------------------------------------------------ _transformationManager = None #------------------------------------------------------------------------------ def getTransformationManager(): global _transformationManager if _transformationManager is None: _transformationManager = DatabasesTransformationManager() return _transformationManager #------------------------------------------------------------------------------ # standard referentials talairachACPCReferentialId = uuid.Uuid( 'a2a820ac-a686-461e-bcf8-856400740a6c' ) talairachMNIReferentialId = uuid.Uuid( '803552a6-ac4d-491d-99f5-b938392b674b' ) globallyRegistredSPAMReferentialId = uuid.Uuid( '5f83f18d-e211-6705-99a0-720c4707901b' )