class PythonStandaloneApplication(object):
    def __init__(self):
        EnsureModule('{EA433010-2BAC-43C4-857C-7AEAC4A8CCE0}', 0, 1, 0)
        EnsureModule('{F66684D7-AAFE-4A62-9156-FF7A7853F764}', 0, 1, 0)

        self.TheConnection = EnsureDispatch("ZOSAPI.ZOSAPI_Connection")

        print(self.TheConnection)

        self.TheApplication = self.TheConnection.CreateNewApplication()

        print(self.TheApplication)

        self.TheSystem = self.TheApplication.PrimarySystem

        print(self.TheSystem)

    def __del__(self):
        if self.TheApplication is not None:
            self.TheApplication.CloseApplication()
            self.TheApplication = None
        self.TheConnection = None
Example #2
0
class PythonStandaloneApplication(object):
    class LicenseException(Exception):
        pass

    class ConnectionException(Exception):
        pass

    class InitializationException(Exception):
        pass

    class SystemNotPresentException(Exception):
        pass

    def __init__(self):
        # make sure the Python wrappers are available for the COM client and
        # interfaces
        EnsureModule('ZOSAPI_Interfaces', 0, 1, 0)
        # Note - the above can also be accomplished using 'makepy.py' in the
        # following directory:
        #      {PythonEnv}\Lib\site-packages\wind32com\client\
        # Also note that the generate wrappers do not get refreshed when the
        # COM library changes.
        # To refresh the wrappers, you can manually delete everything in the
        # cache directory:
        #	   {PythonEnv}\Lib\site-packages\win32com\gen_py\*.*

        self.TheConnection = EnsureDispatch("ZOSAPI.ZOSAPI_Connection")
        if self.TheConnection is None:
            raise PythonStandaloneApplication.ConnectionException(
                "Unable to intialize COM connection to ZOSAPI")

        self.TheApplication = self.TheConnection.CreateNewApplication()
        if self.TheApplication is None:
            raise PythonStandaloneApplication.InitializationException(
                "Unable to acquire ZOSAPI application")

        if self.TheApplication.IsValidLicenseForAPI == False:
            raise PythonStandaloneApplication.LicenseException(
                "License is not valid for ZOSAPI use")

        self.TheSystem = self.TheApplication.PrimarySystem
        if self.TheSystem is None:
            raise PythonStandaloneApplication.SystemNotPresentException(
                "Unable to acquire Primary system")

    def __del__(self):
        if self.TheApplication is not None:
            self.TheApplication.CloseApplication()
            self.TheApplication = None

        self.TheConnection = None

    def OpenFile(self, filepath, saveIfNeeded):
        if self.TheSystem is None:
            raise PythonStandaloneApplication.SystemNotPresentException(
                "Unable to acquire Primary system")
        self.TheSystem.LoadFile(filepath, saveIfNeeded)

    def CloseFile(self, save):
        if self.TheSystem is None:
            raise PythonStandaloneApplication.SystemNotPresentException(
                "Unable to acquire Primary system")
        self.TheSystem.Close(save)

    def SamplesDir(self):
        if self.TheApplication is None:
            raise PythonStandaloneApplication.InitializationException(
                "Unable to acquire ZOSAPI application")

        return self.TheApplication.SamplesDir

    def ExampleConstants(self):
        if self.TheApplication.LicenseStatus is constants.LicenseStatusType_PremiumEdition:
            return "Premium"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_ProfessionalEdition:
            return "Professional"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_StandardEdition:
            return "Standard"
        else:
            return "Invalid"
