Index: /issm/trunk-jpl/src/m/model/ismodelselfconsistent.m
===================================================================
--- /issm/trunk-jpl/src/m/model/ismodelselfconsistent.m	(revision 12754)
+++ /issm/trunk-jpl/src/m/model/ismodelselfconsistent.m	(revision 12755)
@@ -12,5 +12,5 @@
 [analyses,numanalyses]=AnalysisConfiguration(solution);
 
-%Go through al model field check that it is a class and call checkconsistency
+%Go through a model field, check that it is a class, and call checkconsistency
 fields=properties('model');
 for i=1:length(fields),
Index: /issm/trunk-jpl/src/m/model/ismodelselfconsistent.py
===================================================================
--- /issm/trunk-jpl/src/m/model/ismodelselfconsistent.py	(revision 12755)
+++ /issm/trunk-jpl/src/m/model/ismodelselfconsistent.py	(revision 12755)
@@ -0,0 +1,35 @@
+"""
+ISMODELSELFCONSISTENT - check that model forms a closed form solvable problem.
+ 
+    Usage:
+       ismodelselfconsistent(md),
+"""
+
+def ismodelselfconsistent(md):
+
+	#initialize consistency as true
+	md.private.isconsistent=true
+
+	#Get solution and associated analyses
+	solution=md.private.solution
+	analyses,numanalyses=AnalysisConfiguration(solution)
+
+	#Go through a model fields, check that it is a class, and call checkconsistency
+	fields=variables('model')
+	for field in fields:
+
+		#Some properties do not need to be checked
+		if field in ['results','debug','radaroverlay']:
+			continue
+
+		#Check that current field is an object
+		if not hasattr(getattr(md,field),'checkconsistency'):
+			md=checkmessage(md,"field '%s' is not an object." % field)
+
+		#Check consistency of the object
+		exec("md.%s.checkconsistency(md,solution,analyses)" % field)
+
+	#error message if mode is not consistent
+	if not md.private.isconsistent:
+		raise RuntimeError('Model not consistent, see messages above.')
+
Index: /issm/trunk-jpl/src/m/model/solve.py
===================================================================
--- /issm/trunk-jpl/src/m/model/solve.py	(revision 12755)
+++ /issm/trunk-jpl/src/m/model/solve.py	(revision 12755)
@@ -0,0 +1,116 @@
+"""
+SOLVE - apply solution sequence for this model
+ 
+    Usage:
+       md=solve(md,solutionenum,varargin)
+       where varargin is a list of paired arguments of string OR enums
+ 
+    solution types available comprise:
+ 		 - DiagnosticSolutionEnum
+ 		 - PrognosticSolutionEnum
+ 		 - ThermalSolutionEnum
+ 		 - SteadystateSolutionEnum
+ 		 - TransientSolutionEnum...
+ 		 - BalancethicknessSolutionEnum
+ 		 - BedSlopeSolutionEnum
+ 		 - SurfaceSlopeSolutionEnum
+ 		 - HydrologySolutionEnum
+ 		 - FlaimSolutionEnum
+ 
+   extra options:
+       - loadonly : does not solve. only load results
+ 
+    Examples:
+       md=solve(md,DiagnosticSolutionEnum);
+"""
+
+import datetime
+import os
+import shutil
+
+def solve(md,solutionenum,*args):
+
+	#recover and process solve options
+	options=pairoptions('solution_type',solutionenum,*args)
+	options=process_solve_options(options)
+
+	#recover some fields
+	md.private.solution=options['solution_type']
+	cluster=md.cluster
+
+	#check model consistency
+	print "checking model consistency"
+	if solutionenum == FlaimSolutionEnum:
+		md.private.isconsistent=True
+		md.mesh.checkconsistency(md,solutionenum)
+		md.flaim.checkconsistency(md,solutionenum)
+		if not md.private.isconsistent:
+			raise RuntimeError("Model not consistent, see messages above.")
+	else:
+		ismodelselfconsistent(md)
+
+	#First, build a runtime name that is unique
+	c=datetime.datetime.now()
+	md.private.runtimename="%s-%02i-%02i-%04i-%02i-%02i-%02i-%i" % (md.miscellaneous.name,c.month,c.day,c.year,c.hour,c.minute,c.second,os.getpid())
+
+	#if running qmu analysis, some preprocessing of dakota files using models
+	#fields needs to be carried out. 
+	if md.qmu.isdakota:
+		md=preqmu(md,options)
+
+	#flaim analysis
+	if options['solution_type'] == FlaimSolutionEnum:
+		md=flaim_sol(md,options)
+		md.private.solution=EnumToString(options['solution_type'])
+		return md
+
+	#Do we load results only?
+	if options['loadonly']:  
+		md=loadresultsfromcluster(md)
+		return md
+
+	#Wite all input files
+	marshall(md)                                           # bin file
+	md.solver.PetscFile(md.miscellaneous.name+'.petsc')    # petsc file
+	cluster.BuildQueueScript(md.miscellaneous.name,md.private.solution,md.settings.io_gather,md.debug.valgrind,md.debug.gprof)    # queue file
+
+	#we need to make sure we have PETSC support, otherwise, we run with only one cpu: 
+	if not ispetsc:
+		print "PETSC support not included, running on 1 cpu only!"
+		cluster.np=1
+
+	#Stop here if batch mode
+	if strcmpi(options['batch'],'yes'):
+		print 'batch mode requested: not launching job interactively'
+		print 'launch solution sequence on remote cluster by hand'
+		return md
+
+	#Launch job
+	modelname = md.miscellaneous.name
+	filelist  = [modelname+'.bin ',modelname+'.petsc ',modelname+'.queue ']
+	if md.qmu.isdakota:
+		filelist.append(modelname+'.qmu.in')
+	cluster.LaunchQueueJob(md.miscellaneous.name,md.private.runtimename,filelist)
+
+	#did we even try to run? if so, wait on lock
+	if strcmpi(options['upload'],'on'):
+		print 'solve done uploading test decks'
+		return md
+
+	#wait on lock
+	if md.settings.waitonlock>0:
+		#we wait for the done file
+		islock=waitonlock(md)
+		if islock==0:    #no results to be loaded
+			print 'The results must be loaded manually with md=loadresultsfromcluster(md).'
+		else:            #load results
+			print 'loading results from cluster'
+			md=loadresultsfromcluster(md)
+
+	#post processes qmu results if necessary
+	if md.qmu.isdakota:
+		if not strncmpi(options['keep'],'y',1):
+			shutil.rmtree('qmu'+str(os.getpid()))
+
+	return md
+
