www.gusucode.com > mbctools 工具箱 matlab 源码程序 > mbctools/+tpsetup/ModelData.m

    classdef ModelData < handle
    %ModelData Data model for test plan setup
    
    %  Copyright 2014-2016 The MathWorks, Inc. and Ford Global Technologies, Inc.
    
    properties (Constant)
        %TypeList types of test plans
        TypeList = {'One-Stage','Two-Stage','Point-by-Point'}
        %Icon large icon for JList
        Icon = 'testplan.bmp';
    end
    
    properties
        %BuiltIn builtin test plan templates
        BuiltIn = {};
        %BuiltInNames names for builtin test plan templates
        BuiltInNames = {};
        %CurrentTestplans test plans in current MBCMODEL project
        CurrentTestplans = {}
        %CurrentNames names of test plans in current MBCMODEL project
        CurrentNames = {};
        %UserTemplateFiles test plan template files
        UserTemplateFiles = {};
        %UserTemplateNames names of test plan templates
        UserTemplateNames = {};
        %Boundary fit boundary model
        Boundary= true;
        %FinalTestplan final test plan to build
        FinalTestplan
        %ValidationPercent percentage of fitting data to use for validation
        ValidationPercent = 20;
        %ValidationData validation data set pointer
        ValidationData = xregpointer;
    end
    
    properties (AbortSet,SetObservable)
        %type of validation data 
        ValidationType = 'none';
        %SelectedIndex index to selected testplan
        SelectedIndex = 0;
        %InputsOK inputs defined for all stages
        InputsOK = true;
    end
    

    properties
        %Project MBC Model project pointer
        Project
        %OpenDataEditor
        OpenDataEditor = false;
        %UseDataRange = true;
        UseDataRange = true;
        %Dir template directory
        Dir
        FilterDatasets = true;
    end
    
    properties (Dependent,AbortSet,SetObservable)
        %pData pointer selected data set
        pData = xregpointer; 
        %Selected selected test plan (mdevtestplan)
        Selected        
    end
    
    properties (Access=private)
        %pDataStorage private storage for dependent property pData
        pDataStorage = xregpointer;
        %SelectedStorage private storage for dependent property Selected
        SelectedStorage
    end
    
    properties(Dependent)
        %TypeIndex index to current test plan type (1=One-Stage, 2=Two-stage, 3=Point-by-point)
        TypeIndex
        %pDataList list of data sets
        pDataList
        %index to 
        pDataIndex
        %list of validation data sets
        pValidationSets
    end
    
    methods
        function obj = ModelData(pProject,pData,FilterDatasets)
        %ModelData constructor
        
        obj.Project = pProject;
        obj.Dir = mbcGetPath('mbcmodel', 'Designs');
        addBuiltinTemplates(obj)
        
        if nargin>2
            obj.FilterDatasets = FilterDatasets;
        end
        if nargin>1
            obj.pData = pData;
        end
        addUserTemplates(obj);
        addCurrentTestplans( obj );
        selectTestplan(obj,1);
        
        end
        
        function TypeIndex = get.TypeIndex(obj)
        TypeIndex = find(strcmpi(type(obj.Selected),obj.TypeList));
        
        end
        
        function dp = get.pDataList(obj)
        dp = obj.Project.dataptrs;
        nf = nfactors( HSModel(designdev(obj.Selected) ));
        Valid= false(size(dp));
        for i=1:length(dp)
            % dataset must have more than nf variables
            Valid(i)= dp(i).size(2) >= nf && dp(i).size(1)>0;
        end
        dp   = dp(Valid);
        
        end
        
        function set.pData(obj,pData)
        if isempty(obj.Selected) || ismember(pData,obj.pDataList)
            % data set selected and in project list
            obj.pDataStorage = pData;
            
            addUserTemplates(obj);
            addCurrentTestplans( obj )
        end
        end
        function pData = get.pData(obj)
        
        pData = obj.pDataStorage;
        end        
        
        function set.Selected(obj,T)
        
        obj.SelectedStorage = T;
        dlist = obj.pDataList;
        if obj.FilterDatasets && ~any(obj.pData==dlist)
            if isempty(dlist)
                % select first valid data set
                % deselect data set
                obj.pData = xregpointer;
            else
                obj.pData = dlist(1);
            end
        end
        end
        
        function s = get.Selected(obj)
        s = obj.SelectedStorage;
        end
        
        function Index = get.pDataIndex(obj)
        
        Index = find(obj.pData==obj.pDataList);
        end
        
        function OK = hasData(obj)
        OK = ~isnull(obj.pData);
        end
        
        function addBuiltinTemplates(obj)
        %addBuiltinTemplates builtin test plan templates
        
        % load templates and populate the listbox
        % builtin
        templates=[];
        load('tpbuiltintemps.mat');
        % user
        obj.BuiltIn= templates;
        for i=1:length(obj.BuiltIn)
            obj.BuiltInNames{i} = name( templates{i} );
        end
        end
        
        function addUserTemplates( obj,Dir )
        %addUserTemplates add user defined templates to the listctrl
        
        if nargin>1
            obj.Dir = Dir;
        end
        userfiles= dir(fullfile(obj.Dir, '*.MBT'));
        mbtnames = cell(1,length(userfiles));
        if isnull(obj.pData) 
            ChannelNames = {};
        else
            ChannelNames = get(obj.pData.info,'Name');
        end
        
        OK = true(1,length(userfiles));
        for n=1:length(userfiles)
            
            [~,mbtnames{n}] = fileparts(userfiles(n).name);
            
            try
                Ti = struct2cell(load('-mat',fullfile(obj.Dir,userfiles(n).name)));
                checkmodel(Ti{1});
            catch
                OK(n) = false;
                continue
            end
            if OK(n) && ~isempty(ChannelNames)
            % only show test plan if all inputs are in the data set
                Inps = getInputs(Ti{1});
                Inps = cat(1,Inps{:});
                OK(n)= all(ismember({Inps.Name},ChannelNames));
            end
            
        end
        
        obj.UserTemplateFiles= userfiles(OK);
        obj.UserTemplateNames =mbtnames(OK);
        end
        
        function addCurrentTestplans( obj )
        %addCurrentTestplans add test plans from current MBCMODEL project
        tps = obj.Project.children(@MakeTemplate);
        if ~isnull(obj.pData)
            OK = true(1,length(tps));
            if isnull(obj.pData) || ~obj.FilterDatasets
                ChannelNames = {};
            else
                ChannelNames = get(obj.pData.info,'Name');
            end
            for i=1:length(tps)
                Inps = getInputs(tps{i});
                Inps = cat(1,Inps{:});
                OK(i)= all(ismember({Inps.Name},ChannelNames));
            end
            tps = tps(OK);
        end
        obj.CurrentTestplans = tps;
        obj.CurrentNames = cellfun(@name,tps,'UniformOutput',false);
        end
        
        
        function selectTestplan(obj,ind)
        %selectTestplan select test plan from list
        if ind~=obj.SelectedIndex
            
            if ind<=length(obj.BuiltIn)
                % builtin
                T= obj.BuiltIn{ind};
            else
                i = ind-length(obj.BuiltIn);
                if i<=length(obj.UserTemplateFiles)
                    Ti = struct2cell(load('-mat',fullfile(obj.Dir,obj.UserTemplateFiles(i).name)));
                    T= Ti{1};
                else
                    i = ind-length(obj.BuiltIn)-length(obj.UserTemplateFiles);
                    T = obj.CurrentTestplans{i};
                end
            end
            
            obj.Selected = T;
            obj.SelectedIndex = ind;
        end
        end
        
        
        function createTestplan(obj)
        %createTestplan create template
        
        T = obj.FinalTestplan;
        % create test plan and add to tree
        pTP = xregpointer(T);
        AddChild(info(obj.Project),pTP);
        % make name of test plan unique
        pTP.name(pTP.name);
        pTP.info = cacheTSSF(pTP.info);
        if ~isnull(obj.pData)
            % attach data to test plan if necessary
            T = info(pTP);
            T = setmatched(T,false);
            % prepare data for use in test plan
            %   setupTSSF makes a copy of the data if the data is used in
            %   another testplan. This could cause a new data pointer.
            T = setupTSSF(T,obj.pData);
            % don't broadcast these changes
            obj.pDataStorage = DataLinkPtr(T);
                      % setup test groups
            [obj.pData.info,OK] = setupGroups(T,info(obj.pData));
            if ~OK
                % setupGroups cancelled so clean up data

                % update private pDataStorage (required to set data to
                % null)
                obj.pDataStorage = xregpointer;
                T = DataLinkPtr(T,obj.pData);
                % clean up extra data created by setupTSSF
                cleanupData(info(obj.Project),address(T));
            end
            obj.FinalTestplan = T;
        end
        obj.FinalTestplan = info(pTP);

        if pTP.isBrowserProject
            % add to browser and select if relevant
            treeview(MBrowser,pTP,'add')
            SelectNode(MBrowser,pTP);
        end
        end
        
        function fitmodels(obj)
        %fitmodels fit models to selected data
        
        T = obj.FinalTestplan;
        pFitData = obj.pData;

        % create validation data subset

        checkLargeData(obj,pFitData);
        % don't attempt to attach empty data
        if ~isempty(pFitData.info) 
            switch obj.ValidationType
                case 'none'
                case {'random','last'}
                    pFitData = createValidationSubset(obj);
            end
            
            % fit models in test plan
            T = setmatched(info(T),false);
            T = DataLinkPtr(T,xregpointer);
            
            if ~isnull(obj.ValidationData)
                % attach validation data first because it may be needed for
                % fit statistics
                valdata(info(T),sweepsetfilter(obj.ValidationData));
            end
            attachData(info(T),pFitData,...
                'UseDataRange',logical(obj.UseDataRange),...
                'Boundary',logical(obj.Boundary));
        end
        if address(T)==get(MBrowser,'CurrentNode')
            % setup framework again if necessary 
            frameWork = GetViewData(MBrowser);
            change(frameWork,address(T));
        end
            
        end
        
        function checkLargeData(obj,pFitData)
        %checkDataSizes use large data options

        ssf = info(pFitData);
        T = obj.FinalTestplan;
        D = designdev(T);
        TS = HSModel(D);
        ChangeModel = false;
        switch lower(type(T))
            case 'one-stage'
                if size(ssf,1)>2000 
                    % more than 2000 points
                    mLarge = xregCreateModel(@xreggpr,TS);
                    if ~isequal(mLarge,TS)                    
                        ChangeModel = true;
                        TS = mLarge;
                    end
                end
            case 'two-stage'
                if size(ssf,3)>2000  
                    % more than 1000 tests
                    m = get(TS,'baseglobal');
                    m = xregCreateModel(@xregcubic,m);
                    % use a polynomial
                    mLarge = set(m,'order',2*ones(1,nfactors(m)));
                    if ~isequal(mLarge,m) 
                        ChangeModel = true;
                        TS = set(TS,'global',mLarge);
                    end
                end
                
            case 'point-by-point'
                if size(ssf,3)>100 || any(tsizes(sweepset(ssf))>2000)
                    % more than 100 tests or a test with more than 2000
                    % points
                    ChangeModel = true;
                    L = get(TS,'Local');
                    % use a default GPM
                    m = xregCreateModel(@xreggpr,L);
                    L = set(L,'models',{m});
                    TS = set(TS,'Local',L);
                end
        end
        if ChangeModel
            %update testplan response models
            updateResponseModels(T,TS);
        end
        
        end
        
        function sendToDataEditor(obj,varargin)
        %sendToDataEditor open data editor from test plan for fit models
        
        T = info( obj.FinalTestplan );
        if nargin==1
            Args = {obj.pData,T,[],true};
        else
            Args = varargin;
        end
        
        % call processTestplanData to process data
        frameWork = GetViewData(MBrowser);
        ms = frameWork.MessageService;
        if isnull(ms.Pointer)
            % setup framework again if necessary 
            change(frameWork,get(MBrowser,'CurrentNode'));
        end
        editData(ms, Args{:},@obj.processTestplanData);
        end        
        
        function processTestplanData(obj,pSSF,newData,changes)
        %processTestplanData process test plan data after the test plan Fit models wizard

        % make validation data if necessary
        
        T = info( obj.FinalTestplan );
        
        switch obj.ValidationType
            case {'random','last'}
                OldData = pSSF.info;
                pSSF.info = newData;
                pSSF = createValidationSubset(obj);
                newData = pSSF.info;
                pSSF.info = OldData;
        end

        if obj.UseDataRange
            Inputs = getInputs(T);
            % use data ranges for model inputs
            for i=1:length(Inputs)
                D = newData(:,{Inputs{i}.Name});
                Inputs{i} = DataRange(Inputs{i},D);
            end
            T = setInputs(T,Inputs);
        end
        modifyData(T, pSSF, newData,changes);
        if obj.Boundary
           buildBoundaryModels(info(T)); 
        end
        if ~isnull(obj.ValidationData)
            valdata(info(T),sweepsetfilter(obj.ValidationData));
        end
        
        end

        function pValList = get.pValidationSets(obj)
        % list of possible validation data - must have all channels that are in the main dataset
        
        if ~isnull(obj.pData)
            Channels = get(obj.pData.info,'name');
            pValList = obj.pDataList(obj.pDataList~=obj.pData);
            OK = parrayeval(pValList,@(D) all(ismember(Channels,get(D,'name'))),{},@false);
            pValList = pValList(OK);
        else
            pValList = mbcpointer(1,0);
        end
        end
        
        end
    
    
    methods (Access=private)
        function pFitData = createValidationSubset(obj)
        %createValidationSubset create validation data set as subset of fit data
        
        pFitData = obj.pData;
        T = info(obj.FinalTestplan);

        % add a variable to index validation data
        ssf = pFitData.info;
        
        vars = get(ssf,'name');
        valVariable = 'mbcValSelector';
        if any(strcmp(valVariable,vars))
            % remove any mbcValSelector variables and filters from ssf
            f = get(ssf,'filters');
            if ~isempty(f)
                remFilters = ~cellfun(@isempty,strfind({f.filterExp},valVariable));
                if any(remFilters)
                    ssf = removeFilter(ssf,remFilters);
                end
            end
            f = get(ssf,'sweepfilters');
            if ~isempty(f)
                remFilters = ~cellfun(@isempty,strfind({f.filterExp},valVariable));
                if any(remFilters)
                    ssf = removeSweepFilter(ssf,remFilters);
                end
            end
            % remove user variables
            v = get(ssf,'variables');
            if ~isempty(v)
                ssf = removeVariable(ssf,find(strcmp(valVariable,{v.varName})));
            end
            v = get(ssf,'sweepvariables');
            if ~isempty(v)
                ssf = removeSweepVariable(ssf,find(strcmp(valVariable,{v.varName})));
            end
        end
        fAddFcn = @addVariable;
        if strcmp(obj.ValidationType,'random')
            % sample points at random
            vardef = sprintf('%s = mbcRandomSelection(%s,%d)',valVariable,vars{1},sum(clock));
        else
            vardef = sprintf('%s = mbcLastSelection(%s)',valVariable,vars{1});
            if strcmp(type(T),'Point-by-Point')
                % need indices per test for last % of tests
                fAddFcn = @addSweepVariable;
            end
        end
        ssf = fAddFcn(ssf,vardef);
        
        pFitData.info = ssf;
        % make a copy of the data for validation - this has a common base data with validation
        % selector variable
        ssf = copy(sweepsetfilter(ssf));
        ssf = set(ssf,'Label',[get(ssf,'Label'),' Validation']);
        pValData = xregpointer(ssf);
        addData(obj.Project.info,pValData);
        
        % add filters
        switch type(T)
            case 'One-Stage'
                % one-stage has ordinary filters
                pFitData.info = addFilter(pFitData.info,sprintf('%s > prctile(%s,%g)',valVariable,valVariable,obj.ValidationPercent));
                pValData.info = addFilter(pValData.info,sprintf('%s <= prctile(%s,%g)',valVariable,valVariable,obj.ValidationPercent));
            case 'Point-by-Point'
                % point-by-point filters operate on a per sweep basis
                pFitData.info = addSweepFilter(pFitData.info,sprintf('%s > prctile(%s,%g)',valVariable,valVariable,obj.ValidationPercent));
                pValData.info = addSweepFilter(pValData.info,sprintf('%s <= prctile(%s,%g)',valVariable,valVariable,obj.ValidationPercent));
            case 'Two-Stage'
                % select whole sweeps based on first element in mbcValSelector for each sweep
                % last % will be based on record indices
                pFitData.info = addSweepFilter(pFitData.info,sprintf('~mbcTestSelector(%s,%d)',valVariable,obj.ValidationPercent));
                pValData.info = addSweepFilter(pValData.info,sprintf('mbcTestSelector(%s,%d)',valVariable,obj.ValidationPercent));
        end
        obj.ValidationData = pValData;
        
        end
    end
    
end