Example #3
0
class MisAlignmentGenerator(object):
    class LicenseException(Exception):
        pass

    class ConnectionException(Exception):
        pass

    class InitializationException(Exception):
        pass

    class SystemNotPresentException(Exception):
        pass

    def __init__(self):
        # make sure the Python wrappers are available for the COM client and
        # interfaces
        EnsureModule('ZOSAPI_Interfaces', 0, 1, 0)
        # Note - the above can also be accomplished using 'makepy.py' in the
        # following directory:
        #      {PythonEnv}\Lib\site-packages\wind32com\client\
        # Also note that the generate wrappers do not get refreshed when the
        # COM library changes.
        # To refresh the wrappers, you can manually delete everything in the
        # cache directory:
        #	   {PythonEnv}\Lib\site-packages\win32com\gen_py\*.*
        
        self.TheConnection = EnsureDispatch("ZOSAPI.ZOSAPI_Connection")
        if self.TheConnection is None:
            raise MisAlignmentGenerator.ConnectionException("Unable to intialize COM connection to ZOSAPI")

        self.TheApplication = self.TheConnection.CreateNewApplication()
        if self.TheApplication is None:
            raise MisAlignmentGenerator.InitializationException("Unable to acquire ZOSAPI application")

        if self.TheApplication.IsValidLicenseForAPI == False:
            raise MisAlignmentGenerator.LicenseException("License is not valid for ZOSAPI use")

        self.TheSystem = self.TheApplication.PrimarySystem
        if self.TheSystem is None:
            raise MisAlignmentGenerator.SystemNotPresentException("Unable to acquire Primary system")

    def __del__(self):
        """Boiler plate"""
        if self.TheApplication is not None:
            self.TheApplication.CloseApplication()
            self.TheApplication = None

        self.TheConnection = None

    def OpenFile(self, filepath, saveIfNeeded):
        """Boiler plate"""
        if self.TheSystem is None:
            raise MisAlignmentGenerator.SystemNotPresentException("Unable to acquire Primary system")
        self.TheSystem.LoadFile(filepath, saveIfNeeded)

    def CloseFile(self, save):
        """Boiler plate"""
        if self.TheSystem is None:
            raise MisAlignmentGenerator.SystemNotPresentException("Unable to acquire Primary system")
        self.TheSystem.Close(save)

    def SamplesDir(self):
        """Boiler plate"""
        if self.TheApplication is None:
            raise MisAlignmentGenerator.InitializationException("Unable to acquire ZOSAPI application")

        return self.TheApplication.SamplesDir

    def ExampleConstants(self):
        """Boiler plate"""
        if self.TheApplication.LicenseStatus is constants.LicenseStatusType_PremiumEdition:
            return "Premium"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_ProfessionalEdition:
            return "Professional"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_StandardEdition:
            return "Standard"
        else:
            return "Invalid"

    def SpecialGauss(self,mean, sigma):
        """ A gaussian distribution whith the tails clipped at 2 sigma."""
        rand = 10.0 * sigma
        while abs(rand) > 2.0 * sigma:
            rand = random.gauss(0,sigma)
        return(rand + mean)
    
    def RemoveAllMtfRows(self):
        """Remove all the oparands in the merit function editor"""
        mfe = self.TheSystem.MFE
        nRows = mfe.NumberOfOperands
        dmfsrow = -1
        CastTo(mfe,'IEditor').DeleteRowsAt(0, nRows)

    def AddREAOp(self, surf, missCenter, missPupilX, missPupilY, REAXp):
        """
        Add operand of type REAX or REAY to MFE. This means how much the (almost)chief ray is going to miss the vertex of the surface.
surf is the surface that we are aiming for
missCenter is the amount we miss the center of the surface by.
missPupilX and missPupilY is how much we miss the center of the aperture by.
REAXp is true if we are aiming in x, false if we are aiming in y
        """     
        mfe = self.TheSystem.MFE
        op = mfe.AddOperand()
        if REAXp:
            op.ChangeType(constants.MeritOperandType_REAX)
        else:   
            op.ChangeType(constants.MeritOperandType_REAY)
        p1 = op.GetOperandCell(constants.MeritColumn_Param1)
        p1.IntegerValue = surf
        p3 = op.GetOperandCell(constants.MeritColumn_Param3)
        p3.DoubleValue = 0.0
        p4 = op.GetOperandCell(constants.MeritColumn_Param4)
        p4.DoubleValue = 0.0
        p5 = op.GetOperandCell(constants.MeritColumn_Param5)
        p5.DoubleValue = missPupilX
        p6 = op.GetOperandCell(constants.MeritColumn_Param6)
        p6.DoubleValue = missPupilY
        op.Target = missCenter
        wt = op.GetOperandCell(constants.MeritColumn_Weight)
        wt.DoubleValue = 1.0
        
    def AddREAOperands(self, surface, missx, missy, pupilx, pupily):
        """
        Add MF operands
        """
        self.AddREAOp(surface, missx, pupilx, pupily, True)
        self.AddREAOp(surface, missy, pupilx, pupily, False)

    def SurfaceDisplacement(self, surface, missx, missy):
        """ Displace the mirror vertex randomly """
        lde = self.TheSystem.LDE
        row = CastTo(lde,'IEditor').GetRowAt(surface - 1)
        colx = CastTo(row,'ILDERow').GetSurfaceCell(constants.SurfaceColumn_Par1);
        colx.DoubleValue = missx;
        coly = CastTo(row,'ILDERow').GetSurfaceCell(constants.SurfaceColumn_Par2);
        coly.DoubleValue = missy;

    def ThicknessRandomizer(self, sigma):
        """ All planes with a thickness different from 0 gets moved around a little"""
        lde = self.TheSystem.LDE
        nSurf = lde.NumberOfSurfaces
        for n in range(0,nSurf):
            surf = lde.GetSurfaceAt(n)
            thickness = surf.Thickness
            if thickness != 0:
                surf.Thickness = self.SpecialGauss(thickness, sigma)
        
    def LocalOptimize(self, target):
        """
        Start local optimization, keep tunning until MF is below target, local optimization converges, 
        or 500 minutes has passed.
        """
        lopt = self.TheSystem.Tools.OpenLocalOptimization()
        lopt.Algorithm = constants.OptimizationAlgorithm_DampedLeastSquares
        lopt.Cycles = constants.OptimizationCycles_Infinite
        lopt.NumberOfCores = 8
        print("Starting local optimization")    
        CastTo(lopt, "ISystemTool").Run()
        mf = lopt.InitialMeritFunction
        counter = 0
        print("Starting loop, mf = " + str(mf))
        while mf > target:
            time.sleep(6)
            mf = lopt.CurrentMeritFunction
            print("mf = " + str(mf))
            counter = counter + 1
            if( counter > 10): break
        CastTo(lopt, "ISystemTool").Cancel()
        CastTo(lopt, "ISystemTool").Close()
        return(mf)

    def ListMirrorPlanes(self):
        """ Get a list containing the indexes of mirror surfaces """
        lde = self.TheSystem.LDE
        nSurf = lde.NumberOfSurfaces
        surfList = []
        for n in range(0,nSurf):
            surf = lde.GetSurfaceAt(n)
            if surf.Material == 'MIRROR':
                surfList.append(n)
        return(surfList)

    def createPickupsAndSetOrder(self, indexFrom, indexTo):
        """ Create picups with scale factor -1 for decenters and tilts. Set order to 1"""
        lde = self.TheSystem.LDE
        surf2 = lde.GetSurfaceAt(indexTo)
        for cellIndex in [12,13,14,15]:
            cell2 = CastTo(surf2, "IEditorRow").GetCellAt(cellIndex)
            pickup = cell2.CreateSolveType(constants.SolveType_SurfacePickup)._S_SurfacePickup
            pickup.ScaleFactor = -1.0
            pickup.Surface = indexFrom
            cell2.SetSolveData(pickup)
        ocol = CastTo(surf2,'ILDERow').GetSurfaceCell(constants.SurfaceColumn_Par6)
        ocol.IntegerValue = 1
        

    def CBify(self, index, variablep):
        """ Make surface a CG, make tilts variable """
        surf = self.TheSystem.LDE.GetSurfaceAt(index)
        setting = surf.GetSurfaceTypeSettings(constants.SurfaceType_CoordinateBreak)
        surf.ChangeType(setting)
        if(variablep):
            CastTo(surf,'IEditorRow').GetCellAt(14).MakeSolveVariable()
            CastTo(surf,'IEditorRow').GetCellAt(15).MakeSolveVariable()            

    def AddCoordinateBreaks(self):
        """ Add coordinate break surfaces to the LDE, set variables and pickups """ 
        mList = self.ListMirrorPlanes()
        lde = self.TheSystem.LDE
        for index in mList[::-1]:
            lde.InsertNewSurfaceAt(index+1)
            self.CBify(index+1, False)
            lde.InsertNewSurfaceAt(index)
            self.CBify(index, True)
            self.createPickupsAndSetOrder(index,index+2)

    def RemoveAllVariables(self):
        """ Remove all the variables """
        rv = self.TheSystem.Tools.RemoveAllVariables()

       
    def MisalignSystem(self, t1, t2, t3):
        """ Misalign the system
    T1 is the s.t.d. of decentering of the mirror
    T2 is the s.t.d. of how much the laser misses the center of the mirror
    T3 is the s.t.d. of the thickness

    The vertex is displaced by t1. The chief ray should miss by t2.
    Final plane is missed by t1 + t2, since there is no vertex displacement, only decenter and
    """
        self.ThicknessRandomizer(t3)
        
        stopSurf = self.TheSystem.LDE.StopSurface
        stopRad = self.TheSystem.LDE.GetSurfaceAt(stopSurf).SemiDiameter
        lastSurf = self.TheSystem.LDE.NumberOfSurfaces - 1
        px = self.SpecialGauss(0,t2)/stopRad
        py = self.SpecialGauss(0,t2)/stopRad

        mList = self.ListMirrorPlanes()
        mList.append(lastSurf)
        for surf in mList:
            x1 = self.SpecialGauss(0,t1)
            y1 = self.SpecialGauss(0,t1)
            x2 = self.SpecialGauss(0,t2)
            y2 = self.SpecialGauss(0,t2)
             
            if not surf == lastSurf:
                self.SurfaceDisplacement(surf, x1, y1)

            if surf == lastSurf:
                self.AddREAOperands(surf, x1 + x2, y1 + y2, px, py)
            elif not surf == stopSurf:
                self.AddREAOperands(surf, x2, y2, px, py)
            
        self.LocalOptimize(0.00000001)        
