def test( model, center2center, nAtoms=10, exclude=None ): from Biskit import Pymoler, PDBModel g = PatchGeneratorFromOrbit( model, center2center ) overlap = int( round( nAtoms / 4.0 ) ) r = g.randomPatches( nAtoms, 500, max_overlap=overlap, exclude=exclude ) profile = N0.sum( N0.array(r) ) pm = Pymoler() pm.addPdb( model, 'all' ) ms = [ model.take( N0.nonzero(mask) ) for mask in r ] pm.addMovie( ms ) return pm
def display(self, traj): """Display random complexes as trajectory in Pymol. Only run in local interactive mode. """ from Biskit import Pymoler print "activate debug switch to get random complexes written to disc!" if self.DEBUG: print "writing random complex as trajectory to file..." traj.ref.writePdb(self.f_pfb) traj.writeCrd(self.f_crd) print 'Wrote reference pdb file to: %s' % self.f_pfb print 'Wrote crd file to: %s' % self.f_crd self.pm = Pymoler(full=0) mname = self.pm.addMovie([traj[i] for i in range(len(traj))]) self.pm.add('hide all') self.pm.add('show cartoon') self.pm.add('spectrum') self.pm.add('mplay') self.pm.run()
def test( model ): from Biskit import Pymoler g = PatchGenerator( model ) r = g.randomPatches( 85, 50, max_overlap=25 ) profile = N.sum( N.array(r) ) pm = Pymoler() pm.addPdb( model, 'o' ) ms = [ model.take( N.flatnonzero(mask) ) for mask in r ] pm.addMovie( ms ) return pm
def display(self, traj ): """Display random complexes as trajectory in Pymol. Only run in local interactive mode. """ from Biskit import Pymoler print "activate debug switch to get random complexes written to disc!" if self.DEBUG: print "writing random complex as trajectory to file..." traj.ref.writePdb( self.f_pfb ) traj.writeCrd( self.f_crd ) print 'Wrote reference pdb file to: %s' % self.f_pfb print 'Wrote crd file to: %s' % self.f_crd self.pm = Pymoler( full=0 ) mname = self.pm.addMovie( [ traj[i] for i in range(len(traj)) ] ) self.pm.add('hide all') self.pm.add('show cartoon') self.pm.add('spectrum') self.pm.add('mplay') self.pm.run()
def test(model, center2center, nAtoms=10, exclude=None): from Biskit import Pymoler, PDBModel g = PatchGeneratorFromOrbit(model, center2center) overlap = int(round(nAtoms / 4.0)) r = g.randomPatches(nAtoms, 500, max_overlap=overlap, exclude=exclude) profile = N0.sum(N0.array(r)) pm = Pymoler() pm.addPdb(model, 'all') ms = [model.take(N0.nonzero(mask)) for mask in r] pm.addMovie(ms) return pm
class Test(BT.BiskitTest): """Test case The test generates 3 random complexes. In interactive mode, the 3 complexes are displayed as movie in Pymol. They are written out as Amber trajectory if debug=True. """ TAGS = [ BT.EXE, BT.LONG ] def prepare(self): import tempfile self.f_pfb = tempfile.mktemp('_test.pdb') self.f_crd = tempfile.mktemp('_test.crd') def cleanUp(self): t.tryRemove( self.f_pfb ) t.tryRemove( self.f_crd ) def test_ComplexRandomizer(self): """Dock.ComplexRandomizer test""" from Biskit import Trajectory if self.local: print "\nLoading Rec and Lig files ...", rec_pdb = t.testRoot() + '/rec/1A2P.pdb' lig_pdb = t.testRoot() + '/lig/1A19.pdb' rec_psf = t.testRoot() + '/rec/1A2P.psf' lig_psf = t.testRoot() + '/lig/1A19.psf' rec = PCRModel( rec_psf, rec_pdb ) lig = PCRModel( lig_psf, lig_pdb ) if self.local: print "Initializing Randomizer..." self.cr = ComplexRandomizer( rec, lig, debug=self.DEBUG ) if self.local: print "Creating 3 random complexes..." cs = [ self.cr.random_complex() for i in range(3) ] self.traj = Trajectory( [ c.model() for c in cs ] ) if self.local: self.display( self.traj ) globals().update( locals() ) self.assertEqual( len(self.traj), 3 ) def display(self, traj ): """Display random complexes as trajectory in Pymol. Only run in local interactive mode. """ from Biskit import Pymoler print "activate debug switch to get random complexes written to disc!" if self.DEBUG: print "writing random complex as trajectory to file..." traj.ref.writePdb( self.f_pfb ) traj.writeCrd( self.f_crd ) print 'Wrote reference pdb file to: %s' % self.f_pfb print 'Wrote crd file to: %s' % self.f_crd self.pm = Pymoler( full=0 ) mname = self.pm.addMovie( [ traj[i] for i in range(len(traj)) ] ) self.pm.add('hide all') self.pm.add('show cartoon') self.pm.add('spectrum') self.pm.add('mplay') self.pm.run()
## get filenames of all models models = glob.glob('%s/modeller/%s*.pdb' % (outFolder, tools.stripFilename(f_target))) ## create a Trajectory object with the models traj = Trajectory(pdbs=models) ## fit the models against the average structure iteratively traj.blockFit2ref() ## calculate and print rmsd matrix rmsHeavy = traj.pairwiseRmsd() print '\nHEAVY ATOM RMSD BETWEEN MODELS::' __printMatrix(rmsHeavy) ## same thing for backbone atoms BBMask = traj[0].maskBB() traj.blockFit2ref(mask=BBMask) rmsBB = traj.pairwiseRmsd(aMask=BBMask) print '\nBACKBONE RMSD BETWEEN MODELS:' __printMatrix(rmsBB) if options.has_key('view'): ## show backbone superimposed structures in pymol pm = Pymoler() for t in traj: pm.addPdb(t) pm.show()
def test_Benchmark(self): """Mod.Benchmark test""" from Biskit import Pymoler self.b = Benchmark( self.outfolder ) self.b.go() pdb = T.load( self.outfolder + "/modeller/PDBModels.list" )[0] reference = PDBModel(self.outfolder + "/reference.pdb" ) tmp_model = pdb.clone() reference = reference.compress( reference.maskCA() ) pdb = pdb.compress( pdb.maskCA() ) tmp_model = tmp_model.compress(tmp_model.maskCA()) tm = tmp_model.transformation( reference, n_it=0, profname="rms_outliers") pdb = pdb.transform( tm ) if self.local: pm = Pymoler() pm.addPdb( pdb, "m" ) pm.addPdb( reference, "r" ) pm.colorAtoms( "m", tmp_model.profile("rms_outliers") ) pm.add('set ribbon_trace,1') pm.add('show ribbon') pm.show() if self.DEBUG: self.log.add( 'The result from the benchmarking is in %s/benchmark'%\ self.outfolder) globals().update( locals() )
def test_Benchmark(self): """Mod.Benchmark test""" from Biskit import Pymoler self.b = Benchmark(self.outfolder) self.b.go() pdb = T.load(self.outfolder + "/modeller/PDBModels.list")[0] reference = PDBModel(self.outfolder + "/reference.pdb") tmp_model = pdb.clone() reference = reference.compress(reference.maskCA()) pdb = pdb.compress(pdb.maskCA()) tmp_model = tmp_model.compress(tmp_model.maskCA()) tm = tmp_model.transformation(reference, n_it=0, profname="rms_outliers") pdb = pdb.transform(tm) if self.local: pm = Pymoler() pm.addPdb(pdb, "m") pm.addPdb(reference, "r") pm.colorAtoms("m", tmp_model.profile("rms_outliers")) pm.add('set ribbon_trace,1') pm.add('show ribbon') pm.show() if self.DEBUG: self.log.add( 'The result from the benchmarking is in %s/benchmark'%\ self.outfolder) globals().update(locals())
## get filenames of all models models = glob.glob( '%s/modeller/%s*.pdb'%(outFolder, tools.stripFilename(f_target)) ) ## create a Trajectory object with the models traj = Trajectory( pdbs=models ) ## fit the models against the average structure iteratively traj.blockFit2ref() ## calculate and print rmsd matrix rmsHeavy = traj.pairwiseRmsd() print '\nHEAVY ATOM RMSD BETWEEN MODELS::' __printMatrix( rmsHeavy ) ## same thing for backbone atoms BBMask = traj[0].maskBB() traj.blockFit2ref( mask = BBMask ) rmsBB = traj.pairwiseRmsd( aMask = BBMask ) print '\nBACKBONE RMSD BETWEEN MODELS:' __printMatrix( rmsBB ) if options.has_key('view'): ## show backbone superimposed structures in pymol pm = Pymoler( ) for t in traj: pm.addPdb( t ) pm.show()
def main(options): ## ## get extra options from external file ## if options.has_key('x'): ## options.update( _parseExternalOptions( options['x'] ) ) fname = options['i'] # input pdb file outPath = options['o'] chainMask = options.get('cmask', None) if chainMask: chainMask = toIntList(chainMask) try: if options.has_key('h'): fheader = options['h'] else: fheader = options['t'] + '/head.inp' if options.has_key('s'): fsegment = options['s'] else: fsegment = options['t'] + '/segment.inp' if options.has_key('e'): ftail = options['e'] else: ftail = options['t'] + '/end.inp' except: errWriteln("You have to specify either all three template files or\n"+ "(option -t) a folder that contains head.inp, segment.inp, end.inp.\n" + "If both -t and -h, -s, or -e are present, files specified with\n" + "-h, -s, -e are preferred.") ## check that input pdb file name (stripped of its path and extension) ## is at least 5 characters long and starts with a number ## Prompt user for renaming of the file. name = stripFilename(fname) ## the filename is OK, but it has the same name as used for the ## XPLOR output therefore we append _original to the input file if toInt( name[0] )== None or len(name)==4 : print "##### NOTE: ######" print "The pdb file name you gave is OK, but exactly" print "the same name will be used for the output from" print "the XPLOR script. Therefore '_original' will be" print "appended to the input pdb file you gave." base, ext = absfile(fname).split('.') new_fname = base +'_original.' + ext os.rename( fname, new_fname ) fname = new_fname if toInt( name[0] )== None or len(name)<4 : print "##### WARNING: ######" print "The pdb file name you gave is either shorter " print "than 4 characters or it doesn't start with a number." print "This will cause the X-PLOR job to fail" msg = "Do you want to rename the file (Y/N)?" if upper( raw_input( msg ) ) == 'Y': new_name = upper( raw_input( "Give a new filname:" ) ) ## check that the new name is OK if toInt( new_name[0] )== None or len(new_name)<4 : raise StandardError, \ 'You gave an incorrect new filename. Exiting' ## create link else: new_file = '%s/%s.%s'%(os.path.dirname(absfile(fname)), new_name, fname.split('.')[-1]) os.link(fname, new_file) print 'Link from %s to %s created sucessfully'\ %(absfile(fname), new_file) fname = new_file ## switch on Amber specialities ? amber = options.has_key('a') ## cap N- and C-term of chain breaks? capBreaks = options.has_key('cap') cleaner = ChainCleaner( ChainSeparator(fname, outPath, int(options['c']), capBreaks=capBreaks, chainMask=chainMask) ) # initialize with output path and base file name for generate.inp file xplorer = Xplor(outPath, cleaner, fheader, fsegment, ftail, amber, extras=options ) xplorer.generateInp() ## run X-Plor if options.has_key('exe'): out, error, returncode = Executor( 'xplor' , strict=0, f_in=xplorer.cleaner.pdbname + "_generate.inp", f_out=xplorer.cleaner.pdbname + '_generate.log').run() ## Show structure in pymol if options.has_key('view'): pm = Pymoler( ) mname = pm.addPdb( xplorer.outname + '.pdb' ) pm.add('select xray-wat, segi 1XWW') pm.add('select added-wat, segi 1WWW') pm.add('select hydrogens, elem H') pm.add('hide everything, xray-wat OR added-wat OR hydrogens') pm.add('select none') colors = [ hex2rgb(c, str) for c in hexColors( len(xplorer.chains) )] i=0 for c in xplorer.chains: print colors[i], c.segment_id pm.add( 'set_color col_%i, %s'%( i, colors[i] ) ) pm.add('color col_%i, segi %s and elem c'%( i, c.segment_id ) ) i += 1 pm.add('zoom all') pm.show()
class Test(BT.BiskitTest): """Test case The test generates 3 random complexes. In interactive mode, the 3 complexes are displayed as movie in Pymol. They are written out as Amber trajectory if debug=True. """ TAGS = [BT.EXE, BT.LONG] def prepare(self): import tempfile self.f_pfb = tempfile.mktemp('_test.pdb') self.f_crd = tempfile.mktemp('_test.crd') def cleanUp(self): t.tryRemove(self.f_pfb) t.tryRemove(self.f_crd) def test_ComplexRandomizer(self): """Dock.ComplexRandomizer test""" from Biskit import Trajectory if self.local: print "\nLoading Rec and Lig files ...", rec_pdb = t.testRoot() + '/rec/1A2P.pdb' lig_pdb = t.testRoot() + '/lig/1A19.pdb' rec_psf = t.testRoot() + '/rec/1A2P.psf' lig_psf = t.testRoot() + '/lig/1A19.psf' rec = PCRModel(rec_psf, rec_pdb) lig = PCRModel(lig_psf, lig_pdb) if self.local: print "Initializing Randomizer..." self.cr = ComplexRandomizer(rec, lig, debug=self.DEBUG) if self.local: print "Creating 3 random complexes..." cs = [self.cr.random_complex() for i in range(3)] self.traj = Trajectory([c.model() for c in cs]) if self.local: self.display(self.traj) globals().update(locals()) self.assertEqual(len(self.traj), 3) def display(self, traj): """Display random complexes as trajectory in Pymol. Only run in local interactive mode. """ from Biskit import Pymoler print "activate debug switch to get random complexes written to disc!" if self.DEBUG: print "writing random complex as trajectory to file..." traj.ref.writePdb(self.f_pfb) traj.writeCrd(self.f_crd) print 'Wrote reference pdb file to: %s' % self.f_pfb print 'Wrote crd file to: %s' % self.f_crd self.pm = Pymoler(full=0) mname = self.pm.addMovie([traj[i] for i in range(len(traj))]) self.pm.add('hide all') self.pm.add('show cartoon') self.pm.add('spectrum') self.pm.add('mplay') self.pm.run()
d = [f] if options.has_key('d'): folders = T.toList(options['d']) else: folders = d T.flushPrint("Starting job...\n") for f in folders: a = A(outFolder=f) a.go() T.flushPrint("Done.\n") ## show result in PyMol if options.has_key('s'): p = Pymoler() p.addPdb(folders[0] + a.F_FINAL_PDB) p.add('color_b') p.add('select na, b<0') p.add('color grey, na') p.add('hide all') p.add('show cartoon') p.add('show stick') p.add('hide stick, name o+c+n') p.add('select ca, /////ca') p.add('label ca,"%s-%s"%(resn, resi)') p.add('select none') p.show()
def test_Complex(self): """Dock.Complex test""" lig = PCRModel( t.testRoot() + "/com/1BGS.psf", t.testRoot() + "/com/lig.model") rec = PCRModel( t.testRoot() + "/com/1BGS.psf", t.testRoot() + "/com/rec.model") rec = rec.compress( rec.maskHeavy() ) lig = lig.compress( lig.maskHeavy() ) c = Complex(rec, lig) c.info['soln'] = 1 cont = c.atomContacts( 6.0 ) contProfile_lig = N.sum( cont ) contProfile_rec = N.sum( cont, 1 ) try: dope = PDBDope( c.rec_model ) dope.addSurfaceRacer( probe=1.4 ) rec_surf = c.rec_model.profile2mask( 'MS', 0.0000001, 1000 ) dope = PDBDope( c.lig_model ) dope.addSurfaceRacer( probe=1.4 ) lig_surf = c.lig_model.profile2mask( 'MS', 0.0000001, 1000 ) except: pass if self.local: from Biskit import Pymoler self.pm = Pymoler() self.pm.addPdb( c.rec(), 'rec' ) self.pm.addPdb( c.lig(), 'lig' ) self.pm.colorAtoms( 'rec', contProfile_rec ) self.pm.colorAtoms( 'lig', contProfile_lig ) rec_sphere = c.rec().clone() rec_sphere.xyz = mathUtils.projectOnSphere( rec_sphere.xyz ) lig_sphere = c.lig().clone() lig_sphere.xyz = mathUtils.projectOnSphere( lig_sphere.xyz ) self.pm.addPdb( rec_sphere, 'rec_sphere' ) self.pm.addPdb( lig_sphere, 'lig_sphere' ) self.pm.colorAtoms( 'rec_sphere', contProfile_rec ) self.pm.colorAtoms( 'lig_sphere', contProfile_lig ) self.pm.add( 'hide all') self.pm.add( 'color grey, (b=0)' ) self.pm.add( 'show stick, (rec or lig)' ) self.pm.add( 'show surf, rec_sphere') self.pm.add( 'zoom all' ) self.pm.show() globals().update( locals() ) self.assertEqual( N.sum(contProfile_lig) + N.sum(contProfile_rec), 2462 )
def main(options): ## ## get extra options from external file ## if options.has_key('x'): ## options.update( _parseExternalOptions( options['x'] ) ) fname = options['i'] # input pdb file outPath = options['o'] chainMask = options.get('cmask', None) if chainMask: chainMask = toIntList(chainMask) try: if options.has_key('h'): fheader = options['h'] else: fheader = options['t'] + '/head.inp' if options.has_key('s'): fsegment = options['s'] else: fsegment = options['t'] + '/segment.inp' if options.has_key('e'): ftail = options['e'] else: ftail = options['t'] + '/end.inp' except: errWriteln( "You have to specify either all three template files or\n" + "(option -t) a folder that contains head.inp, segment.inp, end.inp.\n" + "If both -t and -h, -s, or -e are present, files specified with\n" + "-h, -s, -e are preferred.") ## check that input pdb file name (stripped of its path and extension) ## is at least 5 characters long and starts with a number ## Prompt user for renaming of the file. name = stripFilename(fname) ## the filename is OK, but it has the same name as used for the ## XPLOR output therefore we append _original to the input file if toInt(name[0]) == None or len(name) == 4: print "##### NOTE: ######" print "The pdb file name you gave is OK, but exactly" print "the same name will be used for the output from" print "the XPLOR script. Therefore '_original' will be" print "appended to the input pdb file you gave." base, ext = absfile(fname).split('.') new_fname = base + '_original.' + ext os.rename(fname, new_fname) fname = new_fname if toInt(name[0]) == None or len(name) < 4: print "##### WARNING: ######" print "The pdb file name you gave is either shorter " print "than 4 characters or it doesn't start with a number." print "This will cause the X-PLOR job to fail" msg = "Do you want to rename the file (Y/N)?" if upper(raw_input(msg)) == 'Y': new_name = upper(raw_input("Give a new filname:")) ## check that the new name is OK if toInt(new_name[0]) == None or len(new_name) < 4: raise StandardError, \ 'You gave an incorrect new filename. Exiting' ## create link else: new_file = '%s/%s.%s' % (os.path.dirname( absfile(fname)), new_name, fname.split('.')[-1]) os.link(fname, new_file) print 'Link from %s to %s created sucessfully'\ %(absfile(fname), new_file) fname = new_file ## switch on Amber specialities ? amber = options.has_key('a') ## cap N- and C-term of chain breaks? capBreaks = options.has_key('cap') cleaner = ChainCleaner( ChainSeparator(fname, outPath, int(options['c']), capBreaks=capBreaks, chainMask=chainMask)) # initialize with output path and base file name for generate.inp file xplorer = Xplor(outPath, cleaner, fheader, fsegment, ftail, amber, extras=options) xplorer.generateInp() ## run X-Plor if options.has_key('exe'): out, error, returncode = Executor( 'xplor', strict=0, f_in=xplorer.cleaner.pdbname + "_generate.inp", f_out=xplorer.cleaner.pdbname + '_generate.log').run() ## Show structure in pymol if options.has_key('view'): pm = Pymoler() mname = pm.addPdb(xplorer.outname + '.pdb') pm.add('select xray-wat, segi 1XWW') pm.add('select added-wat, segi 1WWW') pm.add('select hydrogens, elem H') pm.add('hide everything, xray-wat OR added-wat OR hydrogens') pm.add('select none') colors = [hex2rgb(c, str) for c in hexColors(len(xplorer.chains))] i = 0 for c in xplorer.chains: print colors[i], c.segment_id pm.add('set_color col_%i, %s' % (i, colors[i])) pm.add('color col_%i, segi %s and elem c' % (i, c.segment_id)) i += 1 pm.add('zoom all') pm.show()
def visualize(self, profile='so_min', wat=None, xwat=None): """ Create a receptor / ligand / water view with a profile color-coded on it. @param profile: name of the profile to color-project ['so_min'] @type profile: str @param wat: chain ids of water molecules (default: None) These will end up as spheres in group 'water' @type wat: [ int ] @param xwat: chain ids of crystal water molecules (default: None) These will end up as spheres in group 'xwater' @type xwat: [ int ] @return: Pymoler instance with receptor and ligand colored by shelling order (use pm.run() to make it show up) @rtype: Pymoler """ import Biskit.Pymoler as Pymoler model = self.model.clone() ## replace all 0 values by -1 to distinguish them better by color model[profile] += (model[profile] == 0) * -1 rec = model.takeChains(self.chains_rec, breaks=self.breaks) lig = model.takeChains(self.chains_lig, breaks=self.breaks) water = xwater = None if wat: water = model.takeChains(wat, breaks=self.breaks) water = water.compress(N.greater(water['n_facets'], 0)) if xwat: xwater = model.takeChains( xwat, breaks=self.breaks) ## X-ray determined water ## kick out waters that do not belong to the interface xwater = xwater.compress(N.greater(xwater['n_facets'], 0)) pm = Pymoler() pm.addPdb(model, 'com') pm.addPdb(rec, 'rec') pm.addPdb(lig, 'lig') pm.colorAtoms('rec', rec[profile]) pm.colorAtoms('lig', lig[profile]) if xwater: pm.addPdb(xwater, 'x-water') pm.colorAtoms('x-water', xwater[profile]) if water: pm.addPdb(water, 'water') pm.colorAtoms('water', water[profile]) pm.add('hide') pm.add('show surface, rec') pm.add('show mesh, lig') pm.add('show spheres, x-water') pm.add('show spheres, water') pm.add('zoom') return pm
folders = T.toList(options['d']) else: folders = d T.flushPrint("Starting job...\n") for f in folders: a = A(outFolder=f) a.go() T.flushPrint("Done.\n") ## show result in PyMol if options.has_key('s'): p=Pymoler() p.addPdb( folders[0] + a.F_FINAL_PDB ) p.add('color_b') p.add('select na, b<0') p.add('color grey, na') p.add('hide all') p.add('show cartoon') p.add('show stick') p.add('hide stick, name o+c+n') p.add('select ca, /////ca') p.add('label ca,"%s-%s"%(resn, resi)') p.add('select none') p.show()
def visualize( self, profile='so_min', wat=None, xwat=None ): """ Create a receptor / ligand / water view with a profile color-coded on it. @param profile: name of the profile to color-project ['so_min'] @type profile: str @param wat: chain ids of water molecules (default: None) These will end up as spheres in group 'water' @type wat: [ int ] @param xwat: chain ids of crystal water molecules (default: None) These will end up as spheres in group 'xwater' @type xwat: [ int ] @return: Pymoler instance with receptor and ligand colored by shelling order (use pm.run() to make it show up) @rtype: Pymoler """ import Biskit.Pymoler as Pymoler model = self.model.clone() ## replace all 0 values by -1 to distinguish them better by color model[profile] += (model[profile] == 0) * -1 rec = model.takeChains( self.chains_rec, breaks=self.breaks ) lig = model.takeChains( self.chains_lig, breaks=self.breaks ) water = xwater = None if wat: water = model.takeChains(wat, breaks=self.breaks) water = water.compress( N.greater( water['n_facets'], 0) ) if xwat: xwater = model.takeChains( xwat, breaks=self.breaks ) ## X-ray determined water ## kick out waters that do not belong to the interface xwater = xwater.compress( N.greater( xwater['n_facets'], 0) ) pm = Pymoler() pm.addPdb( model, 'com' ) pm.addPdb( rec, 'rec' ) pm.addPdb( lig, 'lig' ) pm.colorAtoms( 'rec', rec[profile]) pm.colorAtoms( 'lig', lig[profile]) if xwater: pm.addPdb( xwater, 'x-water' ) pm.colorAtoms( 'x-water', xwater[profile] ) if water: pm.addPdb( water, 'water' ) pm.colorAtoms( 'water', water[profile] ) pm.add( 'hide' ) pm.add( 'show surface, rec' ) pm.add( 'show mesh, lig' ) pm.add( 'show spheres, x-water' ) pm.add( 'show spheres, water' ) pm.add( 'zoom' ) return pm