#!/usr/local/bin/env python

#=============================================================================================
# MODULE DOCSTRING
#=============================================================================================

"""
Test that forces and energies agree across platforms

DESCRIPTION

TODO

COPYRIGHT AND LICENSE

@author Mark Friedrichs <friedrim@stanford.edu>

All code in this repository is released under the GNU General Public License.

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 of the License, 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.  If not, see <http://www.gnu.org/licenses/>.

"""

#=============================================================================================
# GLOBAL IMPORTS
#=============================================================================================

import sys
import traceback
import os
import os.path
import math
import doctest
import time

import simtk.unit as units
import simtk.openmm as openmm
from ValidationUtilities import ValidationUtilities             
from ParameterFileParser                import ValidationParameterFileParser
from OpenMMSystemParameters             import OpenMMSystemParameters

import ForceEnergyPlatformComparisonTests

#=============================================================================================
# Print usage (command-line arguments)
#=============================================================================================

def printUsage( ):
    """Print command line arguments

    ARGUMENTS

    """

    firstTab    = 1
    secondTab   = 19
    thirdTab    = 60
    print "Command line arguments:\n"
    outputString  = ' '.rjust(firstTab) + "-platform0".rjust(secondTab) + " Comparison platform (Reference, Cuda, OpenCL)\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-platform1".rjust(secondTab) + " Comparison platform (Reference, Cuda, OpenCL)\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-controlFile".rjust(secondTab) + " Control file name\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-systemsDirectory".rjust(secondTab) + " Systems file directory\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-serializeDirectory".rjust(secondTab) + " Serialize file directory\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-configDirectory".rjust(secondTab) + " Config file directory\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-dataDirectory".rjust(secondTab) + " Data file directory\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-deviceId".rjust(secondTab) + " device id for gpu\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-sleep ".rjust(secondTab) + " if nonzero, then sleep the specified time between tests\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-verbose".rjust(secondTab) + " if nonzero, then be verbose\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-testSummaryFileName".rjust(secondTab) + " summary file name\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-printParam".rjust(secondTab) + " if nonzero, then be print parameters\n".rjust(thirdTab)
    outputString += ' '.rjust(firstTab) + "-help".rjust(secondTab) + " current output\n".rjust(thirdTab)
    outputString += "\n\n"
    print outputString
    return 

# parse command-line arguments