class PlotCentralFieldMTF(object):
    class LicenseException(Exception):
        pass

    class ConnectionException(Exception):
        pass

    class InitializationException(Exception):
        pass

    class SystemNotPresentException(Exception):
        pass

    def __init__(self):
        # make sure the Python wrappers are available for the COM client and
        # interfaces
        EnsureModule('ZOSAPI_Interfaces', 0, 1, 0)
        # Note - the above can also be accomplished using 'makepy.py' in the
        # following directory:
        #      {PythonEnv}\Lib\site-packages\wind32com\client\
        # Also note that the generate wrappers do not get refreshed when the
        # COM library changes.
        # To refresh the wrappers, you can manually delete everything in the
        # cache directory:
        #	   {PythonEnv}\Lib\site-packages\win32com\gen_py\*.*

        self.TheConnection = EnsureDispatch("ZOSAPI.ZOSAPI_Connection")
        if self.TheConnection is None:
            raise PlotCentralFieldMTF.ConnectionException(
                "Unable to intialize COM connection to ZOSAPI")

        self.TheApplication = self.TheConnection.CreateNewApplication()
        if self.TheApplication is None:
            raise PlotCentralFieldMTF.InitializationException(
                "Unable to acquire ZOSAPI application")

        if self.TheApplication.IsValidLicenseForAPI == False:
            raise PlotCentralFieldMTF.LicenseException(
                "License is not valid for ZOSAPI use")

        self.TheSystem = self.TheApplication.PrimarySystem
        if self.TheSystem is None:
            raise PlotCentralFieldMTF.SystemNotPresentException(
                "Unable to acquire Primary system")

    def __del__(self):
        if self.TheApplication is not None:
            self.TheApplication.CloseApplication()
            self.TheApplication = None

        self.TheConnection = None

    def OpenFile(self, filepath, saveIfNeeded):
        if self.TheSystem is None:
            raise PlotCentralFieldMTF.SystemNotPresentException(
                "Unable to acquire Primary system")
        self.TheSystem.LoadFile(filepath, saveIfNeeded)

    def CloseFile(self, save):
        if self.TheSystem is None:
            raise PlotCentralFieldMTF.SystemNotPresentException(
                "Unable to acquire Primary system")
        self.TheSystem.Close(save)

    def SamplesDir(self):
        if self.TheApplication is None:
            raise PlotCentralFieldMTF.InitializationException(
                "Unable to acquire ZOSAPI application")

        return self.TheApplication.SamplesDir

    def ExampleConstants(self):
        if self.TheApplication.LicenseStatus is constants.LicenseStatusType_PremiumEdition:
            return "Premium"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_ProfessionalEdition:
            return "Professional"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_StandardEdition:
            return "Standard"
        else:
            return "Invalid"

    def RemoveExtremeFields(self):
        """Remove field points 6,7,8,9 and 1. """
        field = self.TheSystem.SystemData.Fields
        for x in range(9, 5, -1):
            field.RemoveField(x)
        field.RemoveField(1)

    def CheckLimits(self, xdata, ydata, index, histos):
        resolution = 20.0
        for i in range(xdata.Length):
            if ydata.Data[i][index] < 0.25:
                lim = xdata.Data[i]
                resolution = xdata.Data[i]
                break
        histos.resolutions.append(20)
        return (resolution)

    def CornerCounter(self, res, index, h5, h75, h10):
        if res > 5.0:
            h5[index] = 1 + h5[index]
        if res > 7.5:
            h75[index] = 1 + h75[index]
        if res > 10.0:
            h10[index] = 1 + h10[index]

    def PlotMtfAllConfigs(self, bname, histos):
        """Loop over all configs in MCE, and plot the MTF for all active fields"""
        mce = self.TheSystem.MCE
        mcs = mce.NumberOfConfigurations
        #Loop over all configs
        for mc in range(mcs):
            mce.SetCurrentConfiguration(mc + 1)

            #Plot MTF
            gmtf = self.TheSystem.Analyses.New_GeometricMtf()
            settings = CastTo(gmtf.GetSettings(), 'IAS_GeometricMtf')
            #settings.ShowDiffractionLimit()
            settings.MaximumFrequency = 20.0
            gmtf.ApplyAndWaitForCompletion()
            #gmtf.ToFile('m:\\gmtf.txt')
            results = gmtf.GetResults()

            fig, ax = plt.subplots(1, 1, figsize=(8, 6))
            res5 = [0, 0, 0]
            res75 = [0, 0, 0]
            res10 = [0, 0, 0]

            #Loop over results.
            for i in range(results.NumberOfDataSeries):
                ds = results.GetDataSeries(i)
                plt.plot(ds.XData.Data, ds.YData.Data)
                resT = self.CheckLimits(ds.XData, ds.YData, 0,
                                        histos)  #Tangential (or opposite)
                resS = self.CheckLimits(ds.XData, ds.YData, 1,
                                        histos)  #Sagittal(or opposite)
                self.CornerCounter(resT, 0, res5, res75, res10)
                self.CornerCounter(resS, 1, res5, res75, res10)
                self.CornerCounter((resT + resS) / 2.0, 2, res5, res75, res10)

            histos.FillCounterHisto(histos.histos5, res5)
            histos.FillCounterHisto(histos.histos75, res75)
            histos.FillCounterHisto(histos.histos10, res10)
            plt.grid()
            fig.savefig('c:\\Users\\haavagj\\plots\\' + bname + str(mc) +
                        '.png')
            plt.close(fig)
