00001 __copyright__ = """
00002 Copyright 2008 Sean Ross-Ross
00003 """
00004 __license__ = """
00005 This file is part of SLIMpy .
00006
00007 SLIMpy is free software: you can redistribute it and/or modify
00008 it under the terms of the GNU Lesser General Public License as published by
00009 the Free Software Foundation, either version 3 of the License, or
00010 (at your option) any later version.
00011
00012 SLIMpy is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015 GNU Lesser General Public License for more details.
00016
00017 You should have received a copy of the GNU Lesser General Public License
00018 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00019 """
00020
00021 from slimpy_base.Core.Interface.PSpace import PSpace
00022 from slimpy_base.Core.Interface.node import Source
00023 from slimpy_base.api.Plugins.slim2rsf.mpi_factory import rsf_mpi_factory
00024 from slimpy_base.api.Plugins.slim2rsf.sfCommandFactory import rsfCommandFactory
00025 from slimpy_base.api.Plugins.slim2rsf.sfcommands.sfConverter import sfConverter
00026 from slimpy_base.Environment.InstanceManager import InstanceManager
00027 from slimpy_base.User.AumentedMatrix.MetaSpace import MetaSpace
00028 from itertools import izip
00029 from numpy import divide, prod, array, fromiter
00030 from os.path import join
00031 from slimpy_base.api.linearops.ScatterOperator import apply_along_axis
00032 from slimpy_base.Core.Command.Drivers.FileDist import even_dist
00033 from socket import getfqdn
00034
00035
00036
00037
00038 def windowm_mpi_runtime_map( command ):
00039
00040 _env = InstanceManager()
00041
00042 nodemap = _env['slimvars'].get_node_map()
00043 params = []
00044
00045 nodes = [node for node,_ in nodemap ]
00046 files = command.params
00047 dist = even_dist(nodes, files, 0)
00048 for (container,node_dist) in izip( files, dist ):
00049
00050 if isinstance(node_dist, tuple):
00051 from_node, to_node = node_dist
00052 assert from_node in container.nodenames
00053 container.node_copy( to_node )
00054 else:
00055 from_node, to_node = node_dist,node_dist
00056
00057 assert container.available_from( to_node )
00058 if to_node in ['localhost','']:
00059 to_node = getfqdn( )
00060 params.append( "%s:%s" %( to_node, container.get_data( to_node ) ) )
00061
00062
00063 return params , command.kparams
00064
00065
00066 class create_meta_header_converter( sfConverter ):
00067 """
00068 This is a mapping instance that maps a SLIMpy command into an object that
00069 can be run
00070 This also maps the agruments and keyword arguments to be pugin specific
00071 """
00072
00073 @classmethod
00074 def map( cls, source, command ):
00075 """
00076 map a SLIMpy command to a rsf command
00077 """
00078
00079 command = sfConverter.mpi_function(command, "create_meta", num_proc='all')
00080
00081 meta_nX = source.space.meta.shape
00082 assert meta_nX is not None
00083 for i in range(3):
00084 command["N%s" %(i+1)] = 1
00085 for X,val in enumerate(meta_nX):
00086 meta_n = "N%s" %(X+1)
00087 command[meta_n] = val
00088
00089 numb_nX = source.space.meta['num_blocks']
00090 command.pop_kw('num_blocks', None)
00091
00092 for i in range(3):
00093 command["p%s" %(i+1)] = 1
00094
00095 for X,val in enumerate(numb_nX):
00096 block = "p%s" %(X+1)
00097 command[block] = val
00098
00099 if 'eps' in source.space.meta:
00100 command['eps'] = source.space.meta['eps']
00101
00102 source_list = source.ravel().tolist()
00103
00104 command.add_other_dep( Source )
00105 sources = [ Source(srtuc.container) for srtuc in source_list]
00106 command.params.extend( sources )
00107
00108 slen = len(source_list)
00109 for i,val in enumerate([slen,1,1]):
00110 command['n%s' %(i+1)] = val
00111
00112
00113 command.runtime_map = windowm_mpi_runtime_map
00114 command = cls.truefalseHelper( command )
00115
00116 return cls.pack( command, stdin=None )
00117
00118 @classmethod
00119 def map_adj( cls, source, command ):
00120 command = sfConverter.default_function( command, "#Extracting Meta Info" )
00121 command.command_type = 'multi_process'
00122 return cls.pack( command, stdin=None,stdout=None )
00123
00124
00125 @classmethod
00126 def trans( cls, command, space, *spaces ):
00127 'define how this operator affect the space'
00128
00129 metaspace = space.copy()
00130 space = space.coalesce( )
00131 space.plugin = 'rsfmpi'
00132
00133
00134 space['metaspace'] = metaspace
00135 space.update( metaspace.meta )
00136 return space
00137
00138 @classmethod
00139 def trans_adj( cls, command, space, *spaces ):
00140 'define how this operator affect the space'
00141
00142 metaspace = space['metaspace'].copy()
00143
00144 metaspace.meta = space.copy()
00145 return metaspace
00146
00147 @classmethod
00148 def constr( cls, command, space ):
00149 assert isinstance( space, MetaSpace )
00150
00151 @classmethod
00152 def constr_adj( cls, command, space ):
00153 'make sure the data on the adjoint command is complex'
00154 assert isinstance( space, PSpace )
00155
00156
00157
00158 class scatter_mpi_converter( sfConverter ):
00159 """
00160 This is a mapping instance that maps a SLIMpy command into an object that
00161 can be run
00162 This also maps the agruments and keyword arguments to be pugin specific
00163 """
00164 fprefix = 0
00165 @classmethod
00166 def gen_node_map(cls, space, command ):
00167 mapping = cls.env['slimvars'].get_node_map( )
00168
00169 filenodemap = []
00170
00171 fprefix = space['fprefix']
00172 for nodename, rank in mapping:
00173 filename = fprefix+".%.4d.rsf" %rank
00174 filenodemap.append( (filename,nodename) )
00175
00176
00177 return filenodemap
00178
00179 @classmethod
00180 def get_fprefix(cls):
00181 fprefix = "scatter_mpi.%d" %cls.fprefix
00182 cls.fprefix +=1
00183 return fprefix
00184
00185
00186 @classmethod
00187 def map( cls, source, command ):
00188 """
00189 map a SLIMpy command to a rsf command
00190 """
00191
00192
00193 command = sfConverter.mpi_function(command, "winscumpi")
00194
00195 command['datapath'] = cls.env['slimvars']['localtmpdir']
00196
00197
00198 command = cls.keywordmap(command, {'adj':'inv'})
00199 command = cls.truefalseHelper( command )
00200
00201 num_blocks = command.pop_kw('num_blocks')
00202 for X,pX in enumerate(num_blocks):
00203 command[ 'p%s' %(X+1) ] = pX
00204
00205
00206 return cls.pack( command )
00207
00208 @classmethod
00209 def trans( cls, command, space, *spaces ):
00210 'define how this operator affect the space'
00211 num_blocks = command['num_blocks']
00212 slist = []
00213 for blk in range( prod(num_blocks) ):
00214 comp = space.copy( )
00215 comp.shape = divide( comp.shape, num_blocks )
00216
00217
00218 slist.append( comp )
00219
00220
00221 space.plugin = 'rsfmpi'
00222
00223 fprefix = cls.get_fprefix()
00224 command['fprefix'] = fprefix
00225 localtmpdir = cls.env['slimvars']['localtmpdir']
00226 space['fprefix'] = join( localtmpdir, fprefix )
00227
00228 space['num_blocks'] = num_blocks
00229
00230 metaspace = MetaSpace( slist )
00231 metaspace.resize( num_blocks )
00232 metaspace.meta = space.copy()
00233
00234 set_offset(metaspace)
00235
00236 space['metaspace'] = metaspace
00237
00238 return space
00239
00240 @classmethod
00241 def trans_adj( cls, command, space, *spaces ):
00242 'define how this operator affect the space'
00243 space.plugin = 'rsf'
00244 space.pop( 'metaspace' , None )
00245 space.pop( 'fprefix' , None )
00246 space.pop( 'num_blocks' , None )
00247
00248
00249 return space
00250
00251 @classmethod
00252 def constr( cls, command, space ):
00253 'make sure the data on the forward command is float'
00254
00255 @classmethod
00256 def constr_adj( cls, command, space ):
00257 'make sure the data on the adjoint command is complex'
00258
00259
00260 def add_eps( metaspace, eps, oper):
00261
00262 mshape = list( metaspace.meta['num_blocks'] )
00263 ndim = len(mshape)
00264
00265
00266 epsary = array( [eps]*ndim )
00267
00268
00269
00270 for pos in xrange(metaspace.size):
00271 space = metaspace.flat[pos]
00272 space.shape = oper( space.shape, epsary*2 )
00273
00274 return
00275
00276 def set_offset_eps( metaspace ,eps ):
00277 mshape = list( metaspace.meta['num_blocks'] )
00278 blocksize = array(metaspace.meta.shape)/mshape
00279 ndim = metaspace.ndim
00280 def f( arr, axis, multipl,eps ):
00281 for space,sX in zip(arr, multipl):
00282 space['s%s' %(axis+1)] = sX-eps
00283
00284 return arr
00285
00286 for axis in xrange(ndim):
00287
00288 multipl = fromiter( xrange(0, metaspace.meta.shape[axis], blocksize[axis] ), int)
00289 apply_along_axis( f, axis,metaspace,axis,multipl ,eps )
00290
00291 return
00292
00293 def set_offset( metaspace ):
00294
00295 mshape = list( metaspace.meta['num_blocks'] )
00296 blocksize = array(metaspace.meta.shape)/mshape
00297 ndim = metaspace.ndim
00298 def f( arr, axis, multipl ):
00299 for space,sX in zip(arr, multipl):
00300 space['s%s' %(axis+1)] = sX
00301
00302 return arr
00303
00304 for axis in xrange(ndim):
00305
00306 multipl = fromiter( xrange(0, metaspace.meta.shape[axis], blocksize[axis] ), int)
00307 apply_along_axis( f, axis,metaspace,axis,multipl )
00308
00309 return
00310
00311 class ghost_taper_converter( sfConverter ):
00312 """
00313 This is a mapping instance that maps a SLIMpy command into an object that
00314 can be run
00315 This also maps the agruments and keyword arguments to be pugin specific
00316 """
00317 fprefix = 0
00318 @classmethod
00319 def gen_node_map(cls, space, command ):
00320 mapping = cls.env['slimvars'].get_node_map( )
00321
00322 filenodemap = []
00323
00324 fprefix = space['fprefix']
00325 for nodename, rank in mapping:
00326 filename = fprefix+".%.4d.rsf" %rank
00327 filenodemap.append((filename,nodename))
00328
00329 return filenodemap
00330
00331 @classmethod
00332 def get_fprefix(cls):
00333 fprefix = "ghost_update_mpi.%d" %cls.fprefix
00334 cls.fprefix +=1
00335 return fprefix
00336
00337
00338 @classmethod
00339 def map( cls, source, command ):
00340 """
00341 map a SLIMpy command to a rsf command
00342 """
00343
00344
00345 command = sfConverter.mpi_function(command, "wintpgmpi")
00346
00347
00348 command['datapath'] = cls.env['slimvars']['localtmpdir']
00349
00350
00351 command = cls.keywordmap(command, {'adj':'inv'})
00352 command = cls.truefalseHelper( command )
00353
00354
00355 return cls.pack( command )
00356
00357 @classmethod
00358 def trans( cls, command, space, *spaces ):
00359 'define how this operator affect the space'
00360 num_blocks = space['num_blocks']
00361 metaspace = space['metaspace'].copy()
00362
00363 fprefix = cls.get_fprefix()
00364 command['fprefix'] = fprefix
00365 localtmpdir = cls.env['slimvars']['localtmpdir']
00366 space['fprefix'] = join( localtmpdir, fprefix )
00367
00368
00369
00370 eps = command['eps']
00371 add_eps( metaspace, eps,
00372 lambda shape,epsary:shape+epsary )
00373
00374
00375 set_offset_eps(metaspace, eps)
00376
00377 space['eps'] = eps
00378 space['metaspace'] = metaspace
00379 return space
00380
00381 @classmethod
00382 def trans_adj( cls, command, space, *spaces ):
00383 'define how this operator affect the space'
00384
00385 space['metaspace']
00386 fprefix = cls.get_fprefix()
00387 command['fprefix'] = fprefix
00388 localtmpdir = cls.env['slimvars']['localtmpdir']
00389 space['fprefix'] = join( localtmpdir, fprefix )
00390
00391 eps = command['eps']
00392
00393 metaspace = space['metaspace'].copy()
00394
00395 add_eps( metaspace, eps,
00396 lambda shape,epsary:shape-epsary )
00397
00398 set_offset(metaspace)
00399
00400 space['metaspace'] = metaspace
00401 space['eps'] = 0
00402 return space
00403
00404 @classmethod
00405 def constr( cls, command, space ):
00406 'make sure the data on the forward command is float'
00407
00408 @classmethod
00409 def constr_adj( cls, command, space ):
00410 'make sure the data on the adjoint command is complex'
00411
00412
00413
00414 factory = rsfCommandFactory()
00415
00416
00417 factory['meta'] = create_meta_header_converter
00418
00419 factory['window_mpi'] = scatter_mpi_converter
00420
00421 mpi_factory = rsf_mpi_factory( )
00422 mpi_factory['window_mpi'] = scatter_mpi_converter
00423 mpi_factory['meta'] = create_meta_header_converter
00424 mpi_factory['ghost_taper'] = ghost_taper_converter