StepScan PowerScript Code

PowerScript

This code run StepScan in SmartScan

main 0 files
StepScan PowerScript Code..js
StepScan PowerScript Code..js 14461 bytes
var $ = {
    "flag" : {
        "useCantileverFromStepScanParam" : false,
        "isNeedNCMSweep" : true
    },

    "msg" : {
        "moveXY" : __tr("stepScan_run", "Prepare / Moving XY stage to (%1, %2)"),
        "repeat" : __tr("stepScan_run", "[ Repeat #%1 (of total %2) ]"),
        "ncmStart" : __tr("stepScan_run", "Prepare / ncm sweep started"),
        "ncmError" : __tr("stepScan_run", "Prepare / ncm sweep result is not good, change cantilever"),
        "parkingError" : __tr("stepScan_run", "Prepare / parking cantilever was unsuccessful"),
        "ncmDone" : __tr("stepScan_run", "Prepare / ncm sweep done, peak = %1 kHz"),
        "done" :__tr("stepScan_run", "Done"),
        "error" : __tr("stepScan_run", "Error occured : %1")
    },

    "init" : function() {
        // parameter validation
        if (!__methods || !__recipe)
            throw "variable was not set";

        app.setErrorStatusVisible(false);
        app.msg.category = "__autoScan__";
        app.msg.sendCmd("reset+show");
    },

    "finalize" : function() {
        app.msg.sendProgress(this.msg.done, 100, 10 * 1000);
        app.msg.sendCmd("hide.later");
    },

    "startApproach" : function(postWait) {
        var type = "q+s";
        var args = {
            "isFastApproachEnabled" : false
        };
        app.msg.sendProgress('Approach / start');
        spm.approach.start(type, args);
        spm.sleep(postWait);
        app.msg.sendProgress('Approach / done'); // + setpoint and Z Scanner Pos.
    },

    "tryNcmSweep" : function(params) {
        if (!spm.head.isNonContactType)
            return;
        this.flag.isNeedNCMSweep = false;
        var amplitudeFromParam = params.basicParams.params.zservo.setpoint.amplitude;
        var amplitudeRatio = params.basicParams.params.zservo.setpoint.amplitudeRatio;
        var useSetpointPreset = params.basicParams.params.zservo.setpoint.useSetpointPreset;
        var useAmplitudeRatio = params.basicParams.params.zservo.setpoint.useAmplitudeRatio;
        var drive = 10.0;
        var startHz = spm.cantilever.resonanceRange.start * 1000;
        var endHz = spm.cantilever.resonanceRange.end * 1000;
        var amplitude = amplitudeFromParam;
        app.msg.sendProgress(this.msg.ncmStart, 30, 30 * 1000);

        spm.ncm.sweepAuto(amplitude, startHz, endHz, drive);

        var peakHz = spm.ncm.sweepResult.peakFreq;
        var peakKHz = (peakHz / 1000.0).toFixed(1);

        if (peakHz < startHz || peakHz >= endHz)
            throw this.msg.ncmError;

//        if (useSetpointPreset)
//            spm.zservo.setpoint.normValue = params.basicParams.params.zservo.setpoint.normValue;

        if (useAmplitudeRatio) {
            var tryNumber = 0;
            var tryMaximumNumber = 30;

            while (spm.ncm.isRunning && (tryNumber < tryMaximumNumber)) {
                tryNumber = tryNumber + 1;
                spm.sleep(1000);
            }

            app.msg.sendProgress("Prepare / applied amplitude ratio to setpoint");
            spm.sleep(500);
            spm.zservo.setpoint.value = amplitudeFromParam * amplitudeRatio / 100;
        }
        app.msg.sendProgress(__arg(this.msg.ncmDone, peakKHz));
        app.msg.sendProgress(__arg("Prepare / Setpoint: %1 nm", spm.zservo.setpoint.value));
    },

    "getQRInfoOnProbehand" : function() {
        var qrType = spm.fx.probeExchanger.fetchDefaultProbeTypeOnProbehand();
        var isEdited = spm.fx.probeExchanger.isEditedProbeTypeOnProbehand();
        var isNullQR = qrType === "Non_QR" || qrType === "Not_Classified";
        return [isNullQR, isEdited];
    },

    "tryExchangeProbe" : function(method) {
        if (!spm.capability.supportsProbeExchanger){
            this.flag.useCantileverFromStepScanParam = true;
            return false;
        }
        var params = method.params;

        if (!params.basicParams.params.probe.use) {
            this.flag.useCantileverFromStepScanParam= true;
            return false;
        }

        if (spm.fx.probeExchanger.probehandIndex === params.basicParams.params.probe.index) {
            var result = this.getQRInfoOnProbehand();
            var isNullQR = result[0]; isEdited = result[1]
            if (!isNullQR){
                var qrName = spm.fx.probeExchanger.fetchDefaultProbeTypeOnProbehand();
                spm.cantilever.changeTo(qrName)
            } else {

                if (isEdited) {
                    var EditedName = spm.fx.probeExchanger.fetchEditedProbeTypeOnProbehand();
                    spm.cantilever.changeTo(EditedName)

                } else {
                    this.flag.useCantileverFromStepScanParam = true;
                }
            }
            return false;
        }

        if (!spm.fx.probeExchanger.isProbehandEmpty) {
            app.msg.sendProgress("Prepare / Parking into cantilever")
            var isParking = spm.fx.probeExchanger.putback(); // Validation: Always return value is false
            // TODO: Need Revision SmartScan
            // if (!isParking) {
            //     throw this.msg.parkingError
            // }
        }
        app.msg.sendProgress("Prepare / Picking up cantilever")
        spm.fx.probeExchanger.pickupAt(params.basicParams.params.probe.index, false);
        result = this.getQRInfoOnProbehand();
        isNullQR = result[0]; isEdited = result[1];
        if (isNullQR && !isEdited) {
            this.flag.useCantileverFromStepScanParam = true;
        }

        spm.fx.analyzer.autoAlign();
        return true;
    },

    "tryChangeHeadMode" : function(next) {
        var current = __kernel__.findHeadModeId(spm.head.modeName)
        if (current !== next) {
            try {
                spm.head.setMode(next);
                // wait time is not precise
                spm.sleep(200);
                app.msg.sendProgress('Prepare / Changing head mode: '+ next);
            } catch (e) {
                // intended catch
            }
        }
    },

    "applyParametersAfterApproach" : function(method, env) {
        var params = method.params;
        var headMode = method.headMode;

        if (spm.head.isEfm) {
            spm.kpfm.config = params.basicParams.params.biasPage.kpfm;
            app.msg.sendProgress("applied EFM parameter after approach");
            spm.sleep(1000);
        }
    },

    "applyParameters" : function(method, env) {
        var params = method.params;
        var headMode = method.headMode;

        if (typeof method !== "object" || typeof params !== "object")
            throw "internal error, method is invalid";

        // change headmode
        this.tryChangeHeadMode(headMode);

        if (this.flag.useCantileverFromStepScanParam && (spm.cantilever.name !== params.basicParams.params.cantileverName)){
            spm.cantilever.changeTo(params.basicParams.params.cantileverName);
            app.msg.sendProgress("Cantilever changed to " + params.basicParams.params.cantileverName);
            this.flag.useCantileverFromStepScanParam = false
        }

        if (method.scanType === "adaptive") {
            if (!spm.head.isNonContactType) {
                app.alert("Cannot enable adaptive scan other than NCM mode");
                throw "error";
            }
        }

        if (!spm.head.isNonContactType && params.basicParams.params.zservo.setpoint.useSetpointPreset) {
            spm.zservo.setpoint.normValue = params.basicParams.params.zservo.setpoint.normValue;
            spm.zservo.setpoint.useSetpointPreset = params.basicParams.params.zservo.setpoint.useSetpointPreset;
        }

        if (spm.head.isNonContactType) {
            if (this.flag.isNeedNCMSweep) {
                this.tryNcmSweep(params);
            } else {
                app.msg.sendProgress("Prepare / skipping ncm sweep", 50, 10 * 1000);
            }

            if (params.basicParams.params.zservo.setpoint.useAmplitudeRatio) {
                spm.zservo.setpoint.value = spm.ncm.sweepResult["peakAmp"] * params.basicParams.params.zservo.setpoint.amplitudeRatio / 100;
            }

            if (!params.basicParams.params.zservo.setpoint.useAmplitudeRatio) {
                spm.zservo.setpoint.value = spm.ncm.sweepResult["peakAmp"] * 0.74;
            }
        }

        spm.zservo.gain = params.basicParams.params.zservo.gain;
//        spm.bias.tip = params.basicParams.params.biasPage.tipBias;
//        spm.bias.sample = params.basicParams.params.biasPage.sampleBias;
        spm.bias.setBiasConfig(params.basicParams.params.biasPage);
        spm.scan.rate = params.basicParams.params.rate;
        spm.scan.quickStep = params.scanTypeParams.quickStep;
        spm.scan.adaptiveLinewise = params.scanTypeParams.adaptive;
        spm.scan.type = method.scanType;
        spm.scan.options = params.optionParams.scanParamOptions;
        spm.scan.channels.all = params.basicParams.params.channels;
        spm.scan.setScanGeometry(params.basicParams.params.geometry);
        spm.scan.liftMode = params.basicParams.params.liftMode;

        if (spm.head.isEfm) {
            var kpfmConfig = spm.kpfm.config;
            if (kpfmConfig.isServoOn)
                kpfmConfig.isServoOn = false;
                spm.kpfm.config = kpfmConfig;
                app.msg.sendProgress("Prepare / tip bias servo off before approach");
                spm.sleep(1000);

            spm.lockin2.detector.config = params.basicParams.params.lockinAmp.detector2;
            spm.sleep(200);
            spm.lockin2.modulator.config = params.basicParams.params.lockinAmp.modulator2;
            spm.sleep(200);

            spm.lockin3.detector.config = params.basicParams.params.lockinAmp.detector3;
            spm.sleep(200);
            spm.lockin3.modulator.config = params.basicParams.params.lockinAmp.modulator3;
            spm.sleep(200);
        }

        if (spm.head.isCurrentAmpRelated) {
            spm.currentamp.config = params.basicParams.params.currentAmp;
            spm.sleep(200);
        }

    },

    "preparePoint" : function(lift) {
        try {
            spm.scan.stop();
            app.msg.sendProgress(__arg("Prepare / Lifting Z stage %1 um",lift));
            spm.zstage.move(lift, 1.0);
        } catch (e) {
        }
    },

    "run" : function() {
        var env = __recipe.env;
        var items = __recipe.items;

        var itemCount = items.length;
        var repeatCount = env.repeatCount;
        var totalIteration = repeatCount * itemCount;
        if (env.ncmSweep === "none") {
            this.flag.isNeedNCMSweep = true // specified for safety reasons.
        }

        for (var repeat = 0; repeat < repeatCount; repeat += 1)
        {
            if (repeatCount > 1) {
                app.msg.textPrefix = "";
                app.msg.sendProgress(__arg(this.msg.repeat, (repeat + 1), repeatCount));
            }

            app.msg.textPrefix = __arg("%1-- : ", repeat + 1);

            if (env.ncmSweep === "perRepeat" && !__isTestRun) {
                var firstMethodName = items[0].method;
                var firstMethod = __methods[firstMethodName];
                var params = firstMethod.params;

                if (typeof firstMethod !== "object" || typeof params !== "object")
                    throw "internal error, method is invalid";

                this.flag.isNeedNCMSweep = true;

            }

            for (var i = 0; i < itemCount; i += 1)
            {
                var pos = items[i].pos;
                var methodName = items[i].method;
                var method = __methods[methodName];

                if (typeof pos == "undefined" ||
                        typeof methodName == "undefined" ||
                        typeof method == "undefined")
                    continue;

                app.msg.sendCmd("reset+show");

                var exchanged = this.tryExchangeProbe(method);

                // preparing
                app.msg.textPrefix = __arg("[ Repeat(%1/%2) Recipe(%3/%4: %5) ]: ",repeat+1, repeatCount, i + 1, itemCount, methodName);
                this.preparePoint(env.liftHeight);

                // xy positioning
                app.msg.sendProgress(__arg(this.msg.moveXY, pos.x, pos.y), 50, 10 * 1000);
                spm.xystage.moveTo(pos.x, pos.y, 0.8, 0.8);


                if ((env.ncmSweep === "perPoint" && !__isTestRun) || exchanged)
                    this.flag.isNeedNCMSweep = true;

                // set parameters and approach with ncm sweep when needed
                this.applyParameters(method, env);

                var context = {
                    "reason" : "batch.stepScan",
                    "params" : {
                        "x" : pos.x,
                        "y" : pos.y,
                        "method" : methodName,
                        "note" : items[i].note,
                        "repeatIndex" : repeat,
                        "repeatCount" : repeatCount
                    }
                };

                if (__isTestRun) {
                    app.msg.sendProgress("(test run / skipping approach)");
                    app.msg.sendProgress("(test run / waiting a little instead of imaging)");
                    spm.sleep(5000);
                } else {
                    this.startApproach(env.postApproachWait);
                    this.applyParametersAfterApproach(method, env);
                    spm.scan.context = context;
                    app.msg.sendProgress("Scan / start");
                    spm.scan.startImageScan();
                    app.msg.sendProgress("Scan / done"); // + time information

                }
                app.msg.textPrefix = "";
                var ProgressPercent = 100 * (repeat * itemCount + i + 1) / totalIteration
                app.msg.sendProgress(__arg("[Progress %1% (#%2 of total %3)]",ProgressPercent.toFixed(0) ,repeat * itemCount + i + 1, totalIteration));

            }
        }
    }
}

// main flow
try {
    $.init();
    $.run();
    $.finalize();
}
catch (e) {
    app.msg.sendProgress(__arg($.msg.error, e), 0);
    throw e;
}
Comments (0)

No comments yet. Be the first to comment!

Snippet Information
Author: admin_alex
Language: PowerScript
Created: Oct 22, 2025
Updated: 0 minutes ago
Views: 54
Stars: 1