Skip to content

Commit 5e6a9e6

Browse files
committed
Added option to multi_param_minimization to tweak model file in accordance with optimization results
1 parent 13d3894 commit 5e6a9e6

File tree

1 file changed

+43
-5
lines changed

1 file changed

+43
-5
lines changed

multi_param_minimization.py

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@
4949
import time
5050
import findSim
5151
from multiprocessing import Pool
52+
import moose
5253

5354
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]
5455

5556
resultCount = 0
5657
numIterations = 0
57-
TOLERANCE = 0.0001 # Don't want to go too tight on tolarance.
5858

5959
def reportReturn( result ):
6060
global resultCount
@@ -123,14 +123,15 @@ def optCallback( x ):
123123

124124
def main():
125125
t0 = time.time()
126-
parser = argparse.ArgumentParser( description = 'Wrapper script to run a lot of FindSim evaluations in parallel.' )
127-
126+
parser = argparse.ArgumentParser( description = 'Script to run a multi-parameter optimization in which each function evaluation is the weighted mean of a set of FindSim evaluations. These evaluations may be run in parallel. The optimiser uses the BGFR method with bounds. Since we are doing relative scaling the bounds are between 0.03 and 30 for Kd, tau and Km, and between 0 and 30 for other parameters' )
128127
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.')
129128
parser.add_argument( '-n', '--numProcesses', type = int, help='Optional: Number of processes to spawn', default = 2 )
129+
parser.add_argument( '-t', '--tolerance', type = float, help='Optional: Tolerance criterion for completion of minimization', default = 1e-4 )
130130
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" )
131-
parser.add_argument( '-p', '--parameters', nargs='*', default=[], help='Parameter to vary. Each is defined as an object.field pair. The object is defined as a unique MOOSE name, typically name or parent/name. The field is separated from the object by a period. The field may be concInit for molecules, Kf, Kb, Kd or tau for reactions, and Km or Kcat for enzymes. One can specify more than one parameter for a given reaction or enzyme. It is advisable to use Kd and tau for reactions unless you have a unidirectional reaction.' )
131+
parser.add_argument( '-p', '--parameters', nargs='*', default=[], help='Parameter to vary. Each is defined as an object.field pair. The object is defined as a unique MOOSE name, typically name or parent/name. The field is separated from the object by a period. The field may be concInit for molecules, Kf, Kb, Kd or tau for reactions, and Km or kcat for enzymes. One can specify more than one parameter for a given reaction or enzyme. It is advisable to use Kd and tau for reactions unless you have a unidirectional reaction.' )
132132
parser.add_argument( '-f', '--file', type = str, help='Optional: File name for output of parameter minimization', default = "" )
133133
args = parser.parse_args()
134+
134135
location = args.location
135136
if location[-1] != '/':
136137
location += '/'
@@ -162,7 +163,7 @@ def main():
162163
ev.doEval( [1.0]* len( params ) )
163164
initScore = ev.score
164165
# Do the minimization
165-
results = optimize.minimize( ev.doEval, np.ones( len(params) ), method='L-BFGS-B', tol = TOLERANCE, callback = optCallback, bounds = bounds )
166+
results = optimize.minimize( ev.doEval, np.ones( len(params) ), method='L-BFGS-B', tol = args.tolerance, callback = optCallback, bounds = bounds )
166167
print( "\n----------- Completed in {:.3f} sec ---------- ".format(time.time() - t0 ) )
167168
print( "\n----- Score= {:.4f} ------ ".format(results.fun ) )
168169
dumpData = False
@@ -173,6 +174,43 @@ def main():
173174
analyzeResults( fp, dumpData, results, params, ev, initScore )
174175
if dumpData:
175176
fp.close()
177+
dumpTweakedModelFile( args, params, results )
178+
179+
def dumpTweakedModelFile( args, params, results ):
180+
filename, file_extension = os.path.splitext( args.model )
181+
resfname, res_ext = os.path.splitext( args.file )
182+
if file_extension == ".xml":
183+
modelId, errormsg = moose.mooseReadSBML( args.model, 'model', 'ee' )
184+
tweakParams( params, results.x )
185+
moose.mooseWriteSBML( modelId.path, resfname + "_tweaked.xml" )
186+
moose.delete( modelId )
187+
elif file_extension == ".g":
188+
modelId = moose.loadModel( args.model, 'model', 'ee' )
189+
tweakParams( params, results.x )
190+
moose.mooseWriteKkit( modelId.path, resfname + "_tweaked.g" )
191+
moose.delete( modelId )
192+
else:
193+
print( "Warning: dumpTweakedModelFile: Don't know file type for {}".format( args.model ) )
194+
195+
def tweakParams( params, scaleFactors ):
196+
for i, x in zip( params, scaleFactors ):
197+
objname, field = i.split( '.' )
198+
w = moose.wildcardFind( "/model/##/{0},/model/{0}".format(objname) )
199+
if len(w) != 1:
200+
print( "Error: tweakParams: Need precisely one object to match name '{}', got {}".format( objname, len(w) ) )
201+
continue
202+
obj = w[0]
203+
if field == 'Kd':
204+
obj.Kf /= np.sqrt( x )
205+
obj.Kb *= np.sqrt( x )
206+
elif field == 'tau':
207+
obj.Kf /= x
208+
obj.Kb /= x
209+
else:
210+
obj.setField( field, obj.getField( field ) * x )
211+
#print( "Tweaked {}.{} by {}".format( obj.path, field, x ) )
212+
213+
176214

177215
def analyzeResults( fp, dumpData, results, params, evalObj, initScore ):
178216
#assert( len(results.x) == len( results.fun ) )

0 commit comments

Comments
 (0)