def parseCommandLine( argumentHash ):

    argLen   = len( sys.argv )
    argLenM1 = argLen - 1
    skip     = 0
    verbose  = argumentHash['Verbose']
    for ii in range( 1,argLen ):  
        if( skip ): 
           skip = 0
           continue
        if( sys.argv[ii].startswith('-platform0') and ii < argLenM1 ):
            skip = 1
            argumentHash['Platform0'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-platform1') and ii < argLenM1 ):
            skip = 1
            argumentHash['Platform1'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-systemsDirectory') and ii < argLenM1 ):
            skip = 1
            systemsDirectory = sys.argv[ii+1]
            argumentHash['SystemsDirectory'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-serializeDirectory') and ii < argLenM1 ):
            skip = 1
            serializeDirectory = sys.argv[ii+1]
            argumentHash['SerializeDirectory'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-configDirectory') and ii < argLenM1 ):
            skip = 1
            argumentHash['ConfigDirectory'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-dataDirectory') and ii < argLenM1 ):
            skip = 1
            argumentHash['DataDirectory'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-sleep') and ii < argLenM1 ):
            skip = 1
            argumentHash['Sleep'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-deviceId') and ii < argLenM1 ):
            skip = 1
            argumentHash['DeviceId'] = int( sys.argv[ii+1] )

        elif( sys.argv[ii].startswith('-verbose') and ii < argLenM1 ):
            skip = 1
            if( int( sys.argv[ii+1] ) > 0 ):
                 argumentHash['Verbose']  = True 
            else:
                 argumentHash['Verbose']  = False

        elif( sys.argv[ii].startswith('-printParam') and ii < argLenM1 ):
            skip = 1
            if( int( sys.argv[ii+1] ) > 0 ):
                 argumentHash['PrintParam']  = True 
            else:
                 argumentHash['PrintParam']  = False

        elif( sys.argv[ii].startswith('-testSummaryFileName') and ii < argLenM1 ):
            skip = 1
            argumentHash['TestSummaryFileName'] = sys.argv[ii+1]

        elif( sys.argv[ii].startswith('-showTests') and ii < argLenM1 ):
            skip = 1
            if( int( sys.argv[ii+1] ) > 0 ):
                 argumentHash['ShowTests']  = True 
            else:
                 argumentHash['ShowTests']  = False

        elif( sys.argv[ii].startswith('-controlFile') and ii < argLenM1 ):
            skip = 1
            argumentHash['ControlFileName']  = sys.argv[ii+1]
        elif( sys.argv[ii].startswith('-help') ):
            printUsage()
            exit(-1)
        else:
            print "Argument %3d %s not recognized." % (ii,sys.argv[ii])
            sys.stdout.flush()
            printUsage()
            exit(-1)

        if( verbose ):
            print "%3d %s" % (ii,sys.argv[ii])
    return

#=============================================================================================
# Print a summary of the results to a file
#=============================================================================================

def printTestSummary( testSummaryFileName, testNameHash, testResults ):

    """Print summary of results

    ARGUMENTS
        testSummaryFileName  (string) summary file name
        testResults          (hash)   testResults[testName] = testResult (EnergyForceComparisonResult object)

    """

    firstTab    = 30
    summaryFile = open( testSummaryFileName, 'w')
    for testName,dummyArg in testNameHash.iteritems():
        #012345678 012345678901234567890123456789 012345678 P/F 012345678901234567 012345678901234 01234567890 01234567890123
        # Platform                         System Particles   1 ForceRelativeDelta NormMaxRelDelta AvgRelDelta EnergyRelDelta
        headerString = testName.rjust(firstTab) + "\n Platform                         System Particles   1 ForceRelativeDelta NormMaxRelDelta AvgRelDelta EnergyRelDelta"
        summaryFile.write( headerString + "\n\n" )
        count        = 0
        average      = 0.0
        wtAverage    = 0.0
        wtStddev     = 0.0
        wtCount      = 0.0
        max          = -1.0
        for fullTestName, result in testResults.iteritems():
            if( result.getTestName() == testName ):

                passed         = result.testPassed( )

                outputString   = result.getPlatform( 1 ).rjust(9) + " "
                outputString  += result.getSystemName().rjust(firstTab) + " "
                outputString  += ("%6d" % result.getNumberOfParticles()).rjust(9) + " "
                outputString  += repr(passed).rjust(3) + " "
                outputString  += ("%10.3e" % result.getMaxRelativeDeltaInForce()).rjust(18) + " "
                sys.stdout.flush()
                outputString  += ("%10.3e" % result.getMaxRelativeDeltaInForceNormSum()).rjust(15) + " "
                outputString  += ("%10.3e" % result.getAvgRelativeDeltaInForce()).rjust(11) + " "
                sys.stdout.flush()
                outputString  += ("%10.3e" % result.getRelativeDeltaPotentialEnergy()).rjust(14) + " "
                outputString += "Tol=" + ("%8.2e" % result.getTolerance())
                average       += result.getMaxRelativeDeltaInForce() 
                count         += 1
                wtAverage     += result.getAvgRelativeDeltaInForce()*result.getCntRelativeDeltaInForce()
                wtStddev      += result.getStdRelativeDeltaInForce()*result.getCntRelativeDeltaInForce()
                wtCount       += result.getCntRelativeDeltaInForce()

                if( result.getMaxRelativeDeltaInForce() > max ):
                    max = result.getMaxRelativeDeltaInForce()
 
                summaryFile.write( outputString + "\n" )

        if( count > 0 ):
            average = average/count

        if( wtCount > 0 ): 
            wtAverage /= wtCount
            wtStddev  /= wtCount

        outputString   = "\n%40s Max %10.3e  Average %10.3e  Count %d\n" % (testName, max, average, count)
        outputString  += "%40s Weighted Average %10.3e  Stdev %10.3e Count %d\n" % (testName, wtAverage, wtStddev, wtCount)

        summaryFile.write( outputString + "\n\n\n" )

    summaryFile.close()

    return

#=============================================================================================
# Build tests objects given name and args
#=============================================================================================

def forceEnergyComparisonTestFactory( testName, systemParameters, testParameterHash, verbose ):

    """Build test

    ARGUMENTS
        test name                         test name
        systemParameters                  systemParameters
        testParameterHash                 testParameterHash
        verbose                           if true, be verbose

    RETURN
        if testName is valid, return test object; else return None
    """
    if( testName == 'HarmonicBondForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.HarmonicBondForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'HarmonicAngleForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.HarmonicAngleForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'PeriodicTorsionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.PeriodicTorsionForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'RBTorsionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.RBTorsionForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'NonbondedForceNoCutoffTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.NonbondedForceNoCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'NonbondedForceCutoffNonPeriodicTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.NonbondedForceCutoffNonPeriodicTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'NonbondedForceCutoffPeriodicTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.NonbondedForceCutoffPeriodicTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'NonbondedForceEwaldTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.NonbondedForceEwaldTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'NonbondedForcePMETest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.NonbondedForcePMETest( systemParameters, testParameterHash, verbose )

    elif( testName == 'GbsaObcForceNoCutoffTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.GbsaObcForceNoCutoffTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'GbsaObcForceCutoffNonPeriodicTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.GbsaObcForceCutoffNonPeriodicTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'GbsaObcForceCutoffPeriodicTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.GbsaObcForceCutoffPeriodicTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'GbviForceNoCutoffTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.GbviForceNoCutoffTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'CustomBondForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.CustomBondForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomAngleForceTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomAngleForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomTorsionForceTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomTorsionForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'CMAPTorsionForceTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CMAPTorsionForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'CustomExternalForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.CustomExternalForceTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomNonbondedForceNonPeriodicCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomNonbondedForceNonPeriodicCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomNonbondedForcePeriodicCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomNonbondedForcePeriodicCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomNonbondedForceNoCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomNonbondedForceNoCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomGbsaForceNonPeriodicCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomGbsaForceNonPeriodicCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomGbsaForcePeriodicCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomGbsaForcePeriodicCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomNonbondedForceNoModificationTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomNonbondedForceNoModificationTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'CustomGbsaForceNoCutoffTest' ):
       forceTest   = ForceEnergyPlatformComparisonTests.CustomGbsaForceNoCutoffTest( systemParameters, testParameterHash, verbose )
    elif( testName == 'AmoebaGeneralizedKirkwoodForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaGeneralizedKirkwoodForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaHarmonicAngleForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaHarmonicAngleForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaHarmonicBondForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaHarmonicBondForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaOutOfPlaneBendForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaOutOfPlaneBendForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaHarmonicInPlaneAngleForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaHarmonicInPlaneAngleForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaMultipoleForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaMultipoleForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaPiTorsionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaPiTorsionForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaTorsionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaTorsionForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaTorsionTorsionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaTorsionTorsionForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaStretchBendForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaStretchBendForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaUreyBradleyForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaUreyBradleyForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaVdwForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaVdwForceTest( systemParameters, testParameterHash, verbose )

    elif( testName == 'AmoebaWcaDispersionForceTest' ):
        forceTest   = ForceEnergyPlatformComparisonTests.AmoebaWcaDispersionForceTest( systemParameters, testParameterHash, verbose )

    else:
        forceTest   = None
        print "%s test not recognized." % testName

    return forceTest

#=============================================================================================
# MAIN
#=============================================================================================

# set Validation directory

argumentHash                             = {}
validationUtilities                      = ValidationUtilities(False)

validationDirectory                      = os.path.join(os.getenv('PYOPENMM_SOURCE_DIR'), 'test', 'validation')
useXml                                   = 1
if( useXml ):
    parameterFileSuffix                  = '.xml'
    systemsDirectory                     = os.path.join(validationDirectory, 'systems_xml')
else:
    parameterFileSuffix                  = '.txt'
    systemsDirectory                         = os.path.join(validationDirectory, 'systems')
configDirectory                          = os.path.join(validationDirectory, 'config')
dataDirectory                            = os.path.join(validationDirectory, 'data')

testListFileName                         = 'ForceEnergyComparisonTestNames.txt'
systemListFileName                       = 'SystemNames.txt'

argumentHash['ValidationDirectory']      = validationDirectory
argumentHash['ConfigDirectory']          = configDirectory
argumentHash['DataDirectory']            = dataDirectory
argumentHash['TestListFileName']         = testListFileName
argumentHash['SystemListFileName']       = systemListFileName
argumentHash['SystemsDirectory']         = systemsDirectory
argumentHash['Platform0']                = 'Reference'
argumentHash['Platform1']                = 'Cuda'
#argumentHash['Platform1']                = 'OpenCL'
argumentHash['Verbose']                  = False
argumentHash['Verbose']                  = True
argumentHash['PrintParam']               = False
argumentHash['ShowTests']                = False
argumentHash['TestSummaryFileName']      = 'NA'
argumentHash['Sleep']                    = 0

# parse command line

parseCommandLine( argumentHash )

systemsDirectory                         = argumentHash['SystemsDirectory']

if( 'SerializeDirectory' in argumentHash ):
    serializeDirectory                   = argumentHash['SerializeDirectory']
else:
    serializeDirectory                   = 0

# track number of tests that do not run

numberOfTestsThatDidNotRun               = 0

defaultParameterHash                     = { 
                                               'Active'                     :       1,
                                               'Tolerance'                  :       1.0e-02,
                                               'MinForceNormCutoff'         :       1.0e+00,
                                               'MinEnergyNormCutoff'        :       1.0e+00,
                                           }

verbose                                  = argumentHash['Verbose']
validationUtilities.setVerbose( verbose )
printParam                               = argumentHash['PrintParam']

comparisonPlatformList                   = [ ]
comparisonPlatformList.append( argumentHash['Platform0'] )
comparisonPlatformList.append( argumentHash['Platform1'] )

if( argumentHash['TestSummaryFileName'] != 'NA' ):
    testSummaryFileName                      = argumentHash['TestSummaryFileName']
else:
    testSummaryFileName = comparisonPlatformList[0] + comparisonPlatformList[1] + 'ForceEnergyComparisonSummary.txt'

fullTestListFileName                     = os.path.join( argumentHash['DataDirectory'], argumentHash['TestListFileName'] )
testList                                 = validationUtilities.getListFromFile( fullTestListFileName )

fullSystemListFileName                   = os.path.join( argumentHash['DataDirectory'], argumentHash['SystemListFileName'] )
systemList                               = validationUtilities.getListFromFile( fullSystemListFileName )

testHash                                 = validationUtilities.buildDefaultTestHash( testList, systemList, defaultParameterHash )
if( 'ControlFileName' in argumentHash ):
    fullControlFileName                  = os.path.join( argumentHash['ConfigDirectory'], argumentHash['ControlFileName'] )
    validationUtilities.editTestHashBasedOnControlFile( fullControlFileName, testHash )

if( verbose or printParam ):
    print "%s" % validationUtilities.printHash( argumentHash, "Arguments\n" )
    print "%s" % validationUtilities.printTestHash( testHash, 1 )
    if( printParam ):exit(0)

testResults                              = {}
testNameHash                             = {}

# loop over tests

for fullTestName, testParameterHash in testHash.iteritems():
    if( argumentHash['ShowTests'] and testParameterHash['Active'] != 0 ):
        print "%s %s active=%d" % ( testParameterHash['SystemName'], testParameterHash['TestName'], testParameterHash['Active'] )

    #print "%s %s active=%d" % ( testParameterHash['SystemName'], testParameterHash['TestName'], testParameterHash['Active'] )

    # skip CustomGB tests on Cuda -- not implmented!

    if( testParameterHash['Active'] != 0 and testParameterHash['TestName'].startswith('CustomGbsaForce') and ( comparisonPlatformList[0].startswith('Cuda') or comparisonPlatformList[1].startswith('Cuda') ) ):
        if( verbose ):
            print "Skipping comparison of %s %s test=%s on %s since CustomGbsaForce is not implemented on Cuda" % (comparisonPlatformList[0], comparisonPlatformList[1], testParameterHash['TestName'], testParameterHash['SystemName'])
        testParameterHash['Active'] = 0

    elif( testParameterHash['Active'] > 0 ):

        systemName              = testParameterHash['SystemName']
        testName                = testParameterHash['TestName']
        testNameHash[testName]  = 1

        print '*' * 80
        print "%30s %30s" % (systemName, testName )
    
        # read parameter file.
    
        parameterFileName        = systemName + parameterFileSuffix
        fullParameterFileName    = os.path.join(systemsDirectory, parameterFileName)
        if( useXml ):
            positionFileName         = systemName + '.txt'
            fullPositionFileName     = os.path.join(systemsDirectory, positionFileName)
            systemParameters         = OpenMMSystemParameters(fullParameterFileName, fullPositionFileName, verbose)
        else:
            systemParameters         = ValidationParameterFileParser(fullParameterFileName, verbose)
     
        # loop over tests

        try:

            # get test and run

            print "forceTest %s %s\n" % (systemName, testName )

            if( 'DeviceId' in argumentHash ):
                testParameterHash['DeviceId'] = argumentHash['DeviceId']

            forceTest   = forceEnergyComparisonTestFactory( testName, systemParameters, testParameterHash, verbose )
            print "forceTest %s %s %d\n" % (systemName, testName, forceTest.isActive() )
            if( forceTest is not None and forceTest.isActive() ):

                if( serializeDirectory ):
                    forceTest.serialize( serializeDirectory )

                forceTest.runTest( comparisonPlatformList )
                fullTestName                 = forceTest.getFullTestName()
                if forceTest.getResult() is not None:
                    testResults[fullTestName]    = forceTest.getResult()
                else:
                    print "%s test did not run for %s" % (testName, systemName)
                    numberOfTestsThatDidNotRun      += 1

                if( 'Sleep' in argumentHash and argumentHash['Sleep'] > 0 ):
                    if( verbose ):
                        print "Sleeping %s seconds." % (str(argumentHash['Sleep']))
                        sys.stdout.flush()
                    time.sleep(float(argumentHash['Sleep']))


        except:

            print "%s test did not run for %s" % (testName, systemName)
            print repr(traceback.print_exception( sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))

            numberOfTestsThatDidNotRun      += 1
     
if( argumentHash['ShowTests'] ):
    exit(0)

# output results

print '*' * 80
numberOfTestsThatPassed                  = 0
numberOfTestsThatFailed                  = 0

for testName,result in testResults.iteritems():
    if( result.testPassed( ) ):
        numberOfTestsThatPassed += 1
    else:
        numberOfTestsThatFailed += 1

print "\nSummary:\n"
print "   %d tests passed"       % numberOfTestsThatPassed
print "   %d tests failed"       % numberOfTestsThatFailed
print "   %d tests did not run"  % numberOfTestsThatDidNotRun

# print summary file

try:
    printTestSummary( testSummaryFileName, testNameHash, testResults )
except:
    print repr(traceback.print_exception( sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))

# exit w/ flag signalling success

if numberOfTestsThatFailed > 0 or numberOfTestsThatDidNotRun > 0:
   sys.exit(1)   
else:
   sys.exit(0)