class MtfMFGenerator(object):
    class LicenseException(Exception):
        pass

    class ConnectionException(Exception):
        pass

    class InitializationException(Exception):
        pass

    class SystemNotPresentException(Exception):
        pass

    def __init__(self):
        # make sure the Python wrappers are available for the COM client and
        # interfaces
        EnsureModule('ZOSAPI_Interfaces', 0, 1, 0)
        # Note - the above can also be accomplished using 'makepy.py' in the
        # following directory:
        #      {PythonEnv}\Lib\site-packages\wind32com\client\
        # Also note that the generate wrappers do not get refreshed when the
        # COM library changes.
        # To refresh the wrappers, you can manually delete everything in the
        # cache directory:
        #	   {PythonEnv}\Lib\site-packages\win32com\gen_py\*.*
        
        self.TheConnection = EnsureDispatch("ZOSAPI.ZOSAPI_Connection")
        if self.TheConnection is None:
            raise MtfMFGenerator.ConnectionException("Unable to intialize COM connection to ZOSAPI")

        self.TheApplication = self.TheConnection.CreateNewApplication()
        if self.TheApplication is None:
            raise MtfMFGenerator.InitializationException("Unable to acquire ZOSAPI application")

        if self.TheApplication.IsValidLicenseForAPI == False:
            raise MtfMFGenerator.LicenseException("License is not valid for ZOSAPI use")

        self.TheSystem = self.TheApplication.PrimarySystem
        if self.TheSystem is None:
            raise MtfMFGenerator.SystemNotPresentException("Unable to acquire Primary system")

    def __del__(self):
        """Boiler plate"""
        if self.TheApplication is not None:
            self.TheApplication.CloseApplication()
            self.TheApplication = None

        self.TheConnection = None

    def OpenFile(self, filepath, saveIfNeeded):
        """Boiler plate"""
        if self.TheSystem is None:
            raise MtfMFGenerator.SystemNotPresentException("Unable to acquire Primary system")
        self.TheSystem.LoadFile(filepath, saveIfNeeded)

    def CloseFile(self, save):
        """Boiler plate"""
        if self.TheSystem is None:
            raise MtfMFGenerator.SystemNotPresentException("Unable to acquire Primary system")
        self.TheSystem.Close(save)

    def SamplesDir(self):
        """Boiler plate"""
        if self.TheApplication is None:
            raise MtfMFGenerator.InitializationException("Unable to acquire ZOSAPI application")

        return self.TheApplication.SamplesDir

    def ExampleConstants(self):
        """Boiler plate"""
        if self.TheApplication.LicenseStatus is constants.LicenseStatusType_PremiumEdition:
            return "Premium"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_ProfessionalEdition:
            return "Professional"
        elif self.TheApplication.LicenseStatus is constants.LicenseStatusType_StandardEdition:
            return "Standard"
        else:
            return "Invalid"

    def RemoveAllAfterDMFS(self):
        """Remove all the oparands after the first DMFS in the merit function editor"""
        mfe = self.TheSystem.MFE
        nRows = mfe.NumberOfOperands
        dmfsrow = -1
        for r in range(nRows):
            row = mfe.GetOperandAt(r)
            if(row.Type == constants.MeritOperandType_DMFS):
                dmfsrow = r
                break
        if(dmfsrow > 0):
            CastTo(mfe,'IEditor').DeleteRowsAt(dmfsrow, nRows - dmfsrow)

    def AddMTFOPGT(self, field, freq, target,type):
        """
        Add operand of type type (GMTS or GMTT) for field and freq. 
        Then add operant OPGT requiring the previous operand to be larger than target
        """
        mfe = self.TheSystem.MFE
        mtf = mfe.AddOperand()
        mtf.ChangeType(type)
        p1 = mtf.GetOperandCell(constants.MeritColumn_Param1)
        p1.IntegerValue = 2
        p3 = mtf.GetOperandCell(constants.MeritColumn_Param3)
        p3.IntegerValue = field + 1
        p4 = mtf.GetOperandCell(constants.MeritColumn_Param4)
        p4.DoubleValue = freq
        p6 = mtf.GetOperandCell(constants.MeritColumn_Param6)
        p6.IntegerValue = 1
        
        opgt = mfe.AddOperand()
        opgt.ChangeType(constants.MeritOperandType_OPGT)
        opgt.Target = target
        wc = opgt.GetOperandCell(constants.MeritColumn_Weight)
        wc.DoubleValue = 1.0
        p1 = opgt.GetOperandCell(constants.MeritColumn_Param1)
        p1.IntegerValue = CastTo(mtf,'IEditorRow').RowIndex + 1
        
    def OptimizeMTFGreaterThan(self, nFields, freq, target):
        """
        Create MF to optimize on MTF for the nFields first field points, trying to make it greater than target at freq. 
        Operands will be added to the end of the merit function.
        """
        mce = self.TheSystem.MCE
        mcs = mce.NumberOfConfigurations
        for mc in range(mcs):
            mfe = self.TheSystem.MFE
            cnf = mfe.AddOperand()
            cnf.ChangeType(constants.MeritOperandType_CONF)
            cnf.GetOperandCell(constants.MeritColumn_Param1).IntegerValue = mc + 1
            for f in range(nFields):
                self.AddMTFOPGT(f, freq, target, constants.MeritOperandType_GMTS)
                self.AddMTFOPGT(f, freq, target, constants.MeritOperandType_GMTT)

    def LocalOptimizeMTF(self, target):
        """
        Start local optimization, keep tunning until MF is below target, local optimization converges, 
        or 500 minutes has passed.
        """
        lopt = self.TheSystem.Tools.OpenLocalOptimization()
        lopt.Algorithm = constants.OptimizationAlgorithm_DampedLeastSquares
        lopt.Cycles = constants.OptimizationCycles_Infinite
        lopt.NumberOfCores = 8
        print("Starting local optimization")    
        CastTo(lopt, "ISystemTool").Run()
        mf = lopt.InitialMeritFunction
        counter = 0
        dcount = 0
        print("Starting loop, mf = " + str(mf))
        while mf > target:
            time.sleep(60)
            if (lopt.CurrentMeritFunction < mf):
                dcount = 0

            if dcount > 0: print("dcount is " + str(dcount))    
            mf = lopt.CurrentMeritFunction
            print("mf = " + str(mf))
            counter = counter + 1
            dcount = dcount + 1
            if( counter > 500): break
            if( dcount > 5): break
        CastTo(lopt, "ISystemTool").Cancel()
        CastTo(lopt, "ISystemTool").Close()
        return(mf)

    def HammerOptimize(self, target):
        """
        Start hammer optimization. Keep running until MF is below target, printing current MF every 10 minutes.
        """

        hopt = self.TheSystem.Tools.OpenHammerOptimization()
        hopt.Algorithm = constants.OptimizationAlgorithm_DampedLeastSquares
        hopt.NumberOfCores = 8
        print("Starting hammer optimization")    
        CastTo(hopt, "ISystemTool").Run()
        mf = hopt.InitialMeritFunction
        print("Starting loop, mf = " + str(mf))
        iter = 0
        while mf > target:
            time.sleep(600)
            mf = hopt.CurrentMeritFunction
            print("Time " + str(iter))
            print("mf = " + str(mf))
            iter = iter + 1
        CastTo(hopt, "ISystemTool").Cancel()
        CastTo(hopt, "ISystemTool").Close()
        return(mf)