From 1f8c891f6a8b98689c8f72fa615f049af5d3b953 Mon Sep 17 00:00:00 2001 From: bhalla Date: Thu, 27 Sep 2018 21:23:13 +0530 Subject: [PATCH 1/6] Clean up of string handling in tsv files, eliminate issues due to dangling carriage return --- findSim.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/findSim.py b/findSim.py index 18f0f29..654cf74 100644 --- a/findSim.py +++ b/findSim.py @@ -108,13 +108,14 @@ def load( fd ): arg = {} for line in fd: cols = line.split('\t') - if doneContext and (len( cols ) == 0 or cols[0] == '' or cols[0].isspace()): + c0 = cols[0].strip() + if doneContext and (len( cols ) == 0 or c0 == '' or c0.isspace()): break - if cols[0] == "Experiment context": + if c0 == "Experiment context": doneContext = True continue for i in Experiment.argNames: - if keywordMatches( cols[0], i ): + if keywordMatches( c0, i ): arg[i] = str.strip( nonBlank( cols ) ) continue return Experiment( **arg ) @@ -674,25 +675,26 @@ def innerLoad( fd, argNames, dataWidth = 2): if len( cols ) == 0 or cols[0] == '' or cols[0].isspace(): return arg, data, param, struct, modelLookup - if keywordMatches( cols[0], 'modelLookup' ): + c0 = cols[0].strip() + if keywordMatches( c0, 'modelLookup' ): # Lines of the form exptName1:simName1,exptName2:simName2,... if cols[1] != "": temp = cols[1].split( ',' ) modelLookup = { i.split(':')[0]:i.split(':')[1].strip() for i in temp } - if keywordMatches( cols[0], 'Data' ): + if keywordMatches( c0, 'Data' ): readData( fd, data, dataWidth ) #print "Ret READ DATA from INNERLOAD", len( data ) return arg, data, param, struct, modelLookup for i in argNames: - if keywordMatches( cols[0], i ): + if keywordMatches( c0, i ): arg[i] = str.strip( nonBlank( cols) ) continue - if keywordMatches(cols[0],"parameterChange"): + if keywordMatches(c0,"parameterChange"): readParameter(fd,param,dataWidth) - if keywordMatches( cols[0], 'itemstodelete' ): + if keywordMatches( c0, 'itemstodelete' ): struct= cols[1].split(',') return arg, data, param, struct, modelLookup @@ -711,7 +713,7 @@ def readData( fd, data, width ): cols = line.split("\t" ) if len( cols ) == 0 or cols[0] == '' or cols[0].isspace(): break - cl = cols[0].lower() + cl = cols[0].strip().lower() if cl == "time" or cl == "dose" or cl == "settletime" or cl == 'entity': if cl == 'entity': entityNameInFirstCol = True @@ -734,7 +736,7 @@ def readParameter(fd, para, width): cols = line.split("\t") if len( cols ) == 0 or cols[0] == '' or cols[0].isspace(): break - if cols[0].lower() == "object": + if cols[0].strip().lower() == "object": continue row = [] lcols = 0 @@ -1257,13 +1259,14 @@ def loadTsv( fname ): if len( line ) > 1 and line[0] != '#': cols = line.split('\t') if len( cols ) > 0: - if cols[0] == 'Experiment metadata': + c0 = cols[0].strip() + if c0 == 'Experiment metadata': expt = Experiment.load(fd ) - if cols[0] == 'Stimuli': + if c0 == 'Stimuli': stims.append( Stimulus.load(fd ) ) - if cols[0] == 'Readouts': + if c0 == 'Readouts': readouts.append( Readout.load(fd) ) - if cols[0] == 'Model mapping': + if c0 == 'Model mapping': model = Model.load(fd ) return expt, stims, readouts, model From 9bcc5c7ae25f2a7e55f5c54fcc33b167be7d99f9 Mon Sep 17 00:00:00 2001 From: bhalla Date: Sat, 6 Oct 2018 17:29:48 +0530 Subject: [PATCH 2/6] Added capability to do parameter sweeps --- basicParameterSweep.py | 138 +++++++++++++++++++++++++++++++++++++++++ findSim.py | 20 +++++- 2 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 basicParameterSweep.py diff --git a/basicParameterSweep.py b/basicParameterSweep.py new file mode 100644 index 0000000..22cfe02 --- /dev/null +++ b/basicParameterSweep.py @@ -0,0 +1,138 @@ + +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth +# Floor, Boston, MA 02110-1301, USA. +# +# + +''' +******************************************************************* + * File: basicParameterSweep.py + * Description: + * Author: Upinder S. Bhalla + * E-mail: bhalla@ncbs.res.in + ********************************************************************/ + +/********************************************************************** +** This program is part of 'FindSim', the +** Framework for Integrating Neuronal Data and SIgnaling Models +** copyright (C) 2003-2018 Upinder S. Bhalla. and NCBS +**********************************************************************/ + +This script does a basic parameter sweep on the model. It runs the findSim +program on all tsv files in the specified directory with modifications of +the selected parameters. It computes the mean score for each run and +presents the "best" (parameter, score) along with next-best flanking. +It can do this in parallel using Python's multiprocessing library. +''' + +from __future__ import print_function +import numpy +import argparse +import os +import sys +import argparse +import findSim +from multiprocessing import Pool + +scaleFactors = [0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 1, 1.05, 1.1, 1.2, 1.4, 1.6, 1.8, 2.0] + +resultCount = 0 + +def reportReturn( result ): + global resultCount + print( ".", end = '' ) + sys.stdout.flush() + resultCount += 1 + if resultCount % 50 == 0: + print( " {}".format( resultCount ) ) + +def main(): + parser = argparse.ArgumentParser( description = 'Wrapper script to run a lot of FindSim evaluations in parallel.' ) + + parser.add_argument( 'location', type = str, help='Required: Directory in which the scripts (in tsv format) are all located.') + parser.add_argument( '-n', '--numProcesses', type = int, help='Optional: Number of processes to spawn', default = 2 ) + parser.add_argument( '-m', '--model', type = str, help='Optional: Composite model definition file. First searched in directory "location", then in current directory.', default = "FindSim_compositeModel_1.g" ) + parser.add_argument( '-p', '--parameter_sweep', nargs='*', default=[], help='Does a parameter sweep in range 0.5-2x of each object.field pair.' ) + args = parser.parse_args() + location = args.location + if location[-1] != '/': + location += '/' + if os.path.isfile( location + args.model ): + modelFile = location + args.model + elif os.path.isfile( args.model ): + modelFile = args.model + else: + print( "Error: Unable to find model file {}".format( args.model ) ) + quit() + + fnames = [ (location + i) for i in os.listdir( args.location ) if i.endswith( ".tsv" )] + pool = Pool( processes = args.numProcesses ) + #ret = findSim.innerMain(fnames[0], hidePlot=True) + + argDict = {} + for i in args.parameter_sweep: + print( "{}".format( i ) ) + scaleDict = {} + spl = i.split( '.' ) + assert( len(spl) == 2 ) + obj, field = spl + for scale in scaleFactors: + ret = [] + for k in fnames: + ret.append( pool.apply_async( findSim.innerMain, (k,), dict(modelFile = modelFile, hidePlot=True, silent=True, scaleParam=[obj,field,str(scale)]), callback = reportReturn ) ) + scaleDict[scale] = ret + argDict[i] = scaleDict + + results = {} + for i in argDict: + scaleDict = argDict[i] + temp = {} + for j in scaleDict: + temp[j] = [ k.get() for k in scaleDict[j] ] + results[i] = temp + print( "\n---------------- Completed ----------------- " ) + for objfield in results: + analyzeResults( objfield, results[objfield] ) + +def analyzeResults( name, results ): + score = [] + scale = [] + for res in results: + goodRes = [ x for x in results[res] if x >= 0.0 ] + if len( goodRes ) > 0: + score.append( sum(goodRes)/len(goodRes) ) + scale.append( res ) + + if len(score) == 0: + print( "-1 at {} with Q = 0".format(name) ) + return + bestScore = min( score ) + bestScoreIndex = score.index( bestScore ) + # We want best, the scale of the best, if it is an extrema, and Q + # Q = slope = (max - min)/abs(scaleMax - scaleMin) + if len( score ) == 1: + Q = 0 + else: + worstScore = max(score) + worstScoreIndex = score.index( worstScore ) + Q = (worstScore - bestScore)/abs(scale[bestScoreIndex] - scale[worstScoreIndex]) + print( "{}: {:3f} at {} with Q = {:3f}".format(name, bestScore, scale[bestScoreIndex], + Q) ) + + +# Run the 'main' if this script is executed standalone. +if __name__ == '__main__': + main() diff --git a/findSim.py b/findSim.py index 654cf74..a7efeaa 100644 --- a/findSim.py +++ b/findSim.py @@ -531,6 +531,17 @@ def findObj( self,rootpath, name ): else: return try2[0] + def _scaleParam( self, params ): + if len(params) == 0: + return + if len(params) != 3: + raise SimError( "scaleParam: expecting [obj, field, scale], got: '{}'".format( params ) ) + + obj = self.findObj( '/model', params[0] ) + val = obj.getField( params[1] ) + obj.setField( params[1], val * float( params[2] ) ) + #print("ScaledParam {}.{} from {} to {}".format( params[0], params[1], val, obj.getField( params[1] ) ) ) + def modify( self, modelId, erSPlist, odelWarning): # Start off with things explicitly specified for deletion. kinpath = modelId.path @@ -1350,11 +1361,12 @@ def main(): parser.add_argument( '-hp', '--hide_plot', action="store_true", help='Hide plot output of simulation along with expected values. Default is to show plot.' ) parser.add_argument( '-hs', '--hide_subplots', action="store_true", help='Hide subplot output of simulation. By default the graphs include dotted lines to indicate individual quantities (e.g., states of a molecule) that are being summed to give a total response. This flag turns off just those dotted lines, while leaving the main plot intact.' ) parser.add_argument( '-o', '--optimize_elec', action="store_true", help='Optimize electrical computation. By default the electrical computation runs for the entire duration of the simulation. With this flag the system turns off the electrical engine except during the times when electrical stimuli are being given. This can be *much* faster.' ) + parser.add_argument( '-s', '--scale_param', nargs=3, default=[], help='Scale specified object.field by ratio.' ) args = parser.parse_args() - innerMain( args.script, modelFile = args.model, dumpFname = args.dump_subset, hidePlot = args.hide_plot, hideSubplots = args.hide_subplots, optimizeElec = args.optimize_elec ) + innerMain( args.script, modelFile = args.model, dumpFname = args.dump_subset, hidePlot = args.hide_plot, hideSubplots = args.hide_subplots, optimizeElec = args.optimize_elec, scaleParam = args.scale_param ) -def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot = True, hideSubplots = False, optimizeElec = True ): +def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot = True, hideSubplots = False, optimizeElec=True, silent = False, scaleParam=[] ): global pause solver = "gsl" # Pick any of gsl, gssa, ee.. modelWarning = "" @@ -1389,6 +1401,7 @@ def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot modelWarning = "" model.modify( modelId, erSPlist,modelWarning ) + model._scaleParam( scaleParam ) if len(dumpFname) > 2: if dumpFname[-2:] == '.g': moose.mooseWriteKkit( modelId.path, dumpFname ) @@ -1435,7 +1448,8 @@ def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot return score except SimError as msg: - print( "Error: findSim failed for script {}: {}".format(script, msg )) + if not silent: + print( "Error: findSim failed for script {}: {}".format(script, msg )) if modelId: moose.delete( modelId ) return -1.0 From 7afc19dd7eb8d8007d0d0315f6a2d3c9574c8f37 Mon Sep 17 00:00:00 2001 From: bhalla Date: Sun, 7 Oct 2018 11:58:02 +0530 Subject: [PATCH 3/6] Added output file to basicParameterSweep. Added options for field scaling of Kd and tau for reacs in findSim. --- basicParameterSweep.py | 28 ++++++++++++++++++++++------ findSim.py | 16 ++++++++++++++-- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/basicParameterSweep.py b/basicParameterSweep.py index 22cfe02..e4e1470 100644 --- a/basicParameterSweep.py +++ b/basicParameterSweep.py @@ -66,6 +66,7 @@ def main(): parser.add_argument( '-n', '--numProcesses', type = int, help='Optional: Number of processes to spawn', default = 2 ) parser.add_argument( '-m', '--model', type = str, help='Optional: Composite model definition file. First searched in directory "location", then in current directory.', default = "FindSim_compositeModel_1.g" ) parser.add_argument( '-p', '--parameter_sweep', nargs='*', default=[], help='Does a parameter sweep in range 0.5-2x of each object.field pair.' ) + parser.add_argument( '-f', '--file', type = str, help='Optional: File name for output of parameter sweep', default = "sweep.out" ) args = parser.parse_args() location = args.location if location[-1] != '/': @@ -104,20 +105,28 @@ def main(): temp[j] = [ k.get() for k in scaleDict[j] ] results[i] = temp print( "\n---------------- Completed ----------------- " ) + fp = open( args.file, "a" ) for objfield in results: - analyzeResults( objfield, results[objfield] ) + analyzeResults( fp, objfield, results[objfield] ) + fp.close() -def analyzeResults( name, results ): +def analyzeResults( fp, name, results ): score = [] scale = [] + numTotExpts = 0 + numGoodExpts = 0 for res in results: + numTotExpts += len( results[res] ) goodRes = [ x for x in results[res] if x >= 0.0 ] + numGoodExpts += len( goodRes ) if len( goodRes ) > 0: score.append( sum(goodRes)/len(goodRes) ) scale.append( res ) if len(score) == 0: - print( "-1 at {} with Q = 0".format(name) ) + outputStr = "{}: score -1 at scale - with Q = 0 in 0/{} expts".format(name, numTotExpts ) + print( outputStr ) + fp.write( outputStr ) return bestScore = min( score ) bestScoreIndex = score.index( bestScore ) @@ -129,9 +138,16 @@ def analyzeResults( name, results ): worstScore = max(score) worstScoreIndex = score.index( worstScore ) Q = (worstScore - bestScore)/abs(scale[bestScoreIndex] - scale[worstScoreIndex]) - print( "{}: {:3f} at {} with Q = {:3f}".format(name, bestScore, scale[bestScoreIndex], - Q) ) - + outputStr = "{}: score {:.3f} at scale {} with Q = {:.3f} in {}/{} expts".format(name, bestScore, scale[bestScoreIndex], Q, numGoodExpts, numTotExpts ) + print( outputStr ) + fp.write( outputStr + '\n' ) + for i, j in sorted(zip( scale, score )): + fp.write( "{:.3f} {:.3f}\n".format( i, j ) ) + for res in results: + goodRes = [ x for x in results[res] if x >= 0.0 ] + if len( goodRes ) > 0: + score.append( sum(goodRes)/len(goodRes) ) + scale.append( res ) # Run the 'main' if this script is executed standalone. if __name__ == '__main__': diff --git a/findSim.py b/findSim.py index a7efeaa..f0b37a3 100644 --- a/findSim.py +++ b/findSim.py @@ -538,8 +538,20 @@ def _scaleParam( self, params ): raise SimError( "scaleParam: expecting [obj, field, scale], got: '{}'".format( params ) ) obj = self.findObj( '/model', params[0] ) - val = obj.getField( params[1] ) - obj.setField( params[1], val * float( params[2] ) ) + scale = float( params[2] ) + assert( scale >= 0.0 and scale <= 100.0 ) + if params[1] == 'Kd': + if not obj.isA[ "ReacBase" ]: + raise SimError( "scaleParam: can only assign Kd to a Reac, was: '{}'".format( obj.className ) ) + sf = np.sqrt( scale ) + obj.Kb *= sf + obj.Kf /= sf + elif params[1] == 'tau': + obj.Kb /= scale + obj.Kf /= scale + else: + val = obj.getField( params[1] ) + obj.setField( params[1], val * scale) #print("ScaledParam {}.{} from {} to {}".format( params[0], params[1], val, obj.getField( params[1] ) ) ) def modify( self, modelId, erSPlist, odelWarning): From 660e43ce34b89dc476672c175ceea7de5c34cef0 Mon Sep 17 00:00:00 2001 From: bhalla Date: Sun, 7 Oct 2018 16:30:52 +0530 Subject: [PATCH 4/6] Added capability to generate a file of parameters that can be tweaked in specified subset of model to findSim --- findSim.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/findSim.py b/findSim.py index f0b37a3..ab85c0b 100644 --- a/findSim.py +++ b/findSim.py @@ -1342,6 +1342,53 @@ def buildVclamp( stim, modelLookup ): moose.connect( vclamp, 'currentOut', compt, 'injectMsg' ) moose.reinit() +def getUniqueName( model, obj ): + path1 = "{}/##/{},{}/{}".format( model, obj.name, model, obj.name ) + wf = moose.wildcardFind( path1 ) + assert( len( wf ) > 0 ) + if len( wf ) == 1: + return obj.name + pa = obj.parent.name + path2 = "{}/##/{}/{},{}/{}/{}".format( model, pa, obj.name, model, pa, obj.name ) + wf = moose.wildcardFind( path2 ) + assert( len( wf ) > 0 ) + if len( wf ) == 1: + return pa + "/" + obj.name + raise SimError( "getUniqueName: {} and {} non-unique, please rename.".format( wf[0].path, wf[1].path ) ) + return obj.name + + +def generateParamFile( model, fname ): + with open( fname, "w" ) as fp: + for i in moose.wildcardFind( model + "/##[ISA=PoolBase]" ): + conc = i.concInit + if conc > 0.0: + objName = getUniqueName( model, i ) + fp.write( "{} concInit\n".format( objName ) ) + + for i in moose.wildcardFind( model + "/##[ISA=ReacBase]" ): + Kf = i.Kf + Kb = i.Kb + if Kb <= 0.0 and Kf <= 0.0: + return + objName = getUniqueName(model, i) + if Kb <= 0.0: + fp.write( "{} Kf\n".format( objName ) ) + elif Kf <= 0.0: + fp.write( "{} Kb\n".format( objName ) ) + else: # Prefer the Kd and tau where possible. + fp.write( "{} Kd\n".format( objName ) ) + fp.write( "{} tau\n".format( objName ) ) + + for i in moose.wildcardFind( model + "/##[ISA=EnzBase]" ): + Km = i.Km + kcat = i.kcat + if Km <= 0.0 or kcat <= 0.0: + return + objName = getUniqueName(model, i) + fp.write( "{} Km\n".format( objName ) ) + fp.write( "{} kcat\n".format( objName ) ) + def runit( expt, model, stims, readouts, modelId ): for i in stims: i.configure( model.modelLookup ) @@ -1370,15 +1417,16 @@ def main(): parser.add_argument( 'script', type = str, help='Required: filename of experiment spec, in tsv format.') parser.add_argument( '-m', '--model', type = str, help='Optional: model filename, .g or .xml', default = "models/synSynth7.g" ) parser.add_argument( '-d', '--dump_subset', type = str, help='Optional: dump selected subset of model into named file', default = "" ) + parser.add_argument( '-p', '--param_file', type = str, help='Optional: Generate file of tweakable params belonging to selected subset of model', default = "" ) parser.add_argument( '-hp', '--hide_plot', action="store_true", help='Hide plot output of simulation along with expected values. Default is to show plot.' ) parser.add_argument( '-hs', '--hide_subplots', action="store_true", help='Hide subplot output of simulation. By default the graphs include dotted lines to indicate individual quantities (e.g., states of a molecule) that are being summed to give a total response. This flag turns off just those dotted lines, while leaving the main plot intact.' ) parser.add_argument( '-o', '--optimize_elec', action="store_true", help='Optimize electrical computation. By default the electrical computation runs for the entire duration of the simulation. With this flag the system turns off the electrical engine except during the times when electrical stimuli are being given. This can be *much* faster.' ) parser.add_argument( '-s', '--scale_param', nargs=3, default=[], help='Scale specified object.field by ratio.' ) args = parser.parse_args() - innerMain( args.script, modelFile = args.model, dumpFname = args.dump_subset, hidePlot = args.hide_plot, hideSubplots = args.hide_subplots, optimizeElec = args.optimize_elec, scaleParam = args.scale_param ) + innerMain( args.script, modelFile = args.model, dumpFname = args.dump_subset, paramFname = args.param_file, hidePlot = args.hide_plot, hideSubplots = args.hide_subplots, optimizeElec = args.optimize_elec, scaleParam = args.scale_param ) -def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot = True, hideSubplots = False, optimizeElec=True, silent = False, scaleParam=[] ): +def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", paramFname = "", hidePlot = True, hideSubplots = False, optimizeElec=True, silent = False, scaleParam=[] ): global pause solver = "gsl" # Pick any of gsl, gssa, ee.. modelWarning = "" @@ -1422,6 +1470,9 @@ def innerMain( script, modelFile = "model/synSynth7.g", dumpFname = "", hidePlot else: raise SimError( "Subset file type not known for '{}'".format( dumpFname ) ) + if len(paramFname) > 0: + generateParamFile( modelId.path, paramFname ) + model.buildModelLookup() if expt.exptType == 'directparameter': From f43e81a20125f42be56adc48c39d89760c9a8bd2 Mon Sep 17 00:00:00 2001 From: bhalla Date: Sun, 7 Oct 2018 20:11:23 +0530 Subject: [PATCH 5/6] Updated basicParamSweep to use either directory (existing) or file (new) to specify which experiment files to use. The file option has a list of experiment files followed by weights to assign to each. --- basicParameterSweep.py | 67 +++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/basicParameterSweep.py b/basicParameterSweep.py index e4e1470..819f2b2 100644 --- a/basicParameterSweep.py +++ b/basicParameterSweep.py @@ -59,6 +59,30 @@ def reportReturn( result ): if resultCount % 50 == 0: print( " {}".format( resultCount ) ) +def enumerateFindSimFiles( location ): + if os.path.isdir( location ): + if location[-1] != '/': + location += '/' + fnames = [ (location + i) for i in os.listdir( location ) if i.endswith( ".tsv" )] + return fnames, [1.0] * len( fnames ) + elif os.path.isfile( location ): + fnames = [] + weights = [] + with open( location, "r" ) as fp: + for line in fp: + if len( line ) <= 2: + continue + if line[0] == '#': + continue + f,w = line.split() + fnames.append( f ) + weights.append( float( w ) ) + return fnames, weights + else: + print( "Error: Unable to find file or directory at " + location ) + quit() + + def main(): parser = argparse.ArgumentParser( description = 'Wrapper script to run a lot of FindSim evaluations in parallel.' ) @@ -66,7 +90,7 @@ def main(): parser.add_argument( '-n', '--numProcesses', type = int, help='Optional: Number of processes to spawn', default = 2 ) parser.add_argument( '-m', '--model', type = str, help='Optional: Composite model definition file. First searched in directory "location", then in current directory.', default = "FindSim_compositeModel_1.g" ) parser.add_argument( '-p', '--parameter_sweep', nargs='*', default=[], help='Does a parameter sweep in range 0.5-2x of each object.field pair.' ) - parser.add_argument( '-f', '--file', type = str, help='Optional: File name for output of parameter sweep', default = "sweep.out" ) + parser.add_argument( '-f', '--file', type = str, help='Optional: File name for output of parameter sweep', default = "" ) args = parser.parse_args() location = args.location if location[-1] != '/': @@ -79,7 +103,10 @@ def main(): print( "Error: Unable to find model file {}".format( args.model ) ) quit() - fnames = [ (location + i) for i in os.listdir( args.location ) if i.endswith( ".tsv" )] + #fnames = [ (location + i) for i in os.listdir( args.location ) if i.endswith( ".tsv" )] + fnames, weights = enumerateFindSimFiles( args.location ) + #print( fnames ) + #print( weights ) pool = Pool( processes = args.numProcesses ) #ret = findSim.innerMain(fnames[0], hidePlot=True) @@ -105,28 +132,38 @@ def main(): temp[j] = [ k.get() for k in scaleDict[j] ] results[i] = temp print( "\n---------------- Completed ----------------- " ) - fp = open( args.file, "a" ) + dumpData = False + fp = "" + if len( args.file ) > 0: + fp = open( args.file, "w" ) + dumpData = True for objfield in results: - analyzeResults( fp, objfield, results[objfield] ) - fp.close() + analyzeResults( fp, dumpData, objfield, results[objfield], weights ) + if dumpData: + fp.close() -def analyzeResults( fp, name, results ): +def analyzeResults( fp, dumpData, name, results, weights ): score = [] scale = [] numTotExpts = 0 numGoodExpts = 0 + sumWts = 0.0 for res in results: + assert( len( weights ) == len( results[res] ) ) numTotExpts += len( results[res] ) - goodRes = [ x for x in results[res] if x >= 0.0 ] + goodRes = [ x*w for x,w in zip(results[res], weights) if x >= 0.0 ] + sumWts = sum( [w for x,w in zip(results[res], weights) if x>= 0.0]) numGoodExpts += len( goodRes ) if len( goodRes ) > 0: - score.append( sum(goodRes)/len(goodRes) ) + score.append( sum(goodRes)/sumWts ) + #print( "{}, {}".format( goodRes, sumWts ) ) scale.append( res ) if len(score) == 0: outputStr = "{}: score -1 at scale - with Q = 0 in 0/{} expts".format(name, numTotExpts ) print( outputStr ) - fp.write( outputStr ) + if dumpData: + fp.write( outputStr ) return bestScore = min( score ) bestScoreIndex = score.index( bestScore ) @@ -140,14 +177,10 @@ def analyzeResults( fp, name, results ): Q = (worstScore - bestScore)/abs(scale[bestScoreIndex] - scale[worstScoreIndex]) outputStr = "{}: score {:.3f} at scale {} with Q = {:.3f} in {}/{} expts".format(name, bestScore, scale[bestScoreIndex], Q, numGoodExpts, numTotExpts ) print( outputStr ) - fp.write( outputStr + '\n' ) - for i, j in sorted(zip( scale, score )): - fp.write( "{:.3f} {:.3f}\n".format( i, j ) ) - for res in results: - goodRes = [ x for x in results[res] if x >= 0.0 ] - if len( goodRes ) > 0: - score.append( sum(goodRes)/len(goodRes) ) - scale.append( res ) + if dumpData: + fp.write( outputStr + '\n' ) + for i, j in sorted(zip( scale, score )): + fp.write( "{:.3f} {:.3f}\n".format( i, j ) ) # Run the 'main' if this script is executed standalone. if __name__ == '__main__': From c33b5ea68e789502573565e0ed3651a2bab3a2b9 Mon Sep 17 00:00:00 2001 From: bhalla Date: Sun, 7 Oct 2018 20:16:43 +0530 Subject: [PATCH 6/6] Minor edit to help info for basicParameterSweep --- basicParameterSweep.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basicParameterSweep.py b/basicParameterSweep.py index 819f2b2..ed790a2 100644 --- a/basicParameterSweep.py +++ b/basicParameterSweep.py @@ -86,7 +86,7 @@ def enumerateFindSimFiles( location ): def main(): parser = argparse.ArgumentParser( description = 'Wrapper script to run a lot of FindSim evaluations in parallel.' ) - parser.add_argument( 'location', type = str, help='Required: Directory in which the scripts (in tsv format) are all located.') + parser.add_argument( 'location', type = str, help='Required: Directory in which the scripts (in tsv format) are all located. OR: File in which each line is the filename of a scripts.tsv file, followed by weight to assign for that file.') parser.add_argument( '-n', '--numProcesses', type = int, help='Optional: Number of processes to spawn', default = 2 ) parser.add_argument( '-m', '--model', type = str, help='Optional: Composite model definition file. First searched in directory "location", then in current directory.', default = "FindSim_compositeModel_1.g" ) parser.add_argument( '-p', '--parameter_sweep', nargs='*', default=[], help='Does a parameter sweep in range 0.5-2x of each object.field pair.' )