source: trunk/src/series.m @ 882

Last change on this file since 882 was 882, checked in by gostiaux, 9 years ago

Added option for PBS job scheduler at LMFA

File size: 151.3 KB
Line 
1%'series': master function associated to the GUI series.m for analysis field series 
2%------------------------------------------------------------------------
3% function varargout = series(varargin)
4% associated with the GUI series.fig
5%
6%INPUT
7% param: structure with input parameters (link with the GUI uvmat)
8%      .menu_coord_str: string for the TransformName (menu for coordinate transforms)
9%      .menu_coord_val: value for TransformName (menu for coordinate transforms)
10%      .FileName: input file name
11%      .FileName_1: second input file name
12%      .list_field: menu of input fields
13%      .index_fields: chosen index
14%      .civ1=0 or 1, .interp1,  ... : input civ field type
15%
16%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
17%  Copyright 2008-2014, LEGI / CNRS UJF G-INP, Joel.Sommeria@legi.grenoble-inp.fr
18%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
19%     This file is part of the toolbox UVMAT.
20%
21%     UVMAT is free software; you can redistribute it and/or modify
22%     it under the terms of the GNU General Public License as published by
23%     the Free Software Foundation; either version 2 of the License, or
24%     (at your option) any later version.
25%
26%     UVMAT is distributed in the hope that it will be useful,
27%     but WITHOUT ANY WARRANTY; without even the implied warranty of
28%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29%     GNU General Public License (file UVMAT/COPYING.txt) for more details.
30%AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
31
32%------------------------------------------------------------------------
33%------------------------------------------------------------------------
34%  I - MAIN FUNCTION series
35%------------------------------------------------------------------------
36%------------------------------------------------------------------------
37function varargout = series(varargin)
38
39% Begin initialization code - DO NOT EDIT
40gui_Singleton = 1;
41gui_State = struct('gui_Name',       mfilename, ...
42                   'gui_Singleton',  gui_Singleton, ...
43                   'gui_OpeningFcn', @series_OpeningFcn, ...
44                   'gui_OutputFcn',  @series_OutputFcn, ...
45                   'gui_LayoutFcn',  [] , ...
46                   'gui_Callback',   []);
47if nargin && ischar(varargin{1})
48    gui_State.gui_Callback = str2func(varargin{1});
49end
50
51if nargout
52    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
53else
54    gui_mainfcn(gui_State, varargin{:});
55end
56% End initialization code - DO NOT EDIT
57
58%--------------------------------------------------------------------------
59% --- Executes just before series is made visible.
60%--------------------------------------------------------------------------
61function series_OpeningFcn(hObject, eventdata, handles,Param)
62
63% Choose default command line output for series
64handles.output = hObject;
65% Update handles structure
66guidata(hObject, handles);
67
68%% initial settings
69% position and  size of the GUI at opening
70set(0,'Unit','points')
71ScreenSize=get(0,'ScreenSize');%size of the current screen, in points (1/72 inch)
72Width=900;% prefered width of the GUI in points (1/72 inch)
73Height=624;% prefered height of the GUI in points (1/72 inch)
74%adjust to screen size (reduced by a min margin)
75RescaleFactor=min((ScreenSize(3)-80)/Width,(ScreenSize(4)-80)/Height);
76if RescaleFactor>1
77    RescaleFactor=min(RescaleFactor,1);
78end
79Width=Width*RescaleFactor;
80Height=Height*RescaleFactor;
81LeftX=80*RescaleFactor;%position of the left fig side, in pixels (put to the left side, with some margin)
82LowY=round(ScreenSize(4)/2-Height/2); % put at the middle height on the screen
83set(hObject,'Units','points')
84set(hObject,'Position',[LeftX LowY Width Height])% position and size of the GUI at opening
85
86% settings of table MinIndex_j
87set(handles.MinIndex_i,'ColumnFormat',{'numeric'})
88set(handles.MinIndex_i,'ColumnEditable',false)
89set(handles.MinIndex_i,'ColumnName',{'i min'})
90set(handles.MinIndex_i,'Data',[])% initiate Data to double (not cell)
91
92% settings of table MinIndex_j
93set(handles.MinIndex_j,'ColumnFormat',{'numeric'})
94set(handles.MinIndex_j,'ColumnEditable',false)
95set(handles.MinIndex_j,'ColumnName',{'j min'})
96set(handles.MinIndex_j,'Data',[])% initiate Data to double (not cell)
97
98% settings of table MaxIndex_i
99set(handles.MaxIndex_i,'ColumnFormat',{'numeric'})
100set(handles.MaxIndex_i,'ColumnEditable',false)
101set(handles.MaxIndex_i,'ColumnName',{'i max'})
102set(handles.MaxIndex_i,'Data',[])% initiate Data to double (not cell)
103
104% settings of table MaxIndex_j
105set(handles.MaxIndex_j,'ColumnFormat',{'numeric'})
106set(handles.MaxIndex_j,'ColumnEditable',false)
107set(handles.MaxIndex_j,'ColumnName',{'j max'})
108set(handles.MaxIndex_j,'Data',[])% initiate Data to double (not cell)
109
110% settings of table PairString
111set(handles.PairString,'ColumnName',{'pairs'})
112set(handles.PairString,'ColumnEditable',false)
113set(handles.PairString,'ColumnFormat',{'char'})
114set(handles.PairString,'Data',{''})
115
116% settings of table MaskTable
117set(handles.MaskTable,'ColumnName',{'mask name'})
118set(handles.PairString,'ColumnEditable',false)
119set(handles.PairString,'ColumnFormat',{'char'})
120set(handles.PairString,'Data',{''})
121
122series_ResizeFcn(hObject, eventdata, handles)%resize table according to series GUI size
123set(hObject,'WindowButtonDownFcn',{'mouse_down'})%allows mouse action with right button (zoom for uicontrol display)
124set(hObject,'DeleteFcn',{@closefcn})%
125
126% check default input data
127if ~exist('Param','var')
128    Param=[]; %default
129end
130
131%% list of builtin functions in the mebu ActionName
132ActionList={'check_data_files';'aver_stat';'time_series';'civ_series';'merge_proj'};% WARNING: fits with nb_builtin_ACTION=4 in ActionName_callback
133NbBuiltinAction=numel(ActionList);
134set(handles.Action,'UserData',NbBuiltinAction)
135[path_series,name,ext]=fileparts(which('series'));% path to the GUI series
136path_series_fct=fullfile(path_series,'series');%path of the functions in subdirectroy 'series'
137[code, message] = system...
138    ('LD_LIBRARY_PATH=$(echo $LD_LIBRARY_PATH | pyp "p.split('':'') |... [s for s in p if ''matlab'' not in s] | '':''.join(p)") python -c "import fluiddyn"');
139if code==0
140    ActionExtList={'.m';'.sh';'.py (in dev.)'};% default choice of extensions (Matlab fct .m or compiled version .sh
141else
142    ActionExtList={'.m';'.sh'};  % python options not installed
143end
144ActionPathList=cell(NbBuiltinAction,1);%initiate the cell matrix of Action fct paths
145ActionPathList(:)={path_series_fct}; %set the default path to series fcts to all list members
146RunModeList={'local';'background'};% default choice of extensions (Matlab fct .m or compiled version .sh)
147[s,w]=system('oarstat');% look for cluster system 'oar'
148if isequal(s,0)
149    RunModeList=[RunModeList;{'cluster_oar'}];
150    set(handles.MonitorCluster,'Visible','on'); % make visible button for access to Monika
151end
152[s,w]=system('qstat --version');% look for cluster system 'sge'
153if isequal(s,0)
154    if regexp(w,'^pbs')
155        RunModeList=[RunModeList;{'cluster_pbs'}];
156    else
157        RunModeList=[RunModeList;{'cluster_sge'}];
158    end
159end
160set(handles.RunMode,'String',RunModeList)
161
162%% list of builtin transform functions in the menu TransformName
163TransformList={'';'sub_field';'phys';'phys_polar'};% WARNING: must fit with the corresponding menu in uvmat and nb_builtin_transform=4 in  TransformName_callback
164NbBuiltinTransform=numel(TransformList);
165path_transform_fct=fullfile(path_series,'transform_field');
166TransformPathList=cell(NbBuiltinTransform,1);%initiate the cell matrix of Action fct paths
167TransformPathList(:)={path_transform_fct}; %set the default path to series fcts to all list members
168
169%% get the user defined functions stored in the personal file uvmat_perso.mat
170dir_perso=prefdir;
171profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
172if exist(profil_perso,'file')
173    h=load (profil_perso);
174    %get the list of previous input files in the upper bar menu Open
175    if isfield(h,'MenuFile')
176        for ifile=1:min(length(h.MenuFile),5)
177            set(handles.(['MenuFile_' num2str(ifile)]),'Label',h.MenuFile{ifile});
178            set(handles.(['MenuFile_' num2str(ifile+5)]),'Label',h.MenuFile{ifile});
179        end
180    end
181    %get the list of previous campaigns in the upper bar menu Open campaign
182    if isfield(h,'MenuCampaign')
183        for ifile=1:min(length(h.MenuCampaign),5)
184            set(handles.(['MenuCampaign_' num2str(ifile)]),'Label',h.MenuCampaign{ifile});
185        end
186    end
187    %get the menu of actions
188%     if isfield(h,'ActionExtListUser') && iscell(h.ActionExtListUser)
189%         ActionExtList=[ActionExtList; h.ActionExtListUser];
190%     end
191    if isfield(h,'ActionListUser') && iscell(h.ActionListUser) && isfield(h,'ActionPathListUser') && iscell(h.ActionPathListUser)
192        ActionList=[ActionList;h.ActionListUser];
193        ActionPathList=[ActionPathList;h.ActionPathListUser(:,1)];
194    end
195    %get the menu of transform fct
196    if isfield(h,'TransformListUser') && iscell(h.TransformListUser) && isfield(h,'TransformPathListUser') && iscell(h.TransformPathListUser)
197        TransformList=[TransformList;h.TransformListUser];
198        TransformPathList=[TransformPathList;h.TransformPathListUser];
199    end
200end
201
202%% selection of the input Action fct
203ActionCheckExist=true(size(ActionList));%initiate the check of the path to the listed action fct
204for ilist=NbBuiltinAction+1:numel(ActionList)%check  the validity of the path of the user defined Action fct
205    ActionCheckExist(ilist)=exist(fullfile(ActionPathList{ilist},[ActionList{ilist} '.m']),'file');
206end
207ActionPathList=ActionPathList(ActionCheckExist,:);% suppress the menu options which are not valid anymore
208ActionList=ActionList(ActionCheckExist);
209set(handles.ActionName,'String',[ActionList;{'more...'}])
210set(handles.ActionName,'UserData',ActionPathList)
211ActionIndex=[];
212if isfield(Param,'ActionName')% copy the selected menu index transferred in Param from uvmat
213    ActionIndex=find(strcmp(Param.ActionName,ActionList),1);
214end
215if isempty(ActionIndex)
216    ActionIndex=1;
217end
218set(handles.ActionName,'Value',ActionIndex)
219set(handles.ActionPath,'String',ActionPathList{ActionIndex})
220set(handles.ActionExt,'Value',1)
221set(handles.ActionExt,'String',ActionExtList)
222
223%% selection of the input transform fct
224TransformCheckExist=true(size(TransformList));
225for ilist=NbBuiltinTransform+1:numel(TransformList)
226    TransformCheckExist(ilist)=exist(fullfile(TransformPathList{ilist},[TransformList{ilist} '.m']),'file');
227end
228TransformPathList=TransformPathList(TransformCheckExist);
229TransformList=TransformList(TransformCheckExist);
230set(handles.TransformName,'String',[TransformList;{'more...'}])
231set(handles.TransformName,'UserData',TransformPathList)
232TransformIndex=[];
233if isfield(Param,'TransformName')% copy the selected menu index transferred in Param from uvmat
234    TransformIndex=find(strcmp(Param.TransformName,TransformList),1);
235end
236if isempty(TransformIndex)
237    TransformIndex=1;
238end
239set(handles.TransformName,'Value',TransformIndex)
240set(handles.TransformPath,'String',TransformPathList{TransformIndex})
241   
242%% fields input initialisation
243if isfield(Param,'list_fields')&& isfield(Param,'index_fields') &&~isempty(Param.list_fields) &&~isempty(Param.index_fields)
244    set(handles.FieldName,'String',Param.list_fields);% list menu fields
245    set(handles.FieldName,'Value',Param.index_fields);% selected string index
246end
247if isfield(Param,'Coordinates')
248    if isfield(Param.Coordinates,'Coord_x')
249        set(handles.Coord_x,'String',Param.Coordinates.Coord_x)
250    end
251    if isfield(Param.Coordinates,'Coord_y')
252        set(handles.Coord_y,'String',Param.Coordinates.Coord_y)
253    end
254    if isfield(Param.Coordinates,'Coord_z')
255        set(handles.Coord_z,'String',Param.Coordinates.Coord_z)
256    end
257end
258% if isfield(Param,'Coord_x_str') && ischar(Param.Coord_x_str)
259%         set(handles.Coord_x,'String',Param.Coord_x_str);% list menu fields
260% end
261% if isfield(Param,'Coord_y_str')&& ischar(Param.Coord_y_str)
262%         set(handles.Coord_y,'String',Param.Coord_y_str);% list menu fields
263% end
264
265%% introduce the input file name(s) if defined from input Param,
266if isfield(Param,'InputFile')
267   
268    %% fill the list of file series
269    InputTable=[{Param.InputFile.RootPath},{Param.InputFile.SubDir},{Param.InputFile.RootFile},{Param.InputFile.NomType},{Param.InputFile.FileExt}];
270    TimeTable=[{Param.InputFile.TimeName},{[]},{[]},{[]},{[]}];
271    if isfield(Param.InputFile,'RootPath_1')
272        InputTable=[InputTable;[{Param.InputFile.RootPath_1},{Param.InputFile.SubDir_1},{Param.InputFile.RootFile_1},{Param.InputFile.NomType_1},{Param.InputFile.FileExt_1}]];
273        TimeTable=[TimeTable; [{Param.InputFile.TimeName_1},{[]},{[]},{[]},{[]}]];
274    end
275    set(handles.InputTable,'Data',InputTable)
276    %% determine the selected reference field indices for pair display
277   
278    [tild,tild,tild,i1,i2,j1,j2]=fileparts_uvmat(Param.InputFile.FileIndex);
279    if isempty(i1)
280        i1=1;
281    end
282    if isempty(i2)
283        i2=i1;
284    end
285    ref_i=floor((i1+i2)/2);% reference image number corresponding to the file
286    % set(handles.num_ref_i,'String',num2str(ref_i));
287    if isempty(j1)
288        j1=1;
289    end
290    if isempty(j2)
291        j2=j1;
292    end
293    ref_j=floor((j1+j2)/2);% reference image number corresponding to the file
294    SeriesData.ref_i=ref_i;
295    SeriesData.ref_j=ref_j;
296    set(handles.series,'UserData',SeriesData)
297    update_rootinfo(handles,Param.HiddenData.i1_series{1},Param.HiddenData.i2_series{1},Param.HiddenData.j1_series{1},Param.HiddenData.j2_series{1},...
298        Param.HiddenData.FileInfo{1},Param.HiddenData.MovieObject{1},1)
299    if isfield(Param,'FileName_1')
300        %         display_file_name(handles,Param,2)
301        update_rootinfo(handles,Param.HiddenData.i1_series{2},Param.HiddenData.i2_series{2},Param.HiddenData.j1_series{2},Param.HiddenData.j2_series{2},...
302            Param.HiddenData.FileInfo{2},Param.HiddenData.MovieObject{2},2)
303    end
304    %% enable field and veltype menus, in accordance with the current action
305    ActionName_Callback([],[], handles)
306   
307    %% set length of waitbar
308    displ_time(handles)
309   
310else
311    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH button to magenta color to indicate that input refresh is needed
312end
313if isfield(Param,'incr_i')
314    set(handles.num_incr_i,'String',num2str(Param.incr_i))
315else
316    set(handles.num_incr_i,'String','1')
317end
318if isfield(Param,'incr_j')
319    set(handles.num_incr_j,'String',num2str(Param.incr_j))
320else
321    set(handles.num_incr_j,'String','1')
322end
323
324%------------------------------------------------------------------------
325% --- Outputs from this function are returned to the command line.
326function varargout = series_OutputFcn(hObject, eventdata, handles)
327%------------------------------------------------------------------------
328varargout{1} = handles.output;
329
330%------------------------------------------------------------------------
331% --- executed when closing uvmat: delete or desactivate the associated figures if exist
332function closefcn(gcbo,eventdata)
333%------------------------------------------------------------------------
334
335% delete set_object_series if detected
336hh=findobj(allchild(0),'name','view_object_series');
337if ~isempty(hh)
338    delete(hh)
339end
340hh=findobj(allchild(0),'name','edit_object_series');
341if ~isempty(hh)
342    delete(hh)
343end
344
345%delete the bowser if detected
346hh=findobj(allchild(0),'tag','browser');
347if ~isempty(hh)
348    delete(hh)
349end
350
351
352%------------------------------------------------------------------------
353%------------------------------------------------------------------------
354%  II - FUNCTIONS FOR INTRODUCING THE INPUT FILES
355% automatically sets the global properties when the rootfile name is introduced
356% then activate the view-field actionname if selected
357% it is activated either by clicking on the RootPath window or by the
358% browser
359%------------------------------------------------------------------------
360%------------------------------------------------------------------------
361% --- fct activated by the browser under 'Open'
362%------------------------------------------------------------------------ 
363function MenuBrowse_Callback(hObject, eventdata, handles)
364%% look for the previously opened file 'oldfile'
365InputTable=get(handles.InputTable,'Data');
366oldfile=InputTable{1,1};
367if isempty(oldfile)
368    % use a file name stored in prefdir
369    dir_perso=prefdir;
370    profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
371    if exist(profil_perso,'file')
372        h=load (profil_perso);
373        if isfield(h,'RootPath') && ischar(h.RootPath)
374            oldfile=h.RootPath;
375        end
376    end
377end
378%% launch the browser
379fileinput=uigetfile_uvmat('pick an input file in the series',oldfile);
380hh=dir(fileinput);
381if numel(hh)>1
382    msgbox_uvmat('ERROR','invalid input, probably a broken link');
383else
384    if ~isempty(fileinput)
385        display_file_name(handles,fileinput,'one')
386    end
387end
388
389% --------------------------------------------------------------------
390function MenuBrowseAppend_Callback(hObject, eventdata, handles)
391
392%% look for the previously opened file 'oldfile'
393InputTable=get(handles.InputTable,'Data');
394RootPathCell=InputTable(:,1);
395if isempty(RootPathCell{1})% no input file in the table
396     MenuBrowse_Callback(hObject, eventdata, handles)%refresh the input table, not append
397     return
398end
399SubDirCell=InputTable(:,2);
400oldfile=fullfile(RootPathCell{1},SubDirCell{1});
401
402%% use a file name stored in prefdir
403dir_perso=prefdir;
404profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
405if exist(profil_perso,'file')
406    h=load (profil_perso);
407    if isfield(h,'RootPath') && ischar(h.RootPath)
408        oldfile=h.RootPath;
409    end
410end
411
412%% launch the browser
413fileinput=uigetfile_uvmat('pick a file to append in the input table',oldfile);
414hh=dir(fileinput);
415if numel(hh)>1
416    msgbox_uvmat('ERROR','invalid input, probably a broken link');
417else
418    if ~isempty(fileinput)
419        display_file_name(handles,fileinput,'append')
420    end
421end
422
423%------------------------------------------------------------------------
424% --- fct activated by selecting a previous file under the menu Open
425%------------------------------------------------------------------------
426function MenuFile_Callback(hObject, eventdata, handles)
427
428errormsg=display_file_name(handles,get(hObject,'Label'),'one');
429if ~isempty(errormsg)
430    set(hObject,'Label','')
431    MenuFile=[{get(handles.MenuFile_1,'Label')};{get(handles.MenuFile_2,'Label')};...
432        {get(handles.MenuFile_3,'Label')};{get(handles.MenuFile_4,'Label')};{get(handles.MenuFile_5,'Label')}];
433    str_find=strcmp(get(hObject,'Label'),MenuFile);
434    MenuFile(str_find)=[];% suppress the input file to the list
435    for ifile=1:numel(MenuFile)
436        set(handles.(['MenuFile_' num2str(ifile)]),'Label',MenuFile{ifile});
437    end
438end
439
440%------------------------------------------------------------------------
441% --- fct activated by selecting a previous file under the menu Open/append
442%------------------------------------------------------------------------
443function MenuFile_append_Callback(hObject, eventdata, handles)
444
445InputTable=get(handles.InputTable,'Data');
446if isempty(InputTable{1,1})% no input file in the table
447    display_file_name(handles,get(hObject,'Label'),'one') %refresh the input table, not append
448else
449    display_file_name(handles,get(hObject,'Label'),'append')% append the selected file to the current list of InputTable
450end
451
452%------------------------------------------------------------------------
453% --- fct activated by the browser under 'Open campaign/Browse...'
454%------------------------------------------------------------------------
455function MenuBrowseCampaign_Callback(hObject, eventdata, handles)
456
457%% look for the previously opened file 'oldfile'
458InputTable=get(handles.InputTable,'Data');
459RootPathCell=InputTable(:,1);
460SubDirCell=InputTable(:,2);
461oldfile=fullfile(RootPathCell{1},SubDirCell{1});
462if isempty(oldfile)
463    % use a file name stored in prefdir
464    dir_perso=prefdir;
465    profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
466    if exist(profil_perso,'file')
467        h=load (profil_perso);
468        if isfield(h,'RootPath') && ischar(h.RootPath)
469            oldfile=h.RootPath;
470        end
471    end
472end
473%% launch the browser
474fileinput=uigetfile_uvmat('pick an input file in the series',oldfile);
475hh=dir(fileinput);
476if numel(hh)>1
477    msgbox_uvmat('ERROR','invalid input, probably a broken link');
478else
479    if ~isempty(fileinput)
480        display_file_name(handles,fileinput,'one')
481    end
482end
483append='one';
484set(handles.MenuOpenCampaign,'ForegroundColor',[1 1 0])
485drawnow
486browse_campaign(handles,append);
487
488%------------------------------------------------------------------------
489% --- fct activated by the browser under 'Open campaign/Browse...'
490%------------------------------------------------------------------------
491function MenuBrowseCampaignAppend_Callback(hObject, eventdata, handles)
492append='append';
493browse_campaign(handles,append);
494
495%------------------------------------------------------------------------
496function browse_campaign(handles,append);
497
498%% look for the previously opened file 'oldfile'
499
500%
501%
502% InputTable=get(handles.InputTable,'Data');
503% RootPath=InputTable{1,1};
504% CampaignPath=fileparts(fileparts(RootPath));
505% DirFull=uigetfile_uvmat('define this path as the Campaign folder:',CampaignPath,'uigetdir');
506% if ~ischar(DirFull)|| ~exist(DirFull,'dir')
507%     return
508% end
509OutPut=browse_data(oldfile);% open the GUI browse_data to get select a campaign dir, experiment and device
510if ~isfield(OutPut,'Campaign')
511    return
512end
513DirName=fullfile(OutPut.Campaign,OutPut.Experiment{1},OutPut.DataSeries{1});
514ListStruct=dir(DirName); %list files and the dir DataSeries
515% select the first appropriate file in the dir
516FileName='';
517for ilist=1:numel(ListStruct)
518    if ~isequal(ListStruct(ilist).isdir,1)%look for files, not dir
519        FileName=ListStruct(ilist).name;
520        FileInfo=get_file_info(fullfile(DirName,FileName));
521        switch FileInfo.FileType
522            case {'image','multimage','civx','civdata','netcdf'}
523                break
524        end
525    end
526end
527if isempty(FileName)
528    msgbox_uvmat('ERROR',['no appropriate input file in the DataSeries folder ' fullfile(DirName)])
529    return
530end
531
532%% update the list of campaigns in the menubar
533MenuCampaign=[{get(handles.MenuCampaign_1,'Label')};{get(handles.MenuCampaign_2,'Label')};...
534    {get(handles.MenuCampaign_3,'Label')};{get(handles.MenuCampaign_4,'Label')};{get(handles.MenuCampaign_5,'Label')}];
535check_dir=isempty(find(strcmp(DirName,MenuCampaign)));
536if check_dir %insert the new campaign in the list if it is not found
537    MenuCampaign(end)=[]; %suppress the last item
538    MenuCampaign=[{DirName};MenuCampaign];%insert the new campaign
539    for ilist=1:numel(MenuCampaign)
540        set(handles.(['MenuCampaign_' num2str(ilist)]),'Label',MenuCampaign{ilist})
541    end
542    % save the list for future opening:
543    dir_perso=prefdir;
544    profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
545    if exist(profil_perso,'file')
546        save (profil_perso,'MenuCampaign','-append'); %store the file names for future opening of uvmat
547    else
548        save (profil_perso,'MenuCampaign','-V6'); %store the file names for future opening of uvmat
549    end
550end
551
552%% display the selected field and related information
553if get(handles.CheckAppend,'Value')
554    display_file_name(handles,fullfile(DirName,FileName),'append')
555else
556    display_file_name(handles,fullfile(DirName,FileName),'one')
557end
558set(handles.MenuOpenCampaign,'ForegroundColor',[0 0 0])
559
560% --------------------------------------------------------------------
561function MenuCampaign_Callback(hObject, eventdata, handles)
562% --------------------------------------------------------------------
563set(handles.MenuOpenCampaign,'ForegroundColor',[1 1 0])
564OutPut=browse_data(get(hObject,'Label'));% open the GUI browse_data to get select a campaign dir, experiment and device
565if ~isfield(OutPut,'Campaign')
566    return
567end
568DirName=fullfile(OutPut.Campaign,OutPut.Experiment{1},OutPut.DataSeries{1});
569hdir=dir(DirName); %list files and dirs
570for ilist=1:numel(hdir)
571    if ~isequal(hdir(ilist).isdir,1)%look for files, not dir
572        FileName=hdir(ilist).name;
573        FileInfo=get_file_info(fullfile(DirName,FileName));
574        switch FileInfo.FileType
575            case {'image','multimage','civx','civdata','netcdf'}
576            break
577        end
578    end
579end
580if get(handles.CheckAppend,'Value')
581    display_file_name(handles,fullfile(DirName,FileName),'append')
582else
583    display_file_name(handles,fullfile(DirName,FileName),'one')
584end
585set(handles.MenuOpenCampaign,'ForegroundColor',[0 0 0])
586
587
588% --- Executes when selected cell(s) is changed in InputTable.
589function InputTable_CellSelectionCallback(hObject, eventdata, handles)
590iline=[];
591if ~isempty(eventdata.Indices)
592    iline=eventdata.Indices(1);
593end
594set(handles.InputLine,'String',num2str(iline));
595% set(handles.InputTable,'UserData',iline);
596
597%------------------------------------------------------------------------
598% --- 'key_press_fcn:' function activated when a key is pressed on the keyboard
599%------------------------------------------------------------------------
600function InputTable_KeyPressFcn(hObject, eventdata, handles)
601set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH button to magenta color to indicate that input refresh is needed
602set(handles.OutputSubDir,'BackgroundColor',[1 0 1])% set edit box OutputSubDir to magenta color to indicate that refresh may be needed
603xx=double(get(handles.series,'CurrentCharacter')); %get the keyboard character
604if ~isempty(xx)
605    switch xx
606        case 31 %downward arrow
607            InputTable=get(handles.InputTable,'Data');
608            iline=str2double(get(handles.InputLine,'String'));
609            if isequal(iline,size(InputTable,1))% arrow downward
610                InputTable=[InputTable;InputTable(iline,:)];% create a new line as a copy of the last one
611                set(handles.InputTable,'Data',InputTable);
612            end
613        case 127  %key 'Suppress'
614            ClearLine_Callback(hObject, eventdata, handles)
615    end
616end
617
618%------------------------------------------------------------------------
619% --- Executes on button press in REFRESH.
620function REFRESH_Callback(hObject, eventdata, handles)
621%------------------------------------------------------------------------
622InputTable=get(handles.InputTable,'Data');
623set(handles.series,'Pointer','watch') % set the mouse pointer to 'watch'
624set(handles.REFRESH,'BackgroundColor',[1 1 0])% set REFRESH  button to yellow color (indicate activation)
625drawnow
626empty_line=false(size(InputTable,1),1);
627for iline=1:size(InputTable,1)
628    empty_line(iline)= isempty(cell2mat(InputTable(iline,1:3)));
629end
630if ~isempty(find(empty_line));
631    InputTable(empty_line,:)=[];%remove empty lines
632    set(handles.InputTable,'Data',InputTable)
633    ListTable={'MinIndex_i','MaxIndex_i','MinIndex_j','MaxIndex_j','PairString','TimeTable'};
634    for ilist=1:numel(ListTable)
635        Table=get(handles.(ListTable{ilist}),'Data');
636        Table(empty_line,:)=[];%remove empty lines
637        set(handles.(ListTable{ilist}),'Data',Table);
638    end
639    set(handles.series,'UserData',[])%refresh the stored info
640end
641for iview=1:size(InputTable,1)
642    RootPath=fullfile(InputTable{iview,1},InputTable{iview,2});
643    if ~exist(RootPath,'dir')
644        i1_series=[];
645        %RootPath=fileparts(RootPath); %will try the upper folder
646        RootFile='';
647    else %scan the input folder
648        [RootPath,SubDir,RootFile,i1_series,i2_series,j1_series,j2_series,tild,FileInfo,MovieObject]=...
649            find_file_series(fullfile(InputTable{iview,1},InputTable{iview,2}),[InputTable{iview,3} InputTable{iview,4} InputTable{iview,5}]);
650    end
651    % if no file is found, open a browser
652    if isempty(RootFile)&& isempty(i1_series)
653        fileinput=uigetfile_uvmat(['wrong input at line ' num2str(iview) ':pick a new input file'],RootPath);
654        if isempty(fileinput)
655            set(handles.REFRESH,'BackgroundColor',[1 0 0])% set REFRESH  back to red color
656            return
657        else
658            display_file_name(handles,fileinput,iview)
659        end
660    else
661       update_rootinfo(handles,i1_series,i2_series,j1_series,j2_series,FileInfo,MovieObject,iview)
662    end
663end
664%% enable field and veltype menus, in accordance with the current action
665ActionName_Callback([],[], handles)
666
667%% set length of waitbar
668displ_time(handles)
669
670set(handles.REFRESH,'BackgroundColor',[1 0 0])% set REFRESH  button to red color (indicate activation finished)
671set(handles.series,'Pointer','arrow') % set the mouse pointer to 'watch'
672
673%------------------------------------------------------------------------
674% --- Function called when a new file is opened, either by series_OpeningFcn or by the browser
675%------------------------------------------------------------------------
676% INPUT:
677% handles: handles of elements in the GUI
678% Param: structure of input parameters, including  input file name and path
679% iview: line index in the input table
680%       or 'one': refresh the list
681%         'append': add a new line to the input table
682function errormsg=display_file_name(handles,Param,iview)
683 
684set(handles.REFRESH,'BackgroundColor',[1 1 0])% set REFRESH  button to yellow color (indicate activation)
685drawnow
686errormsg='';%default
687if ischar(Param)
688    fileinput=Param;
689else% input set when series is opened (called by the GUI uvmat)
690    fileinput=Param.FileName;
691end
692   
693%% get the input root name, indices, file extension and nomenclature NomType
694if ~exist(fileinput,'file')
695    errormsg=['input file ' fileinput  ' does not exist'];
696    msgbox_uvmat('ERROR',errormsg)
697    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH  button to magenta color (refresh still needed)
698    return
699end
700
701%% detect root name, nomenclature and indices in the input file name:
702[FilePath,FileName,FileExt]=fileparts(fileinput);
703%%%%%%%%%%%%%%%%%%
704%TODO: case of input by uvmat: do not check agai the input seies %%%%%%%
705%%%%%%%%%%%%%%%%%%%
706% detect the file type, get the movie object if relevant, and look for the corresponding file series:
707% the root name and indices may be corrected by including the first index i1 if a corresponding xml file exists
708[RootPath,SubDir,RootFile,i1_series,i2_series,j1_series,j2_series,NomType,FileInfo,MovieObject,i1,i2,j1,j2]=find_file_series(FilePath,[FileName FileExt]);
709FileType=FileInfo.FileType;
710if isempty(RootFile)&&isempty(i1_series)
711    errormsg='no input file in the series';
712    msgbox_uvmat('ERROR',errormsg)
713    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH  button to magenta color (end of activation)
714    return
715end
716if strcmp(FileType,'txt')
717    edit(fileinput)
718    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH  button to  magenta color (end of activation)
719    return
720elseif strcmp(FileType,'xml')
721    editxml(fileinput)
722    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH  button to magenta  color (end of activation)
723     return
724elseif strcmp(FileType,'figure')
725    open(fileinput)
726    set(handles.REFRESH,'BackgroundColor',[1 0 1])% set REFRESH  button to magenta  color (end of activation)
727     return
728end
729
730%% enable other menus and uicontrols
731set(handles.MenuOpenCampaign,'Enable','on')
732set(handles.MenuCampaign_1,'Enable','on')
733set(handles.MenuCampaign_2,'Enable','on')
734set(handles.MenuCampaign_3,'Enable','on')
735set(handles.MenuCampaign_4,'Enable','on')
736set(handles.MenuCampaign_5,'Enable','on')
737set(handles.RUN, 'Enable','On')
738set(handles.RUN,'BackgroundColor',[1 0 0])% set RUN button to red
739set(handles.InputTable,'BackgroundColor',[1 1 0]) % set RootPath edit box  to yellow
740drawnow
741
742
743%% fill the list of file series
744InputTable=get(handles.InputTable,'Data');
745SeriesData=get(handles.series,'UserData');
746if strcmp(iview,'append') % display the input data as a new line in the table
747    iview=size(InputTable,1)+1;% the next line in InputTable becomes the current line
748%     InputTable(iview,:)=[{RootPath},{SubDir},{RootFile},{NomType},{FileExt}];
749elseif strcmp(iview,'one') % refresh the list of  input  file series
750    iview=1; %the first line in InputTable becomes the current line
751    InputTable={'','','','',''};
752%     InputTable(iview,:)=[{RootPath},{SubDir},{RootFile},{NomType},{FileExt}];
753    set(handles.TimeTable,'Data',[{''},{[]},{[]},{[]},{[]}])
754    set(handles.MinIndex_i,'Data',[])
755    set(handles.MaxIndex_i,'Data',[])
756    set(handles.MinIndex_j,'Data',[])
757    set(handles.MaxIndex_j,'Data',[])
758    set(handles.PairString,'Data',{''})
759    SeriesData.CheckPair=0;%reset the list of input lines with pairs
760    SeriesData.i1_series={};
761    SeriesData.i2_series={};
762    SeriesData.j1_series={};
763    SeriesData.j2_series={};
764    SeriesData.FileType={};
765    SeriesData.FileInfo={};
766    SeriesData.Time={};
767end
768   SeriesData.i1_series(iview+1:end)=[];
769    SeriesData.i2_series(iview+1:end)=[];
770    SeriesData.j1_series(iview+1:end)=[];
771    SeriesData.j2_series(iview+1:end)=[];
772    SeriesData.FileType(iview+1:end)=[];
773    SeriesData.FileInfo(iview+1:end)=[];
774    SeriesData.Time(iview+1:end)=[];
775 InputTable(iview,:)=[{RootPath},{SubDir},{RootFile},{NomType},{FileExt}];
776if iview >1
777    set(handles.InputLine,'String',num2str(iview))
778end
779set(handles.InputTable,'Data',InputTable)
780
781%% determine the selected reference field indices for pair display
782if isempty(i1)
783    i1=1;
784end
785if isempty(i2)
786    i2=i1;
787end
788ref_i=floor((i1+i2)/2);% reference image number corresponding to the file
789% set(handles.num_ref_i,'String',num2str(ref_i));
790if isempty(j1)
791    j1=1;
792end
793if isempty(j2)
794    j2=j1;
795end
796ref_j=floor((j1+j2)/2);% reference image number corresponding to the file
797SeriesData.ref_i=ref_i;
798SeriesData.ref_j=ref_j;
799
800%% update first and last indices if they do not exist
801Param=read_GUI(handles.series);
802first_j=[];
803if isfield(Param.IndexRange,'first_j'); first_j=Param.IndexRange.first_j; end
804last_j=[];
805if isfield(Param.IndexRange,'last_j'); last_j=Param.IndexRange.last_j; end
806PairString='';
807if isfield(Param.IndexRange,'PairString'); PairString=Param.IndexRange.PairString; end
808[i1,i2,j1,j2] = get_file_index(Param.IndexRange.first_i,first_j,PairString);
809FirstFileName=fullfile_uvmat(Param.InputTable{1,1},Param.InputTable{1,2},Param.InputTable{1,3},...
810    Param.InputTable{1,5},Param.InputTable{1,4},i1,i2,j1,j2);
811if ~exist(FirstFileName,'file')
812    set(handles.num_first_i,'String',num2str(ref_i))
813    set(handles.num_first_j,'String',num2str(ref_j))
814end
815[i1,i2,j1,j2] = get_file_index(Param.IndexRange.last_i,last_j,PairString);
816LastFileName=fullfile_uvmat(Param.InputTable{1,1},Param.InputTable{1,2},Param.InputTable{1,3},...
817    Param.InputTable{1,5},Param.InputTable{1,4},i1,i2,j1,j2);
818if ~exist(LastFileName,'file')
819    set(handles.num_last_i,'String',num2str(ref_i))
820    set(handles.num_last_j,'String',num2str(ref_j))
821end
822
823%% update the list of recent files in the menubar and save it for future opening
824MenuFile=[{get(handles.MenuFile_1,'Label')};{get(handles.MenuFile_2,'Label')};...
825    {get(handles.MenuFile_3,'Label')};{get(handles.MenuFile_4,'Label')};{get(handles.MenuFile_5,'Label')}];
826str_find=strcmp(fileinput,MenuFile);
827if isempty(find(str_find,1))
828    MenuFile=[{fileinput};MenuFile];%insert the current file if not already in the list
829end
830for ifile=1:min(length(MenuFile),5)
831    eval(['set(handles.MenuFile_' num2str(ifile) ',''Label'',MenuFile{ifile});'])
832end
833dir_perso=prefdir;
834profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
835if exist(profil_perso,'file')
836    save (profil_perso,'MenuFile','-append'); %store the file names for future opening of uvmat
837else
838    save (profil_perso,'MenuFile','-V6'); %store the file names for future opening of uvmat
839end
840% save the opened file to initiate future opening
841SeriesData.RefFile{iview}=fileinput;% reference opening file for line iview
842SeriesData.Ref_i1=i1;
843SeriesData.Ref_i2=i2;
844SeriesData.Ref_j1=j1;
845SeriesData.Ref_j2=j2;
846set(handles.series,'UserData',SeriesData)
847
848set(handles.InputTable,'BackgroundColor',[1 1 1])
849
850%% initiate input file series and refresh the current field view:     
851update_rootinfo(handles,i1_series,i2_series,j1_series,j2_series,FileInfo,MovieObject,iview);
852%% enable field and veltype menus, in accordance with the current action
853ActionName_Callback([],[], handles)
854
855%% set length of waitbar
856displ_time(handles)
857
858set(handles.REFRESH,'BackgroundColor',[1 0 0])% set REFRESH  button to red color (end of activation)
859
860%------------------------------------------------------------------------
861% --- Update information about a new field series (indices to scan, timing,
862%     calibration from an xml file
863function update_rootinfo(handles,i1_series,i2_series,j1_series,j2_series,FileInfo,VideoObject,iview)
864%------------------------------------------------------------------------
865InputTable=get(handles.InputTable,'Data');
866
867%% display the min and max indices for the whole file series
868if size(i1_series,2)==2 && min(min(i1_series(:,1,:)))==0
869    MinIndex_j=1;% index j set to 1 by default
870    MaxIndex_j=1;
871    MinIndex_i=find(i1_series(1,2,:), 1 )-1;% min ref index i detected in the series (corresponding to the first non-zero value of i1_series, except for zero index)
872    MaxIndex_i=find(i1_series(1,2,:),1,'last' )-1;%max ref index i detected in the series (corresponding to the last non-zero value of i1_series)
873else
874    ref_i=squeeze(max(i1_series(1,:,:),[],2));% select ref_j index for each ref_i
875    ref_j=squeeze(max(j1_series(1,:,:),[],3));% select ref_i index for each ref_j
876     MinIndex_i=min(find(ref_i))-1;
877     MaxIndex_i=max(find(ref_i))-1;
878     MaxIndex_j=max(find(ref_j))-1;
879     MinIndex_j=min(find(ref_j))-1;
880    diff_j_max=diff(ref_j);
881    diff_i_max=diff(ref_i);
882    if ~isempty(diff_i_max) && isequal (diff_i_max,diff_i_max(1)*ones(size(diff_i_max)))
883        set(handles.num_incr_i,'String',num2str(diff_i_max(1)))% detect an increment to dispaly by default
884    end
885    if ~isempty(diff_j_max) && isequal (diff_j_max,diff_j_max(1)*ones(size(diff_j_max)))
886        set(handles.num_incr_j,'String',num2str(diff_j_max(1)))
887    end
888end
889if isequal(MinIndex_i,-1)
890    MinIndex_i=0;
891end
892if isequal(MinIndex_j,-1)
893    MinIndex_j=0;
894end
895MinIndex_i_table=get(handles.MinIndex_i,'Data');%retrieve the min indices in the table MinIndex
896MinIndex_j_table=get(handles.MinIndex_j,'Data');%retrieve the min indices in the table MinIndex
897MaxIndex_i_table=get(handles.MaxIndex_i,'Data');%retrieve the min indices in the table MinIndex
898MaxIndex_j_table=get(handles.MaxIndex_j,'Data');%retrieve the min indices in the table MinIndex
899if ~isempty(MinIndex_i)&&~isempty(MaxIndex_i)
900    MinIndex_i_table(iview,1)=MinIndex_i;
901    MaxIndex_i_table(iview,1)=MaxIndex_i;
902end
903if ~isempty(MinIndex_j)&&~isempty(MaxIndex_j)
904    MinIndex_j_table(iview,1)=MinIndex_j;
905    MaxIndex_j_table(iview,1)=MaxIndex_j;
906end
907set(handles.MinIndex_i,'Data',MinIndex_i_table)%display the min indices in the table MinIndex
908set(handles.MinIndex_j,'Data',MinIndex_j_table)%display the max indices in the table MaxIndex
909set(handles.MaxIndex_i,'Data',MaxIndex_i_table)%display the min indices in the table MinIndex
910set(handles.MaxIndex_j,'Data',MaxIndex_j_table)%display the max indices in the table MaxIndex
911SeriesData=get(handles.series,'UserData');
912
913%% adjust the first and last indices for the selected series, only if requested by the bounds
914% i index, compare input to min index i
915first_i=str2num(get(handles.num_first_i,'String'));%retrieve previous first i
916% ref_i=str2num(get(handles.num_ref_i,'String'));%index i given by the input field
917ref_i=1;
918if isfield(SeriesData,'ref_i')
919ref_i=SeriesData.ref_i;
920end
921if isempty(first_i)
922    first_i=ref_i;% first_i updated by the input value
923elseif first_i < MinIndex_i
924    first_i=MinIndex_i; % first_i set to the min i index (restricted by oter input lines)
925elseif first_i >MaxIndex_i
926    first_i=MaxIndex_i;% first_i set to the max i index (restricted by oter input lines)
927end
928% j index,  compare input to min index j
929first_j=str2num(get(handles.num_first_j,'String'));
930ref_j=1;
931if isfield(SeriesData,'ref_j')
932ref_j=SeriesData.ref_j;
933end
934if isempty(first_j)
935    first_j=ref_j;% first_j updated by the input value
936elseif first_j<MinIndex_j
937    first_j=MinIndex_j; % first_j set to the min j index (restricted by oter input lines)
938elseif first_j >MaxIndex_j
939    first_j=MaxIndex_j; % first_j set to the max j index (restricted by oter input lines)
940end
941% i index, compare input to max index i
942last_i=str2num(get(handles.num_last_i,'String'));
943if isempty(last_i)
944    last_i=ref_i;
945elseif last_i > MaxIndex_i
946    last_i=MaxIndex_i;
947elseif last_i<first_i
948    last_i=first_i;
949end
950% j index, compare input to max index j
951last_j=str2num(get(handles.num_last_j,'String'));
952if isempty(last_j)
953    last_j=ref_j;
954elseif last_j>MaxIndex_j
955    last_j=MaxIndex_j;
956elseif last_j<first_j
957    last_j=first_j;
958end
959set(handles.num_first_i,'String',num2str(first_i));
960set(handles.num_first_j,'String',num2str(first_j));
961set(handles.num_last_i,'String',num2str(last_i));
962set(handles.num_last_j,'String',num2str(last_j));
963
964%% number of slices set by default
965NbSlice=1;%default
966% read  value set by the first series for the append mode (iwiew >1)
967if iview>1 && strcmp(get(handles.num_NbSlice,'Visible'),'on')
968    NbSlice=str2num(get(handles.num_NbSlice,'String'));
969end
970
971%% default time settings
972TimeUnit='';
973% read  value set by the first series for the append mode (iwiew >1)
974if iview>1
975    TimeUnit=get(handles.TimeUnit,'String');
976end
977TimeName='';
978Time=[];%default
979TimeMin=[];
980TimeFirst=[];
981TimeLast=[];
982TimeMax=[];
983
984%%  read image documentation file if found
985XmlData=[];
986check_calib=0;
987XmlFileName=find_imadoc(InputTable{iview,1},InputTable{iview,2},InputTable{iview,3},InputTable{iview,5});
988if ~isempty(XmlFileName)
989    [XmlData,errormsg]=imadoc2struct(XmlFileName);
990    if ~isempty(errormsg)
991         msgbox_uvmat('WARNING',['error in reading ' XmlFileName ': ' errormsg]);
992    end
993    % read time if available
994    if isfield(XmlData,'Time')
995         Time=XmlData.Time;
996        TimeName='xml';
997    end
998    if isfield(XmlData,'Camera')
999        if isfield(XmlData.Camera,'NbSlice')&& ~isempty(XmlData.Camera.NbSlice)
1000            if iview>1 && ~isempty(NbSlice) && ~strcmp(NbSlice,XmlData.Camera.NbSlice)
1001                msgbox_uvmat('WARNING','inconsistent number of slices with the first field series');
1002            end
1003            NbSlice=XmlData.Camera.NbSlice;% Nbre of slices from camera
1004        end
1005        if isfield(XmlData.Camera,'TimeUnit')&& ~isempty(XmlData.Camera.TimeUnit)
1006            if iview>1 && ~isempty(TimeUnit) && ~strcmp(TimeUnit,XmlData.Camera.TimeUnit)
1007                msgbox_uvmat('WARNING','inconsistent time unit with the first field series');
1008            end
1009            TimeUnit=XmlData.Camera.TimeUnit;
1010        end
1011    end
1012    % number of slices
1013    if isfield(XmlData,'GeometryCalib')
1014        check_calib=1;
1015        if isfield(XmlData.GeometryCalib,'SliceCoord')
1016            siz=size(XmlData.GeometryCalib.SliceCoord);
1017            if siz(1)>1
1018                if iview>1 && ~isempty(NbSlice) && ~strcmp(NbSlice,siz(1))
1019                    msgbox_uvmat('WARNING','inconsistent number of Z indices with the first field series');
1020                end
1021                NbSlice=siz(1);
1022            end
1023        end
1024    end
1025    set(handles.num_NbSlice,'String',num2str(NbSlice))
1026end
1027
1028%% read timing  from the current file (prioritary)
1029if ~isempty(VideoObject)% case of movies
1030    imainfo=get(VideoObject);
1031    if isempty(j1_series); %frame index along i
1032        Time=zeros(imainfo.NumberOfFrames+1,2);
1033        Time(:,2)=(0:1/imainfo.FrameRate:(imainfo.NumberOfFrames)/imainfo.FrameRate)';
1034    else
1035        Time=[0;ones(size(i1_series,3)-1,1)]*(0:1/imainfo.FrameRate:(imainfo.NumberOfFrames)/imainfo.FrameRate);
1036    end
1037    TimeName='video';
1038end
1039
1040
1041%% determine the min and max times: case of Netcdf files will be treated later in FieldName_Callback
1042if ~isempty(TimeName)
1043    TimeMin=Time(MinIndex_i+1,MinIndex_j+1);
1044    if size(Time)>=[first_i+1 first_j+1]
1045        TimeFirst=Time(first_i+1,first_j+1);
1046    end
1047    if size(Time)>=[last_i+1 last_j+1]
1048        TimeLast=Time(last_i+1,last_j+1);
1049    end
1050    if size(Time)>=[MaxIndex_i+1 MaxIndex_j+1];
1051        TimeMax=Time(MaxIndex_i+1,MaxIndex_j+1);
1052    end
1053end
1054
1055%% update the time table
1056TimeTable=get(handles.TimeTable,'Data');
1057TimeTable{iview,1}=TimeName;
1058TimeTable{iview,2}=TimeMin;
1059TimeTable{iview,3}=TimeFirst;
1060TimeTable{iview,4}=TimeLast;
1061TimeTable{iview,5}=TimeMax;
1062set(handles.TimeTable,'Data',TimeTable)
1063
1064%% update the series info in 'UserData'
1065SeriesData.i1_series{iview}=i1_series;
1066SeriesData.i2_series{iview}=i2_series;
1067SeriesData.j1_series{iview}=j1_series;
1068SeriesData.j2_series{iview}=j2_series;
1069SeriesData.FileType{iview}=FileInfo.FileType;
1070SeriesData.FileInfo{iview}=FileInfo;
1071SeriesData.Time{iview}=Time;
1072% if ~isempty(TimeName)
1073%     SeriesData.TimeSource=TimeSource;
1074% end
1075if check_calib
1076    SeriesData.GeometryCalib{iview}=XmlData.GeometryCalib;
1077end
1078set(handles.series,'UserData',SeriesData)
1079
1080%% update pair menus
1081hset_pair=findobj(allchild(0),'Tag','set_pairs');
1082if ~isempty(hset_pair), delete(hset_pair); end % delete the GUI set_pair if opened
1083CheckPair= ~isempty(i2_series)||~isempty(j2_series); % check whether index pairs need to be defined
1084PairString=get(handles.PairString,'Data');
1085if CheckPair% if pairs need to be display for line iview
1086    [ModeMenu,ModeValue]=update_mode(i1_series,i2_series,j2_series);
1087    Menu=update_listpair(i1_series,i2_series,j1_series,j2_series,ModeMenu{ModeValue},Time,TimeUnit,ref_i,ref_j,TimeName,InputTable(iview,:),FileInfo);
1088    PairString{iview,1}=Menu{1};
1089else
1090    PairString{iview,1}='';%no pair for #iview
1091end
1092set(handles.PairString,'Data',PairString)
1093if isempty(find(cellfun('isempty',get(handles.PairString,'Data'))==0, 1))% if all lines of pairs are empty
1094    set(handles.PairString,'Visible','off')
1095    set(handles.SetPairs,'Visible','off')
1096else
1097    set(handles.PairString,'Visible','on')
1098    set(handles.SetPairs,'Visible','on')
1099end
1100
1101
1102%% display the set of existing files as an image
1103set(handles.FileStatus,'Units','pixels')
1104Position=get(handles.FileStatus,'Position');
1105set(handles.FileStatus,'Units','normalized')
1106%xI=0.5:Position(3)-0.5;
1107nbview=numel(SeriesData.i1_series);
1108j_max=cell(1,nbview);
1109MaxIndex_i=ones(1,nbview);%default
1110MinIndex_i=ones(1,nbview);%default
1111for iline=1:nbview
1112    pair_max=squeeze(max(SeriesData.i1_series{iline},[],1)); %max on pair index
1113    j_max{iline}=max(pair_max,[],1);%max on j index
1114    if ~isempty(j_max{iline})
1115    MaxIndex_i(iline)=max(find(j_max{iline}))-1;% max ref index i
1116    MinIndex_i(iline)=min(find(j_max{iline}))-1;% min ref index i
1117    end
1118end
1119MinIndex_i=min(MinIndex_i);
1120MaxIndex_i=max(MaxIndex_i);
1121range_index=MaxIndex_i-MinIndex_i+1;
1122range_y=max(1,floor(Position(4)/nbview));
1123npx=floor(Position(3));
1124file_indices=MinIndex_i+floor(((0.5:npx-0.5)/npx)*range_index)+1;
1125CData=zeros(nbview*range_y,npx);% initiate the image representing the existing files
1126for iline=1:nbview
1127    ind_y=1+(iline-1)*range_y:iline*range_y;
1128    LineData=zeros(size(file_indices));
1129    file_select=file_indices(file_indices<=numel(j_max{iline}));
1130    ind_select=find(file_indices<=numel(j_max{iline}));
1131    LineData(ind_select)=j_max{iline}(file_select)~=0;
1132    CData(ind_y,:)=ones(size(ind_y'))*LineData;
1133end
1134CData=cat(3,zeros(size(CData)),CData,zeros(size(CData)));%make color images r=0,g,b=0
1135set(handles.FileStatus,'CData',CData);
1136
1137%-----------------------------------------------------------guide -------------
1138%------------------------------------------------------------------------
1139%  III - FUNCTIONS ASSOCIATED TO THE FRAME IndexRange
1140%------------------------------------------------------------------------
1141
1142
1143% ---- determine the menu to put in mode and advice a default choice
1144%------------------------------------------------------------------------
1145function [ModeMenu,ModeValue]=update_mode(i1_series,i2_series,j2_series)
1146%------------------------------------------------------------------------   
1147ModeMenu={''};
1148if isempty(j2_series)% no j pair
1149    ModeValue=1;
1150    if ~isempty(i2_series)
1151        ModeMenu={'series(Di)'}; % pair menu with only option Di
1152    end
1153else %existence of j pairs
1154    pair_max=squeeze(max(i1_series,[],1)); %max on pair index
1155    j_max=max(pair_max,[],1);
1156    MaxIndex_i=find(j_max, 1, 'last' )-1;% max ref index i
1157    MinIndex_i=find(j_max, 1 )-1;% min ref index i
1158    i_max=max(pair_max,[],2);
1159    MaxIndex_j=find(i_max, 1, 'last' )-1;% max ref index i
1160    MinIndex_j=find(i_max, 1 )-1;% min ref index i
1161    if MaxIndex_j==MinIndex_j
1162        ModeValue=1;
1163        ModeMenu={'bursts'};
1164    elseif MaxIndex_i==MinIndex_i
1165        ModeValue=1;
1166        ModeMenu={'series(Dj)'};
1167    else
1168        ModeMenu={'bursts';'series(Dj)'};
1169        if (MaxIndex_j-MinIndex_j)>10
1170            ModeValue=2;%set mode to series(Dj) if more than 10 j values
1171        else
1172            ModeValue=1;
1173        end
1174    end
1175end
1176
1177
1178%------------------------------------------------------------------------
1179function displ_pair=update_listpair(i1_series,i2_series,j1_series,j2_series,mode,time,TimeUnit,ref_i,ref_j,TimeName,InputTable,FileInfo)
1180%------------------------------------------------------------------------
1181displ_pair={};
1182if isempty(TimeUnit)
1183    dtunit='e-03';
1184else
1185    dtunit=['m' TimeUnit];
1186end
1187switch mode
1188    case 'series(Di)'
1189        diff_i=i2_series-i1_series;
1190        min_diff=min(diff_i(diff_i>0));
1191        max_diff=max(diff_i(diff_i>0));
1192        for ipair=min_diff:max_diff
1193            if numel(diff_i(diff_i==ipair))>0
1194                pair_string=['Di= ' num2str(-floor(ipair/2)) '|' num2str(ceil(ipair/2)) ];
1195                if ~isempty(time)
1196                    if ref_i<=floor(ipair/2)
1197                        ref_i=floor(ipair/2)+1;% shift ref_i to get the first pair
1198                    end
1199                    Dt=time(ref_i+ceil(ipair/2),ref_j)-time(ref_i-floor(ipair/2),ref_j);
1200                    pair_string=[pair_string ', Dt=' num2str(Dt) ' ' dtunit];
1201                end
1202                displ_pair=[displ_pair;{pair_string}];
1203            end
1204        end
1205        if ~isempty(displ_pair)
1206            displ_pair=[displ_pair;{'Di=*|*'}];
1207        end
1208    case 'series(Dj)'
1209        if isempty(j2_series)
1210            msgbox_uvmat('ERROR','no j1-j2 pair available')
1211            return
1212        end
1213        diff_j=j2_series-j1_series;
1214        min_diff=min(diff_j(diff_j>0));
1215        max_diff=max(diff_j(diff_j>0));
1216        for ipair=min_diff:max_diff
1217            if numel(diff_j(diff_j==ipair))>0
1218                pair_string=['Dj= ' num2str(-floor(ipair/2)) '|' num2str(ceil(ipair/2)) ];
1219                if ~isempty(time)
1220                    if ref_j<=floor(ipair/2)
1221                        ref_j=floor(ipair/2)+1;% shift ref_i to get the first pair
1222                    end
1223                    Dt=time(ref_i,ref_j+ceil(ipair/2))-time(ref_i,ref_j-floor(ipair/2));
1224                    pair_string=[pair_string ', Dt=' num2str(Dt) ' ' dtunit];
1225                end
1226                displ_pair=[displ_pair;{pair_string}];
1227            end
1228        end
1229        if ~isempty(displ_pair)
1230            displ_pair=[displ_pair;{'Dj=*|*'}];
1231        end
1232    case 'bursts'
1233        if isempty(j2_series)
1234            msgbox_uvmat('ERROR','no j1-j2 pair available')
1235            return
1236        end
1237        %diff_j=j2_series-j1_series;
1238        min_j1=min(j1_series(j1_series>0));
1239        max_j1=max(j1_series(j1_series>0));
1240        min_j2=min(j2_series(j2_series>0));
1241        max_j2=max(j2_series(j2_series>0));
1242        for pair1=min_j1:min(max_j1,min_j1+20)
1243            for pair2=min_j2:min(max_j2,min_j2+20)
1244                if numel(j1_series(j1_series==pair1))>0 && numel(j2_series(j2_series==pair2))>0
1245                    pair_string=['j= ' num2str(pair1) '-' num2str(pair2)];
1246                    [TimeValue,DtValue]=get_time(ref_i,[],pair_string,InputTable,FileInfo,TimeName,'Dt');
1247                    %Dt=time(ref_i,pair2+1)-time(ref_i,pair1+1);
1248                    pair_string=[pair_string ', Dt=' num2str(DtValue) ' ' dtunit];
1249                    displ_pair=[displ_pair;{pair_string}];
1250                end
1251            end
1252        end
1253        if ~isempty(displ_pair)
1254            displ_pair=[displ_pair;{'j=*-*'}];
1255        end
1256end
1257
1258%------------------------------------------------------------------------
1259function num_first_i_Callback(hObject, eventdata, handles)
1260%------------------------------------------------------------------------
1261num_last_i_Callback(hObject, eventdata, handles)
1262
1263%------------------------------------------------------------------------
1264function num_last_i_Callback(hObject, eventdata, handles)
1265%------------------------------------------------------------------------
1266SeriesData=get(handles.series,'UserData');
1267if ~isfield(SeriesData,'Time')
1268    SeriesData.Time{1}=[];
1269end
1270displ_time(handles);
1271
1272%------------------------------------------------------------------------
1273function num_first_j_Callback(hObject, eventdata, handles)
1274%------------------------------------------------------------------------
1275 num_last_j_Callback(hObject, eventdata, handles)
1276
1277%------------------------------------------------------------------------
1278function num_last_j_Callback(hObject, eventdata, handles)
1279%------------------------------------------------------------------------
1280% first_j=str2num(get(handles.num_first_j,'String'));
1281% last_j=str2num(get(handles.num_last_j,'String'));
1282% ref_j=ceil((first_j+last_j)/2);
1283% set(handles.num_ref_j,'String', num2str(ref_j))
1284% num_ref_j_Callback(hObject, eventdata, handles)
1285SeriesData=get(handles.series,'UserData');
1286if ~isfield(SeriesData,'Time')
1287    SeriesData.Time{1}=[];
1288end
1289displ_time(handles);
1290
1291%------------------------------------------------------------------------
1292% ---- find the times corresponding to the first and last indices of a series
1293function displ_time(handles)
1294%------------------------------------------------------------------------
1295SeriesData=get(handles.series,'UserData');%
1296if ~isfield(SeriesData,'Time')
1297    return
1298end
1299PairString=get(handles.PairString,'Data');
1300ref_i_1=str2num(get(handles.num_first_i,'String'));%first reference index
1301ref_i_2=str2num(get(handles.num_last_i,'String'));%last reference index
1302ref_j_1=[];ref_j_2=[];
1303if strcmp(get(handles.num_first_j,'Visible'),'on')
1304ref_j_1=str2num(get(handles.num_first_j,'String'));
1305ref_j_2=str2num(get(handles.num_last_j,'String'));
1306end
1307[i1_1,i2_1,j1_1,j2_1] = get_file_index(ref_i_1,ref_j_1,PairString);
1308[i1_2,i2_2,j1_2,j2_2] = get_file_index(ref_i_2,ref_j_2,PairString);
1309TimeTable=get(handles.TimeTable,'Data');
1310%%%%%%
1311%TODO: read time in netcdf file, see ActionName_Callback
1312%%%%%%%
1313%Pairs=get(handles.PairString,'Data');
1314for iview=1:size(TimeTable,1)
1315    if size(SeriesData.Time,1)<iview
1316        break
1317    end
1318    TimeTable{iview,3}=[];
1319    TimeTable{iview,4}=[];
1320    if size(SeriesData.Time{iview},1)>=i2_2+1 && (isempty(ref_j_1)||size(SeriesData.Time{iview},2)>=j2_2+1)
1321        if isempty(ref_j_1)
1322            time_first=(SeriesData.Time{iview}(i1_1+1,2)+SeriesData.Time{iview}(i2_1+1,2))/2;
1323            time_last=(SeriesData.Time{iview}(i1_2+1,2)+SeriesData.Time{iview}(i2_2+1,2))/2;
1324        else
1325            time_first=(SeriesData.Time{iview}(i1_1+1,j1_1+1)+SeriesData.Time{iview}(i2_1+1,j2_1+1))/2;
1326            time_last=(SeriesData.Time{iview}(i1_2+1,j1_2+1)+SeriesData.Time{iview}(i2_2+1,j2_1+1))/2;
1327        end
1328        TimeTable{iview,3}=time_first; %TODO: take into account pairs
1329        TimeTable{iview,4}=time_last; %TODO: take into account pairs
1330    end
1331end
1332set(handles.TimeTable,'Data',TimeTable)
1333
1334%% set the waitbar position with respect to the min and max in the series
1335MinIndex_i=min(get(handles.MinIndex_i,'Data'));
1336MaxIndex_i=max(get(handles.MaxIndex_i,'Data'));
1337pos_first=(ref_i_1-MinIndex_i)/(MaxIndex_i-MinIndex_i+1);
1338pos_last=(ref_i_2-MinIndex_i+1)/(MaxIndex_i-MinIndex_i+1);
1339if isempty(pos_first), pos_first=0; end
1340if isempty(pos_last), pos_last=1; end
1341Position=get(handles.Waitbar,'Position');% position of the waitbar:= [ x,y, width, height]
1342Position_status=get(handles.FileStatus,'Position');
1343Position(1)=Position_status(1)+Position_status(3)*pos_first;
1344Position(3)=max(Position_status(3)*(pos_last-pos_first),0.001);% width must remain positive
1345set(handles.Waitbar,'Position',Position)
1346update_waitbar(handles.Waitbar,0)
1347
1348%------------------------------------------------------------------------
1349% --- Executes when selected cell(s) is changed in PairString.
1350function PairString_CellSelectionCallback(hObject, eventdata, handles)
1351%------------------------------------------------------------------------   
1352if numel(eventdata.Indices)>=1
1353    PairString=get(hObject,'Data');
1354    if ~isempty(PairString{eventdata.Indices(1)})
1355        SetPairs_Callback(hObject, eventdata.Indices(1), handles)
1356    end
1357end
1358
1359%-------------------------------------
1360function enable_i(handles,state)
1361set(handles.i_txt,'Visible',state)
1362set(handles.num_first_i,'Visible',state)
1363set(handles.num_last_i,'Visible',state)
1364set(handles.num_incr_i,'Visible',state)
1365
1366%-----------------------------------
1367function enable_j(handles,state)
1368set(handles.j_txt,'Visible',state)
1369set(handles.num_first_j,'Visible',state)
1370set(handles.num_last_j,'Visible',state)
1371set(handles.num_incr_j,'Visible',state)
1372set(handles.MinIndex_j,'Visible',state)
1373set(handles.MaxIndex_j,'Visible',state)
1374
1375
1376%%%%%%%%%%%%%%%%%%%%
1377%%  MAIN ActionName FUNCTIONS
1378%%%%%%%%%%%%%%%%%%%%
1379%------------------------------------------------------------------------
1380% --- Executes on button press in RUN.
1381%------------------------------------------------------------------------
1382function RUN_Callback(hObject, eventdata, handles)
1383
1384%% settings of the button RUN
1385set(handles.RUN,'BusyAction','queue');% activation of STOP button will set BusyAction to 'cancel'
1386set(handles.RUN, 'Enable','Off')% avoid further RUN action until the current one is finished
1387set(handles.RUN,'BackgroundColor',[1 1 0])%show activation of RUN by yellow color
1388drawnow
1389set(handles.status,'Value',0)% desable status display if relevant
1390status_Callback([], eventdata, handles)
1391
1392%% launch action
1393errormsg=launch_action(handles);
1394if ~isempty(errormsg)
1395     msgbox_uvmat('ERROR',errormsg)
1396end
1397
1398%% reset the GUI series
1399update_waitbar(handles.Waitbar,1); % put the waitbar to end position to indicate launching is finished
1400set(handles.RUN, 'Enable','On')
1401set(handles.RUN,'BackgroundColor',[1 0 0])
1402set(handles.RUN, 'Value',0)
1403
1404%------------------------------------------------------------------------
1405% --- called by RUN_Callback
1406%------------------------------------------------------------------------
1407function errormsg=launch_action(handles)
1408errormsg='';%default
1409
1410%% read the data on the GUI series
1411Param=read_GUI_series(handles);%displayed parameters
1412SeriesData=get(handles.series,'UserData');%hidden parameters
1413if ~isfield(SeriesData,'i1_series')
1414    errormsg='The input field series needs to be refreshed: press REFRESH';
1415    return
1416end
1417if isfield(Param,'InputFields')&& isequal(Param.InputFields.FieldName,'get_field...')
1418    errormsg='input field name(s) not defined, select get_field...';
1419    return
1420end
1421
1422%% select the Action mode, 'local', 'background' or 'cluster' (if available)
1423RunMode='local';%default (needed for first opening of the GUI series)
1424if isfield(Param.Action,'RunMode')
1425    RunMode=Param.Action.RunMode;
1426    Param.Action=rmfield(Param.Action,'RunMode');%remove from the recorded xml file to avoid interference during ImportConfig
1427end
1428ActionExt='.m';%default
1429if isfield(Param.Action,'ActionExt')
1430    ActionExt=Param.Action.ActionExt;% '.m', '.sh' (compiled)  or '.py' (Python)
1431    Param.Action=rmfield(Param.Action,'ActionExt');%remove from the recorded xml file to avoid interference during ImportConfig
1432end
1433ActionName=Param.Action.ActionName;
1434ActionPath=Param.Action.ActionPath;
1435path_series=fileparts(which('series'));
1436
1437%% create the Action fct handle if RunMode option = 'local'
1438if strcmp(RunMode,'local')
1439    if ~isequal(ActionPath,path_series)
1440        eval(['spath=which(''' ActionName ''');']) %spath = current path of the selected function ACTION
1441        if ~exist(ActionPath,'dir')
1442            errormsg=['The prescribed function path ' ActionPath ' does not exist'];
1443            return
1444        end
1445        if ~isequal(spath,ActionPath)
1446            addpath(ActionPath)% add the prescribed path if not the current one
1447        end
1448    end
1449    eval(['h_fun=@' ActionName ';'])%create a function handle for ACTION
1450    if ~isequal(ActionPath,path_series)
1451        rmpath(ActionPath)% add the prescribed path if not the current one
1452    end
1453end
1454
1455%% Get RunTime code from the file PARAM.xml (needed to run compiled functions)
1456errormsg='';%default error message
1457xmlfile=fullfile(path_series,'PARAM.xml');
1458test_batch=0;%default: ,no batch mode available
1459if ~exist(xmlfile,'file')
1460    [success,message]=copyfile(fullfile(path_series,'PARAM.xml.default'),xmlfile);
1461end
1462RunTime='';
1463if strcmp(ActionExt,'.sh')
1464    if exist(xmlfile,'file')
1465        s=xml2struct(xmlfile);
1466        if strcmp(RunMode,'cluster_oar') && isfield(s,'BatchParam')
1467            if isfield(s.BatchParam,'RunTime')
1468                RunTime=s.BatchParam.RunTime;
1469            end
1470            if isfield(s.BatchParam,'NbCore')
1471                NbCore=s.BatchParam.NbCore;
1472            end
1473        elseif (strcmp(RunMode,'background')||strcmp(RunMode,'local')) && isfield(s,'RunParam')
1474            if isfield(s.RunParam,'RunTime')
1475                RunTime=s.RunParam.RunTime;
1476            end
1477            if isfield(s.RunParam,'NbCore')
1478                NbCore=s.RunParam.NbCore;
1479            end
1480        end
1481    end
1482    if isempty(RunTime) && strcmp(RunMode,'cluster_oar')
1483       errormsg='RunTime name not found in PARAM.xml, compiled version .sh cannot run on cluster';
1484        return
1485    end
1486end
1487
1488%% If a compiled version has been selected (ext .sh) check weather it needs to be recompiled
1489if strcmp(ActionExt,'.sh')
1490    TransformPath='';
1491    if ~isempty(get(handles.ActionExt,'UserData'))
1492        TransformPath=get(handles.ActionExt,'UserData');
1493    end
1494    set(handles.series,'Pointer','watch') % set the mouse pointer to 'watch'
1495    set(handles.ActionExt,'BackgroundColor',[1 1 0])
1496    ActionFullName=fullfile(get(handles.ActionPath,'String'),[ActionName '.sh']);
1497    if ~exist(ActionFullName,'file')
1498        answer=msgbox_uvmat('INPUT_Y-N','compiled version has not been created: compile now?');
1499        if strcmp(answer,'Yes')
1500            set(handles.ActionExt,'BackgroundColor',[1 1 0])
1501            path_uvmat=fileparts(which('series'));
1502            currentdir=pwd;
1503            cd(get(handles.ActionPath,'String'))% go to the directory of Action
1504            addpath(path_uvmat)% add the path to uvmat to run the fct 'compile'
1505            compile(ActionName,TransformPath)
1506            cd(currentdir)
1507        else
1508            errormsg='Action launch interrupted';
1509            return
1510        end       
1511    else
1512        sh_file_info=dir(fullfile(get(handles.ActionPath,'String'),[ActionName '.sh']));
1513        m_file_info=dir(fullfile(get(handles.ActionPath,'String'),[ActionName '.m']));
1514        if isfield(m_file_info,'datenum') && m_file_info.datenum>sh_file_info.datenum
1515            set(handles.ActionExt,'BackgroundColor',[1 1 0])
1516            drawnow
1517            answer=msgbox_uvmat('INPUT_Y-N',[ActionName '.sh needs to be updated: recompile now?']);
1518            if strcmp(answer,'Yes')
1519                path_uvmat=fileparts(which('series'));
1520                currentdir=pwd;
1521                cd(get(handles.ActionPath,'String'))% go to the directory of Action
1522                addpath(path_uvmat)% add the path to uvmat to run the fct 'compile'
1523                addpath(fullfile(path_uvmat,'transform_field'))% add the path to uvmat to run the fct 'compile'
1524                compile(ActionName,TransformPath)
1525                cd(currentdir)
1526            end
1527        end
1528    end
1529    set(handles.ActionExt,'BackgroundColor',[1 1 1])
1530     set(handles.series,'Pointer','arrow') % set the mouse pointer to 'watch
1531end
1532
1533%% set nbre of cluster cores and processes
1534switch RunMode
1535    case {'local','background'}
1536        NbCore=1;% no need to split the calculation
1537    case 'cluster_oar'
1538        if strcmp(ActionExt,'.m')% case of Matlab function (uncompiled)
1539            NbCore=1;% one core used only (limitation of Matlab licences)
1540            answer=msgbox_uvmat('INPUT_Y-N','Number of cores =1: select the compiled version .sh for multi-core processing. Proceed with the .m version?');
1541            if ~strcmp(answer,'Yes')
1542                errormsg='Action launch interrupted';
1543                return
1544            end
1545            extra_oar='';
1546        else
1547            answer=inputdlg({'Number of cores (max 36)','extra oar options'},'oarsub parameter',1,{'12',''});
1548            NbCore=str2double(answer{1});
1549            extra_oar=answer{2};
1550        end
1551    case 'cluster_pbs'
1552        if strcmp(ActionExt,'.m')% case of Matlab function (uncompiled)
1553            NbCore=1;% one core used only (limitation of Matlab licences)
1554            answer=msgbox_uvmat('INPUT_Y-N','Number of cores =1: select the compiled version .sh for multi-core processing. Proceed with the .m version?');
1555            if ~strcmp(answer,'Yes')
1556                errormsg='Action launch interrupted';
1557                return
1558            end
1559            extra_oar='';
1560        else
1561            answer=inputdlg({'Number of cores (max 36)','extra oar options'},'oarsub parameter',1,{'12',''});
1562            NbCore=str2double(answer{1});
1563            %extra_oar=answer{2};%TODO : fix this for LMFA cluster. Maybe
1564            %extrs_oar and extra_pbs are not the best names
1565        end
1566end
1567if ~isfield(Param.IndexRange,'NbSlice')
1568    Param.IndexRange.NbSlice=[];
1569end
1570if isempty(Param.IndexRange.NbSlice)
1571    NbProcess=NbCore;% choose one process per core
1572else
1573    NbProcess=Param.IndexRange.NbSlice;% the nbre of run processes is equal to the number of slices
1574    NbCore=min(NbCore,NbProcess);% at least one process per core
1575end
1576
1577%% create the output data directory if needed
1578OutputDir='';
1579if isfield(Param,'OutputSubDir')
1580    SubDirOut=[get(handles.OutputSubDir,'String') Param.OutputDirExt];
1581    SubDirOutNew=SubDirOut;
1582    detect=exist(fullfile(Param.InputTable{1,1},SubDirOutNew),'dir');% test if  the dir  already exist
1583    check_create=1; %need to create the result directory by default
1584    while detect
1585        answer=msgbox_uvmat('INPUT_Y-N-Cancel',['use existing ouput directory: ' fullfile(Param.InputTable{1,1},SubDirOutNew) ', possibly delete previous data']);
1586        if strcmp(answer,'Cancel')
1587            return
1588        elseif strcmp(answer,'Yes')
1589            detect=0;
1590            check_create=0;
1591        else
1592            r=regexp(SubDirOutNew,'(?<root>.*\D)(?<num1>\d+)$','names');%detect whether name ends by a number
1593            if isempty(r)
1594                r(1).root=[SubDirOutNew '_'];
1595                r(1).num1='0';
1596            end
1597            SubDirOutNew=[r(1).root num2str(str2num(r(1).num1)+1)];%increment the index by 1 or put 1
1598            detect=exist(fullfile(Param.InputTable{1,1},SubDirOutNew),'dir');% test if  the dir  already exists
1599            check_create=1;
1600        end
1601    end
1602    Param.OutputDirExt=regexprep(SubDirOutNew,Param.OutputSubDir,'');
1603    Param.OutputRootFile=Param.InputTable{1,3};% the first sorted RootFile taken for output
1604    set(handles.OutputDirExt,'String',Param.OutputDirExt)
1605    OutputDir=fullfile(Param.InputTable{1,1},[Param.OutputSubDir Param.OutputDirExt]);% full name (with path) of output directory
1606    if check_create    % create output directory if it does not exist
1607        [tild,msg1]=mkdir(OutputDir);
1608        if ~strcmp(msg1,'')
1609            errormsg=['cannot create ' OutputDir ': ' msg1];%error message for directory creation
1610            return
1611        end
1612        [success,msg] = fileattrib(OutputDir,'+w','g','s');% allow writing access for the group of users, recursively in the folder 
1613        if success==0
1614            msgbox_uvmat('WARNING',{['unable to set group write access to ' OutputDir ':']; msg1});%error message for directory creation
1615        end
1616    end
1617   
1618elseif isfield(Param,'ActionInput')&&isfield(Param.ActionInput,'LogPath')% custom definition of the output dir
1619    OutputDir=Param.ActionInput.LogPath;   
1620end
1621DirXml=fullfile(OutputDir,'0_XML');
1622if ~exist(DirXml,'dir')
1623    [tild,msg1]=mkdir(DirXml);
1624    if ~strcmp(msg1,'')
1625        errormsg=['cannot create ' DirXml ': ' msg1];%error message for directory creation
1626        return
1627    end
1628    [success,msg] = fileattrib(DirXml,'+w','g','s');% allow writing access for the group of users, recursively in the folder
1629    if success==0
1630        msgbox_uvmat('WARNING',{['unable to set group write access to ' DirXml ':']; msg});%error message for directory creation
1631    end
1632end
1633OutputNomType=nomtype2pair(Param.InputTable{1,4});% nomenclature for output files
1634
1635%% get the set of reference field indices
1636first_i=1;
1637last_i=1;
1638incr_i=1;
1639first_j=1;
1640last_j=1;
1641incr_j=1;
1642if isfield(Param.IndexRange,'first_i')
1643    first_i=Param.IndexRange.first_i;
1644    incr_i=Param.IndexRange.incr_i;
1645    last_i=Param.IndexRange.last_i;
1646end
1647if isfield(Param.IndexRange,'first_j')
1648    first_j=Param.IndexRange.first_j;
1649    last_j=Param.IndexRange.last_j;
1650    incr_j=Param.IndexRange.incr_j;
1651end
1652if last_i < first_i || last_j < first_j
1653    errormsg= 'series/Run_Callback:last field index must be larger or equal to the first one';
1654    return
1655end
1656%incr_i must be defined, =1 by default, if NbSlice is active
1657if isempty(incr_i)&& ~isempty(Param.IndexRange.NbSlice)
1658    incr_i=1;
1659    set(handles.num_incr_i,'String','1')
1660end
1661if isempty(incr_i)
1662    if isempty(incr_j)
1663        [ref_j,ref_i]=find(squeeze(SeriesData.i1_series{1}(1,:,:)));
1664        ref_j=ref_j(ref_j>=first_j & ref_j<=last_j);
1665        ref_i=ref_i(ref_i>=first_i & ref_i<=last_i);
1666        ref_j=ref_j-1;
1667        ref_i=ref_i-1;
1668    else
1669        ref_j=first_j:incr_j:last_j;
1670        [tild,ref_i]=find(squeeze(SeriesData.i1_series{1}(1,:,:)));
1671        ref_i=ref_i-1;
1672        ref_i=ref_i(ref_i>=first_i & ref_i<=last_i);
1673    end
1674else
1675    ref_i=first_i:incr_i:last_i;
1676    if isempty(incr_j)
1677        [ref_j,tild]=find(squeeze(SeriesData.i1_series{1}(1,:,:)));
1678        ref_j=ref_j-1;
1679        ref_j=ref_j(ref_j>=first_j & ref_j<=last_j);
1680    else
1681        ref_j=first_j:incr_j:last_j;
1682    end
1683end
1684BlockLength=ceil(numel(ref_i)/NbProcess);
1685nbfield_j=numel(ref_j);
1686
1687%% record nbre of output files and starting time for computation for status
1688StatusData=get(handles.status,'UserData');
1689if isfield(StatusData,'OutputFileMode')
1690    switch StatusData.OutputFileMode
1691        case 'NbInput'
1692            StatusData.NbOutputFile=numel(ref_i)*nbfield_j;
1693        case 'NbInput_i'
1694            StatusData.NbOutputFile=numel(ref_i);
1695        case 'NbSlice'   
1696            StatusData.NbOutputFile=str2num(get(handles.num_NbSlice,'String'));
1697    end
1698end
1699StatusData.TimeStart=now;
1700set(handles.status,'UserData',StatusData)
1701
1702
1703if strcmp(ActionExt, '.py (in dev.)')
1704    fprintf([
1705        '\n' ...
1706        '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' ...
1707        'The option .py is used. It is still in development.\n' ...
1708        'Do not use it unless you really know what you do!\n' ...
1709        'To try it, first install Pyp and the most recent version of FluidDyn.\n' ...
1710        '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'])
1711    RunMode = 'python';
1712    t = struct2xml(Param);
1713    t = set(t, 1, 'name', 'Series');
1714    filexml = fullfile_uvmat(DirXml, '', Param.InputTable{1,3}, '.xml', OutputNomType,...
1715         Param.IndexRange.first_i, Param.IndexRange.last_i, first_j, last_j);
1716    save(t, filexml);
1717end
1718
1719
1720%% direct processing on the current Matlab session
1721if strcmp (RunMode,'local')
1722    for iprocess=1:NbProcess
1723        if isempty(Param.IndexRange.NbSlice)
1724            %Param.IndexRange.first_i=first_i+(iprocess-1)*BlockLength*incr_i;
1725            Param.IndexRange.first_i=ref_i(1+(iprocess-1)*BlockLength);
1726            if Param.IndexRange.first_i>last_i
1727                break
1728            end
1729            Param.IndexRange.last_i=min(ref_i(iprocess*BlockLength),last_i);
1730            %Param.IndexRange.last_i=min(first_i+(iprocess)*BlockLength*incr_i-1,last_i);
1731        else %multislices (then incr_i is not empty)
1732             Param.IndexRange.first_i= first_i+incr_i*(iprocess-1);
1733             Param.IndexRange.incr_i=incr_i*Param.IndexRange.NbSlice;
1734        end
1735        if isfield(Param,'OutputSubDir')
1736        t=struct2xml(Param);
1737        t=set(t,1,'name','Series');
1738        filexml=fullfile_uvmat(DirXml,'',Param.InputTable{1,3},'.xml',OutputNomType,...
1739            Param.IndexRange.first_i,Param.IndexRange.last_i,first_j,last_j);
1740        save(t,filexml);
1741        end
1742        switch ActionExt
1743            case '.m'
1744                h_fun(Param);
1745            case '.sh'
1746                switch computer
1747                    case {'PCWIN','PCWIN64'} %Windows system
1748                        filexml=regexprep(filexml,'\\','\\\\');% add '\' so that '\' are left as characters
1749                        system([fullfile(ActionPath,[ActionName '.sh']) ' ' RunTime ' ' filexml]);% TODO: adapt to DOS system
1750                    case {'GLNX86','GLNXA64','MACI64'}%Linux  system
1751                        system([fullfile(ActionPath,[ActionName '.sh']) ' ' RunTime ' ' filexml]);
1752                end
1753        end
1754    end
1755elseif ~strcmp(RunMode,'python')
1756    %% processing on a different session of the same computer (background) or cluster, create executable files
1757    batch_file_list=cell(NbProcess,1);% initiate the list of executable files
1758    DirBat=fullfile(OutputDir,'0_EXE');
1759    switch computer
1760        case {'PCWIN','PCWIN64'} %Windows system
1761            ExeExt='.bat';
1762        case {'GLNX86','GLNXA64','MACI64'}%Linux  system
1763           ExeExt='.sh';
1764    end
1765    %create subdirectory for executable files
1766    if ~exist(DirBat,'dir')
1767        [tild,msg1]=mkdir(DirBat);
1768        if ~strcmp(msg1,'')
1769            errormsg=['cannot create ' DirBat ': ' msg1];%error message for directory creation
1770            return
1771        end
1772    end
1773    %create subdirectory for log files
1774    DirLog=fullfile(OutputDir,'0_LOG');
1775    if ~exist(DirLog,'dir')
1776        [tild,msg1]=mkdir(DirLog);
1777        if ~strcmp(msg1,'')
1778            errormsg=['cannot create ' DirLog ': ' msg1];%error message for directory creation
1779            return
1780        end
1781    end
1782    for iprocess=1:NbProcess
1783        if isempty(Param.IndexRange.NbSlice)% process by blocks of i index
1784            Param.IndexRange.first_i=first_i+(iprocess-1)*BlockLength*incr_i;
1785            if Param.IndexRange.first_i>last_i
1786                NbProcess=iprocess-1;
1787                break% leave the loop, we are at the end of the calculation
1788            end
1789            Param.IndexRange.last_i=min(last_i,first_i+(iprocess)*BlockLength*incr_i-1);
1790        else% process by slices of i index if NbSlice is defined, computation in a single process if NbSlice =1
1791            Param.IndexRange.first_i= first_i+iprocess-1;
1792            Param.IndexRange.incr_i=incr_i*Param.IndexRange.NbSlice;
1793        end
1794        for ilist=1:size(Param.InputTable,1)
1795        Param.InputTable{ilist,1}=regexprep(Param.InputTable{ilist,1},'\','/');%correct path name for PCWIN system
1796        end
1797        % create, fill and save the xml parameter file
1798        t=struct2xml(Param);
1799        t=set(t,1,'name','Series');
1800        filexml=fullfile_uvmat(DirXml,'',Param.InputTable{1,3},'.xml',OutputNomType,...
1801            Param.IndexRange.first_i,Param.IndexRange.last_i,first_j,last_j);
1802        save(t,filexml);% save the parameter file
1803       
1804        %create the executable file
1805         filebat=fullfile_uvmat(DirBat,'',Param.InputTable{1,3},ExeExt,OutputNomType,...
1806           Param.IndexRange.first_i,Param.IndexRange.last_i,first_j,last_j);
1807        batch_file_list{iprocess}=filebat;
1808        [fid,message]=fopen(filebat,'w');% create the executable file
1809        if isequal(fid,-1)
1810            errormsg=['creation of .bat file: ' message];
1811            return
1812        end
1813       
1814        % set the log file name
1815        filelog=fullfile_uvmat(DirLog,'',Param.InputTable{1,3},'.log',OutputNomType,...
1816            Param.IndexRange.first_i,Param.IndexRange.last_i,first_j,last_j);
1817       
1818        % fill and save the executable file
1819        switch ActionExt
1820            case '.m'% Matlab function
1821                switch computer
1822                    case {'GLNX86','GLNXA64','MACI64'}
1823                        cmd=[...
1824                            '#!/bin/bash \n'...
1825                            '. /etc/sysprofile \n'...
1826                            'matlab -nodisplay -nosplash -nojvm -logfile ''' filelog ''' <<END_MATLAB \n'...
1827                            'addpath(''' path_series '''); \n'...
1828                            'addpath(''' Param.Action.ActionPath '''); \n'...
1829                            '' Param.Action.ActionName  '( ''' filexml '''); \n'...
1830                            'exit \n'...
1831                            'END_MATLAB \n'];
1832                        fprintf(fid,cmd);%fill the executable file with the  char string cmd
1833                        fclose(fid);% close the executable file
1834                        system(['chmod +x ' filebat]);% set the file to executable
1835                    case {'PCWIN','PCWIN64'}
1836                        text_matlabscript=['matlab -automation -logfile ' regexprep(filelog,'\\','\\\\')...
1837                            ' -r "addpath(''' regexprep(path_series,'\\','\\\\') ''');'...
1838                            'addpath(''' regexprep(Param.Action.ActionPath,'\\','\\\\') ''');'...
1839                            '' Param.Action.ActionName  '( ''' regexprep(filexml,'\\','\\\\') ''');exit"'];
1840                        fprintf(fid,text_matlabscript);%fill the executable file with the  char string cmd
1841                        fclose(fid);% close the executable file
1842                end
1843            case '.sh' % compiled Matlab function
1844                switch computer
1845                    case {'GLNX86','GLNXA64','MACI64'}
1846                        cmd=['#!/bin/bash \n '...
1847                            '#$ -cwd \n '...
1848                            'hostname && date \n '...
1849                            'umask 002 \n'...
1850                            fullfile(ActionPath,[ActionName '.sh']) ' ' RunTime ' ' filexml];%allow writting access to created files for user group
1851                        fprintf(fid,cmd);%fill the executable file with the  char string cmd
1852                        fclose(fid);% close the executable file
1853                        system(['chmod +x ' filebat]);% set the file to executable
1854                       
1855                    case {'PCWIN','PCWIN64'}   
1856                        fprintf(fid,cmd);
1857                        fclose(fid);
1858                end
1859        end
1860    end
1861end
1862
1863%% launch the executable files for background or cluster processing
1864switch RunMode
1865    case 'background'
1866        for iprocess=1:NbProcess
1867            system([batch_file_list{iprocess} ' &'])% directly execute the command file for each process
1868            msgbox_uvmat('CONFIRMATION',[ActionName ' launched in background: press STATUS to see results'])
1869        end
1870    case 'cluster_oar' % option 'oar-parexec' used
1871        %create subdirectory for oar command and log files
1872        DirOAR=fullfile(OutputDir,'0_OAR');
1873        if exist(DirOAR,'dir')% delete the content of the dir 0_OAR to allow new input
1874            curdir=pwd;
1875            cd(DirOAR)
1876            delete('*')
1877            cd(curdir)
1878        else
1879            [tild,msg1]=mkdir(DirOAR);
1880            if ~strcmp(msg1,'')
1881                errormsg=['cannot create ' DirOAR ': ' msg1];%error message for directory creation
1882                return
1883            end
1884        end
1885        max_walltime=3600*20; % 20h max total calculation (cannot exceed 24 h)
1886        walltime_onejob=600;%seconds, max estimated time for asingle file index value
1887        filename_joblist=fullfile(DirOAR,'job_list.txt');%create name of the global executable file
1888        fid=fopen(filename_joblist,'w');
1889        for p=1:length(batch_file_list)
1890            fprintf(fid,[batch_file_list{p} '\n']);% list of exe files
1891        end
1892        fclose(fid);
1893        system(['chmod +x ' filename_joblist]);% set the file to executable
1894        oar_command=['oarsub -n CIVX '...
1895            '-t idempotent --checkpoint ' num2str(walltime_onejob+60) ' '...
1896            '-l /core=' num2str(NbCore) ','...
1897            'walltime=' datestr(min(1.05*walltime_onejob/86400*max(NbProcess*BlockLength*nbfield_j,NbCore)/NbCore,max_walltime/86400),13) ' '...
1898            '-E ' regexprep(filename_joblist,'\.txt\>','.stderr') ' '...
1899            '-O ' regexprep(filename_joblist,'\.txt\>','.stdout') ' '...
1900            extra_oar ' '...
1901            '"oar-parexec -s -f ' filename_joblist ' '...
1902            '-l ' filename_joblist '.log"\n'];
1903        filename_oarcommand=fullfile(DirOAR,'oar_command');
1904        fid=fopen(filename_oarcommand,'w');
1905        fprintf(fid,oar_command);
1906        fclose(fid);
1907        fprintf(oar_command);% display in command line
1908        system(oar_command); 
1909        msgbox_uvmat('CONFIRMATION',[ActionName ' launched in cluster: press STATUS to see results'])
1910    case 'cluster_pbs' % for LMFA Kepler machine
1911        %create subdirectory for pbs command and log files
1912        DirPBS=fullfile(OutputDir,'0_PBS'); %todo : common name OAR/PBS
1913        if exist(DirPBS,'dir')% delete the content of the dir 0_OAR to allow new input
1914            curdir=pwd;
1915            cd(DirPBS)
1916            delete('*')
1917            cd(curdir)
1918        else
1919            [tild,msg1]=mkdir(DirPBS);
1920            if ~strcmp(msg1,'')
1921                errormsg=['cannot create ' DirPBS ': ' msg1];%error message for directory creation
1922                return
1923            end
1924        end
1925        max_walltime=3600*20; % 20h max total calculation (cannot exceed 24 h)
1926        walltime_onejob=600;%seconds, max estimated time for asingle file index value
1927        filename_joblist=fullfile(DirPBS,'job_list.txt');%create name of the global executable file
1928        fid=fopen(filename_joblist,'w');
1929        for p=1:length(batch_file_list)
1930            fprintf(fid,[batch_file_list{p} '\n']);% list of exe files
1931        end
1932        fclose(fid);
1933        system(['chmod +x ' filename_joblist]);% set the file to executable
1934        pbs_command=['qstat -n CIVX '...
1935            '-t idempotent --checkpoint ' num2str(walltime_onejob+60) ' '...
1936            '-l /core=' num2str(NbCore) ','...
1937            'walltime=' datestr(min(1.05*walltime_onejob/86400*max(NbProcess*BlockLength*nbfield_j,NbCore)/NbCore,max_walltime/86400),13) ' '...
1938            '-E ' regexprep(filename_joblist,'\.txt\>','.stderr') ' '...
1939            '-O ' regexprep(filename_joblist,'\.txt\>','.stdout') ' '...
1940            extra_oar ' '...
1941            '"oar-parexec -s -f ' filename_joblist ' '...
1942            '-l ' filename_joblist '.log"\n'];
1943        filename_oarcommand=fullfile(DirPBS,'pbs_command');
1944        fid=fopen(filename_oarcommand,'w');
1945        fprintf(fid,pbs_command);
1946        fclose(fid);
1947        fprintf(pbs_command);% display in command line
1948        %system(pbs_command); 
1949        msgbox_uvmat('CONFIRMATION',[ActionName ' command ready to be launched in cluster'])       
1950    case 'python'
1951        command = [
1952            'LD_LIBRARY_PATH=$(echo $LD_LIBRARY_PATH | pyp "p.split('':'') | [s for s in p if ''matlab'' not in s] | '':''.join(p)") ' ...
1953            'python -m fluiddyn.postproc.uvmat ' filexml];
1954        % fprintf(['command:\n' command '\n\n'])
1955        system(command, '-echo');
1956end
1957
1958%------------------------------------------------------------------------
1959function STOP_Callback(hObject, eventdata, handles)
1960%------------------------------------------------------------------------
1961set(handles.RUN, 'BusyAction','cancel')
1962set(handles.RUN,'BackgroundColor',[1 0 0])
1963set(handles.RUN,'enable','on')
1964set(handles.RUN, 'Value',0)
1965
1966
1967%------------------------------------------------------------------------
1968% --- read parameters from the GUI series
1969%------------------------------------------------------------------------
1970function Param=read_GUI_series(handles)
1971
1972%% read raw parameters from the GUI series
1973Param=read_GUI(handles.series);
1974
1975%% clean the output structure by removing unused information
1976if isfield(Param,'Pairs')
1977    Param=rmfield(Param,'Pairs'); %info Pairs not needed for output
1978end
1979if isfield(Param,'InputLine')
1980    Param=rmfield(Param,'InputLine');
1981end
1982if isfield(Param,'EditObject')
1983    Param=rmfield(Param,'EditObject');
1984end
1985Param.IndexRange.TimeSource=Param.IndexRange.TimeTable{end,1};
1986Param.IndexRange=rmfield(Param.IndexRange,'TimeTable');
1987empty_line=false(size(Param.InputTable,1),1);
1988for iline=1:size(Param.InputTable,1)
1989    empty_line(iline)=isempty(cell2mat(Param.InputTable(iline,1:3)));
1990end
1991Param.InputTable(empty_line,:)=[];
1992
1993%------------------------------------------------------------------------
1994% --- Executes on selection change in ActionName.
1995function ActionName_Callback(hObject, eventdata, handles)
1996%------------------------------------------------------------------------
1997
1998%% stop any ongoing series processing
1999if isequal(get(handles.RUN,'Value'),1)
2000    answer= msgbox_uvmat('INPUT_Y-N','stop current Action process?');
2001    if strcmp(answer,'Yes')
2002        STOP_Callback(hObject, eventdata, handles)
2003    else
2004        return
2005    end
2006end
2007set(handles.ActionName,'BackgroundColor',[1 1 0])
2008huigetfile=findobj(allchild(0),'tag','status_display');
2009if ~isempty(huigetfile)
2010    delete(huigetfile)
2011end
2012drawnow
2013
2014%% check whether the input file(s) need to be refreshed
2015% SeriesData=get(handles.series,'UserData');%hidden parameters
2016% if ~isfield(SeriesData,'i1_series')
2017%     msgbox_uvmat('ERROR','The input field series needs to be refreshed: press REFRESH');
2018%     return
2019% end
2020
2021%% get Action name and path
2022NbBuiltinAction=get(handles.Action,'UserData'); %nbre of functions initially proposed in the menu ActionName (as defined in the Opening fct of series)
2023ActionList=get(handles.ActionName,'String');% list menu fields
2024ActionIndex=get(handles.ActionName,'Value');
2025if ~isequal(ActionIndex,1)% if we are not just opening series
2026    InputTable=get(handles.InputTable,'Data');
2027    if isempty(InputTable{1,4})
2028        msgbox_uvmat('ERROR','no input file available: use Open in the menu bar')
2029        return
2030    end
2031end
2032ActionName= ActionList{get(handles.ActionName,'Value')}; % selected function name
2033ActionPathList=get(handles.ActionName,'UserData');%list of recorded paths to functions of the list ActionName
2034
2035%% add a new function to the menu if 'more...' has been selected in the menu ActionName
2036if isequal(ActionName,'more...')
2037    [FileName, PathName] = uigetfile( ...
2038        {'*.m', ' (*.m)';
2039        '*.m',  '.m files '; ...
2040        '*.*', 'All Files (*.*)'}, ...
2041        'Pick a series processing function ',get(handles.ActionPath,'String'));
2042    if length(FileName)<2
2043        return
2044    end
2045    [tild,ActionName,ActionExt]=fileparts(FileName);
2046   
2047    % insert the choice in the menu ActionName
2048    ActionIndex=find(strcmp(ActionName,ActionList),1);% look for the selected function in the menu Action
2049    PathName=regexprep(PathName,'/$','');
2050    if ~isempty(ActionIndex) && ~strcmp(ActionPathList{ActionIndex},PathName)%compare the path to the existing fct
2051        ActionIndex=[]; % the selected path is different than the recorded one
2052    end
2053    if isempty(ActionIndex)%the qselected fct (with selected path) does not exist in the menu
2054        ActionIndex= length(ActionList);
2055        ActionList=[ActionList(1:end-1);{ActionName};ActionList(end)];% the selected function is appended in the menu, before the last item 'more...'
2056         ActionPathList=[ActionPathList; PathName];
2057    end
2058   
2059    % record the file extension and extend the path list if it is a new extension
2060%     ActionExtList=get(handles.ActionExt,'String');
2061%     ActionExtIndex=find(strcmp(ActionExt,ActionExtList), 1);
2062%     if isempty(ActionExtIndex)
2063%         set(handles.ActionExt,'String',[ActionExtList;{ActionExt}])
2064%     end
2065
2066    % remove old Action options in the menu (keeping a menu length <nb_builtin_ACTION+5)
2067    if length(ActionList)>NbBuiltinAction+5; %nb_builtin_ACTION=nbre of functions always remaining in the initial menu
2068        nbremove=length(ActionList)-NbBuiltinAction-5;
2069        ActionList(NbBuiltinAction+1:end-5)=[];
2070        ActionPathList(NbBuiltinAction+1:end-4,:)=[];
2071        ActionIndex=ActionIndex-nbremove;
2072    end
2073   
2074    % record action menu, choice and path
2075    set(handles.ActionName,'Value',ActionIndex)
2076    set(handles.ActionName,'String',ActionList)
2077       set(handles.ActionName,'UserData',ActionPathList);
2078    set(handles.ActionExt,'Value',ActionExtIndex)
2079%     ActionPathList{ActionIndex,ActionExtIndex}=PathName;
2080       
2081    %record the user defined menu additions in personal file profil_perso
2082    dir_perso=prefdir;
2083    profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
2084    if NbBuiltinAction+1<=numel(ActionList)-1
2085        ActionListUser=ActionList(NbBuiltinAction+1:numel(ActionList)-1);
2086        ActionPathListUser=ActionPathList(NbBuiltinAction+1:numel(ActionList)-1);
2087%         ActionExtListUser={};
2088%         if numel(ActionExtList)>2
2089%             ActionExtListUser=ActionExtList(3:end);
2090%         end
2091        if exist(profil_perso,'file')
2092            save(profil_perso,'ActionListUser','ActionPathListUser','ActionExtListUser','-append')
2093        else
2094            save(profil_perso,'ActionListUser','ActionPathListUser','ActionExtListUser','-V6')
2095        end
2096    end
2097end
2098
2099%% check the current ActionPath to the selected function
2100ActionPath=ActionPathList{ActionIndex};%current recorded path
2101set(handles.ActionPath,'String',ActionPath); %show the path to the senlected function
2102
2103%% reinitialise the waitbar
2104update_waitbar(handles.Waitbar,0)
2105
2106%% create the function handle for Action
2107path_series=which('series');
2108if ~isequal(ActionPath,path_series)
2109    eval(['spath=which(''' ActionName ''');']) %spath = current path of the selected function ACTION
2110    if ~exist(ActionPath,'dir')
2111        errormsg=['The prescribed function path ' ActionPath ' does not exist'];
2112        return
2113    end
2114    if ~isequal(spath,ActionPath)
2115        addpath(ActionPath)% add the prescribed path if not the current one
2116    end
2117end
2118eval(['h_fun=@' ActionName ';'])%create a function handle for ACTION
2119if ~isequal(ActionPath,path_series)
2120        rmpath(ActionPath)% add the prescribed path if not the current one   
2121end
2122
2123%% Activate the Action fct to adapt the configuration of the GUI series and bring specific parameters in SeriesData
2124Param=read_GUI_series(handles);% read the parameters from the GUI series
2125ParamOut=h_fun(Param);%run the selected Action function to get the relevant input
2126
2127%% Put the first line of the selected Action fct as tooltip help
2128try
2129    [fid,errormsg] =fopen([ActionName '.m']);
2130    InputText=textscan(fid,'%s',1,'delimiter','\n');
2131    fclose(fid);
2132    set(handles.ActionName,'ToolTipString',InputText{1}{1})% put the first line of the selected function as tooltip help
2133end
2134
2135
2136%% Visibility of VelType and VelType_1 menus asked by ActionName
2137VelTypeRequest=1;%VelType requested by default
2138VelTypeRequest_1=1;%VelType requested by default
2139if isfield(ParamOut,'VelType')
2140    VelTypeRequest=ismember(ParamOut.VelType,{'on','one','two'});
2141    VelTypeRequest_1=strcmp( ParamOut.VelType,'two');
2142end
2143FieldNameRequest=0;  %hidden by default
2144FieldNameRequest_1=0;  %hidden by default
2145if isfield(ParamOut,'FieldName')
2146    FieldNameRequest=ismember(ParamOut.FieldName,{'on','one','two'});
2147    FieldNameRequest_1=strcmp( ParamOut.FieldName,'two');
2148end
2149
2150%% Detect the types of input files and set menus and default options in 'VelType'
2151SeriesData=get(handles.series,'UserData');% info on the input file series
2152iview_civ=find(strcmp('civx',SeriesData.FileType)|strcmp('civdata',SeriesData.FileType));
2153iview_netcdf=find(strcmp('netcdf',SeriesData.FileType)|strcmp('civx',SeriesData.FileType)|strcmp('civdata',SeriesData.FileType));% all nc files, icluding civ
2154FieldList=get(handles.FieldName,'String');% previous list as default
2155if ~iscell(FieldList),FieldList={FieldList};end
2156FieldList_1=get(handles.FieldName_1,'String');% previous list as default
2157if ~iscell(FieldList_1),FieldList_1={FieldList_1};end
2158CheckList=0;% indicate whether FieldName has been updated
2159CheckList_1=1;% indicate whether FieldName_1 has been updated
2160handles_coord=[handles.Coord_x handles.Coord_y handles.Coord_z handles.Coord_x_title handles.Coord_y_title handles.Coord_z_title];
2161if VelTypeRequest && numel(iview_civ)>=1
2162    menu=set_veltype_display(SeriesData.FileInfo{iview_civ(1)}.CivStage,SeriesData.FileType{iview_civ(1)});
2163    set(handles.VelType,'Value',1)% set first choice by default
2164    set(handles.VelType,'String',[{'*'};menu])
2165    set(handles.VelType,'Visible','on')
2166    set(handles.VelType_title,'Visible','on')
2167    FieldList=[set_field_list('U','V');{'C'};{'get_field...'}];%standard menu for civx data
2168    CheckList=1;
2169    set(handles.FieldName,'Value',1); %velocity vector choice by default
2170    if  VelTypeRequest_1 && numel(iview_civ)>=2
2171        menu=set_veltype_display(SeriesData.FileInfo{iview_civ(2)}.CivStage,SeriesData.FileType{iview_civ(2)});
2172        set(handles.VelType_1,'Value',1)% set first choice by default
2173        set(handles.VelType_1,'String',[{'*'};menu])
2174        set(handles.VelType_1,'Visible','on')
2175        set(handles.VelType_title_1,'Visible','on')
2176        FieldList_1=[set_field_list('U','V');{'C'};{'get_field...'}];%standard menu for civx data
2177        CheckList_1=1;
2178        set(handles.FieldName_1,'Value',1); %velocity vector choice by default
2179    else
2180        set(handles.VelType_1,'Visible','off')
2181        set(handles.VelType_title_1,'Visible','off')
2182    end
2183else
2184    set(handles.VelType,'Visible','off')
2185    set(handles.VelType_title,'Visible','off')
2186end   
2187
2188%% Detect the types of input files and set menus and default options in 'FieldName'
2189if FieldNameRequest && numel(iview_netcdf)>=1
2190    set(handles.InputFields,'Visible','on')
2191    %if CheckList==0        % not civ input made
2192        if isfield(SeriesData.FileInfo{iview_netcdf(1)},'ListVarName')
2193        ListVarName=SeriesData.FileInfo{iview_netcdf(1)}.ListVarName;
2194        ind_var=get(handles.FieldName,'Value');%indices of previously selected variables
2195        for ilist=1:numel(ind_var)
2196            if isempty(find(strcmp(FieldList{ind_var(ilist)},ListVarName)))
2197                FieldList={};% previous choice not consistent with new input field
2198                set(handles.FieldName,'Value',1)
2199                break
2200            end
2201        end
2202        if ~isempty(FieldList)
2203            if isempty(find(strcmp(get(handles.Coord_x,'String'),ListVarName)))||...
2204                    isempty(find(strcmp(get(handles.Coord_y,'String'),ListVarName)))
2205                FieldList={};
2206                set(handles.Coord_x,'String','')
2207                set(handles.Coord_y,'String','')
2208            end
2209            Coord_z=get(handles.Coord_z,'String');
2210            if ~isempty(Coord_z) && isempty(find(strcmp(Coord_z,ListVarName)))
2211                FieldList={};
2212                set(handles.Coord_z,'String','')
2213            end
2214        end
2215        set(handles_coord,'Visible','on')
2216        FieldList=[FieldList;{'get_field...'}];
2217        if FieldNameRequest_1 && numel(iview_netcdf)>=2
2218            set(handles.FieldName_1,'Visible','on')
2219            if CheckList_1==0        % not civ input made
2220                ListVarName=SeriesData.FileInfo{iview_netcdf(2)}.ListVarName;
2221                ind_var=get(handles.FieldName,'Value');%indices of previously selected variables
2222                for ilist=1:numel(ind_var)
2223                    if isempty(find(strcmp(FieldList{ind_var(ilist)},ListVarName)))
2224                        FieldList_1={};% previous choice not consistent with new input field
2225                        set(handles.FieldName_1,'Value',1)
2226                        break
2227                    end
2228                end
2229                warn_coord=0;
2230                if isempty(find(strcmp(get(handles.Coord_x,'String'),ListVarName)))||...
2231                        isempty(find(strcmp(get(handles.Coord_y,'String'),ListVarName)))
2232                    warn_coord=1;
2233                end
2234                if ~isempty(Coord_z) && isempty(find(strcmp(Coord_z,ListVarName)))
2235                    FieldList_1={};
2236                    warn_coord=1;
2237                end
2238                if warn_coord
2239                    msgbox_uvmat('WARNING','coordiante names do not exist in the second netcdf input file')
2240                end
2241                set(handles.FieldName,'String',[FieldList;{'get_field...'}])
2242                set(handles.FieldName_1,'Visible','on')
2243                set(handles.FieldName_1,'Value',1)
2244                set(handles.FieldName_1,'String',FieldList_1)
2245            end
2246        else
2247            set(handles.FieldName_1,'Visible','off')
2248        end
2249        end
2250%     else
2251%         set(handles_coord,'Visible','off')% no coord display for civ data
2252%     end
2253    set(handles.FieldName,'String',FieldList)
2254else
2255    set(handles.InputFields,'Visible','off')
2256end
2257
2258
2259%% Check whether alphabetical sorting of input Subdir is allowed by the Action fct  (for multiples series entries)
2260if isfield(ParamOut,'AllowInputSort')&&isequal(ParamOut.AllowInputSort,'on')&& size(Param.InputTable,1)>1
2261    [tild,iview]=sort(InputTable(:,2)); %subdirectories sorted in alphabetical order
2262    set(handles.InputTable,'Data',InputTable(iview,:));
2263    MinIndex_i=get(handles.MinIndex_i,'Data');
2264    MinIndex_j=get(handles.MinIndex_j,'Data');
2265    MaxIndex_i=get(handles.MaxIndex_i,'Data');
2266    MaxIndex_j=get(handles.MaxIndex_j,'Data');
2267    set(handles.MinIndex_i,'Data',MinIndex_i(iview,:));
2268    set(handles.MinIndex_j,'Data',MinIndex_j(iview,:));
2269    set(handles.MaxIndex_i,'Data',MaxIndex_i(iview,:));
2270    set(handles.MaxIndex_j,'Data',MaxIndex_j(iview,:));
2271    TimeTable=get(handles.TimeTable,'Data');
2272    set(handles.TimeTable,'Data',TimeTable(iview,:));
2273    PairString=get(handles.PairString,'Data');
2274    set(handles.PairString,'Data',PairString(iview,:));
2275end
2276
2277%% Impose the whole input file index range if requested
2278if isfield(ParamOut,'WholeIndexRange')&&isequal(ParamOut.WholeIndexRange,'on')
2279    MinIndex_i=get(handles.MinIndex_i,'Data');
2280    MinIndex_j=get(handles.MinIndex_j,'Data');
2281    MaxIndex_i=get(handles.MaxIndex_i,'Data');
2282    MaxIndex_j=get(handles.MaxIndex_j,'Data');
2283    set(handles.num_first_i,'String',num2str(MinIndex_i(1)))% set first as the min index (for the first line)
2284    set(handles.num_last_i,'String',num2str(MaxIndex_i(1)))% set last as the max index (for the first line)
2285    set(handles.num_incr_i,'String','1')
2286    set(handles.num_first_j,'String',num2str(MinIndex_j(1)))% set first as the min index (for the first line)
2287    set(handles.num_last_j,'String',num2str(MaxIndex_j(1)))% set last as the max index (for the first line)
2288    set(handles.num_incr_j,'String','1')
2289else  % check index ranges
2290    first_i=1;last_i=1;first_j=1;last_j=1;
2291    if isfield(Param.IndexRange,'first_i')
2292        first_i=Param.IndexRange.first_i;
2293        last_i=Param.IndexRange.last_i;
2294    end
2295    if isfield(Param.IndexRange,'first_j')
2296        first_j=Param.IndexRange.first_j;
2297        last_j=Param.IndexRange.last_j;
2298    end
2299    if last_i < first_i || last_j < first_j , msgbox_uvmat('ERROR','last field number must be larger than the first one'),...
2300            set(handles.RUN, 'Enable','On'), set(handles.RUN,'BackgroundColor',[1 0 0]),return,end;
2301end
2302
2303%% enable or desable j index visibility
2304status_j='on';%default
2305if isfield(ParamOut,'Desable_j_index')&&isequal(ParamOut.Desable_j_index,'on')
2306    status_j='off';
2307end
2308if isempty(find(~cellfun(@isempty,SeriesData.j1_series), 1)); % case of empty j indices
2309    status_j='off'; % no j index needed
2310elseif strcmp(get(handles.PairString,'Visible'),'on')
2311    check_burst=cellfun(@isempty,regexp(get(handles.PairString,'Data'),'^j'));%=0 for burst case, 1 otherwise
2312    if isempty(find(check_burst, 1))% if all pair string begins by j (burst)
2313        status_j='off'; % no j index needed for bust case
2314    end
2315end
2316enable_j(handles,status_j) % no j index needed
2317
2318
2319%% NbSlice visibility
2320NbSliceVisible='off';%default
2321if isfield(ParamOut,'NbSlice') && isequal(ParamOut.NbSlice,'on')
2322    NbSliceVisible='on';
2323    set(handles.num_NbProcess,'String',get(handles.num_NbSlice,'String'))% the nbre of processes is imposed as the nbre of slices
2324else
2325    set(handles.num_NbProcess,'String','')% free nbre of processes
2326end
2327set(handles.num_NbSlice,'Visible',NbSliceVisible)
2328set(handles.NbSlice_title,'Visible',NbSliceVisible)
2329
2330
2331
2332%% Visibility of FieldTransform menu
2333FieldTransformVisible='off';  %hidden by default
2334if isfield(ParamOut,'FieldTransform')
2335    FieldTransformVisible=ParamOut.FieldTransform; 
2336    TransformName_Callback([],[], handles)
2337end
2338set(handles.FieldTransform,'Visible',FieldTransformVisible)
2339if isfield(ParamOut,'TransformPath')
2340    set(handles.ActionExt,'UserData',ParamOut.TransformPath)
2341else
2342    set(handles.ActionExt,'UserData',[])
2343end
2344
2345%% Visibility of projection object
2346ProjObjectVisible='off';  %hidden by default
2347if isfield(ParamOut,'ProjObject')
2348    ProjObjectVisible=ParamOut.ProjObject;
2349end
2350set(handles.CheckObject,'Visible',ProjObjectVisible)
2351if ~get(handles.CheckObject,'Value')
2352    ProjObjectVisible='off';
2353end
2354set(handles.ProjObject,'Visible',ProjObjectVisible)
2355set(handles.DeleteObject,'Visible',ProjObjectVisible)
2356set(handles.ViewObject,'Visible',ProjObjectVisible)
2357set(handles.EditObject,'Visible',ProjObjectVisible)
2358
2359%% Visibility of mask input
2360MaskVisible='off';  %hidden by default
2361if isfield(ParamOut,'Mask')
2362    MaskVisible=ParamOut.Mask;
2363end
2364set(handles.CheckMask,'Visible',MaskVisible);
2365
2366%% definition of the directory containing the output files
2367if  ~(isfield(SeriesData,'ActionName') && strcmp(ActionName,SeriesData.ActionName))
2368    OutputDirExt='.series'; %default
2369    if isfield(ParamOut,'OutputDirExt')&&~isempty(ParamOut.OutputDirExt)
2370        OutputDirExt=ParamOut.OutputDirExt;
2371    end
2372    set(handles.OutputDirExt,'String',OutputDirExt)
2373end
2374OutputDirVisible='off';
2375OutputSubDirMode='auto';%default
2376SubDirOut='';
2377if isfield(ParamOut,'OutputSubDirMode')
2378    OutputSubDirMode=ParamOut.OutputSubDirMode;
2379end
2380switch OutputSubDirMode
2381    case 'auto';%default
2382        OutputDirVisible='on';
2383        SubDir=InputTable(1:end,2); %set of subdirectories
2384        SubDirOut=SubDir{1};
2385        if numel(SubDir)>1
2386            for ilist=2:numel(SubDir)
2387                SubDirOut=[SubDirOut '-' regexprep(SubDir{ilist},'^/','')];
2388            end
2389        end
2390    case 'one'
2391        OutputDirVisible='on';
2392        SubDirOut=InputTable{1,2}; %use the first subdir name (+OutputDirExt) as output  subdirectory
2393    case 'two'
2394        OutputDirVisible='on';   
2395        SubDir=InputTable(1:2,2); %set of subdirectories
2396        SubDirOut=SubDir{1};
2397        if numel(SubDir)>1
2398                SubDirOut=[SubDirOut '-' regexprep(SubDir{2},'^/','')];
2399        end
2400    case 'last'
2401        OutputDirVisible='on';
2402        SubDirOut=InputTable{end,2}; %use the last subdir name (+OutputDirExt) as output  subdirectory
2403end
2404set(handles.OutputSubDir,'String',SubDirOut)
2405set(handles.OutputDirExt,'Visible',OutputDirVisible)
2406set(handles.OutputSubDir,'Visible',OutputDirVisible)
2407set(handles.OutputDir_title,'Visible',OutputDirVisible)
2408SeriesData.ActionName=ActionName;%record ActionName for next use
2409
2410
2411%% visibility of the run mode (local or background or cluster)
2412if strcmp(OutputSubDirMode,'none')
2413    RunModeVisible='off';% only local mode available if no output file is produced
2414else
2415    RunModeVisible='on';
2416end
2417set(handles.RunMode,'Visible',RunModeVisible)
2418set(handles.ActionExt,'Visible',RunModeVisible)
2419set(handles.RunMode_title,'Visible',RunModeVisible)
2420set(handles.ActionExt_title,'Visible',RunModeVisible)
2421
2422
2423%% Expected nbre of output files
2424if isfield(ParamOut,'OutputFileMode')
2425    StatusData.OutputFileMode=ParamOut.OutputFileMode;
2426    set(handles.status,'UserData',StatusData)
2427end
2428
2429%% definition of an additional parameter set, determined by an ancillary GUI
2430if isfield(ParamOut,'ActionInput')
2431    set(handles.ActionInput,'Visible','on')
2432    ParamOut.ActionInput.Program=ActionName; % record the program in ActionInput
2433    SeriesData.ActionInput=ParamOut.ActionInput;
2434else
2435    set(handles.ActionInput,'Visible','off')
2436    if isfield(SeriesData,'ActionInput')
2437        SeriesData=rmfield(SeriesData,'ActionInput');
2438    end
2439end
2440set(handles.series,'UserData',SeriesData)
2441set(handles.ActionName,'BackgroundColor',[1 1 1])
2442
2443%------------------------------------------------------------------------
2444% --- Executes on selection change in FieldName.
2445function FieldName_Callback(hObject, eventdata, handles)
2446%------------------------------------------------------------------------
2447field_str=get(handles.FieldName,'String');
2448field_index=get(handles.FieldName,'Value');
2449field=field_str{field_index(1)};
2450if isequal(field,'get_field...')
2451    SeriesData=get(handles.series,'UserData');
2452    % input line for which the field choice is relevant
2453    iview=find(ismember(SeriesData.FileType,{'netcdf','civx','civdata'}));% all nc files, icluding civ
2454    hget_field=findobj(allchild(0),'name','get_field');
2455    if ~isempty(hget_field)
2456        delete(hget_field)%delete opened versions of get_field
2457    end
2458    Param=read_GUI(handles.series);
2459    InputTable=Param.InputTable(iview,:);
2460    % check the existence of the first file in the series
2461    first_j=[];last_j=[];MinIndex_j=1;MaxIndex_j=1;%default setting for index j
2462    if isfield(Param.IndexRange,'first_j');% if index j is used     
2463        first_j=Param.IndexRange.first_j;
2464        last_j=Param.IndexRange.last_j;
2465        MinIndex_j=Param.IndexRange.MinIndex_j(iview);
2466        MaxIndex_j=Param.IndexRange.MaxIndex_j(iview);
2467    end
2468    PairString='';
2469    if isfield(Param.IndexRange,'PairString'); PairString=Param.IndexRange.PairString{iview}; end
2470    [i1,i2,j1,j2] = get_file_index(Param.IndexRange.first_i,first_j,PairString);
2471    LineIndex=iview(1);
2472    if numel(iview)>1     
2473        answer=msgbox_uvmat('INPUT_TXT',['select the line of the input table:' num2str(iview)] ,num2str(iview(1)));
2474        LineIndex=str2num(answer);
2475%         InputLine=str2num(get(handles.InputLine,'String'));
2476%         if ismember(InputLine,iview)
2477%             LineIndex=InputLine;
2478%         end
2479    end
2480    FirstFileName=fullfile_uvmat(InputTable{LineIndex,1},InputTable{LineIndex,2},InputTable{LineIndex,3},...
2481        InputTable{LineIndex,5},InputTable{LineIndex,4},i1,i2,j1,j2);
2482    if exist(FirstFileName,'file')
2483        ParamIn.Title='get_field: pick input variables and coordinates for series processing';
2484        ParamIn.SeriesInput=1;
2485        GetFieldData=get_field(FirstFileName,ParamIn);
2486        FieldList={};
2487        if isfield(GetFieldData,'FieldOption')% if a field has been selected
2488        switch GetFieldData.FieldOption
2489            case 'vectors'
2490                UName=GetFieldData.PanelVectors.vector_x;
2491                VName=GetFieldData.PanelVectors.vector_y;
2492                YName={GetFieldData.Coordinates.Coord_y};
2493                FieldList={['vec(' UName ',' VName ')'];...
2494                    ['norm(' UName ',' VName ')'];...
2495                    UName;VName};
2496            case {'scalar'}
2497                FieldList=GetFieldData.PanelScalar.scalar;
2498                YName={GetFieldData.Coordinates.Coord_y};
2499                if ischar(FieldList)
2500                    FieldList={FieldList};
2501                end
2502            case 'civdata...'
2503                FieldList=[set_field_list('U','V') ;{'C'}];
2504                set(handles.FieldName,'Value',1) % set menu to 'velocity
2505                XName='X';
2506                YName='y';
2507        end
2508        set(handles.FieldName,'Value',1)
2509        set(handles.FieldName,'String',[FieldList; {'get_field...'}]);
2510        if ~strcmp(GetFieldData.FieldOption,'civdata...')
2511           if ~isempty(regexp(FieldList{1},'^vec'))
2512                set(handles.FieldName,'Value',1)
2513           else
2514                set(handles.FieldName,'Value',1:numel(FieldList))%select all input fields by default
2515           end
2516            XName=GetFieldData.Coordinates.Coord_x;
2517            YName=GetFieldData.Coordinates.Coord_y;
2518            TimeNameStr=GetFieldData.Time.SwitchVarIndexTime;
2519            % get the time info                     
2520            TimeTable=get(handles.TimeTable,'Data');
2521            switch TimeNameStr
2522                case 'file index'
2523                    TimeName='';
2524                case 'attribute'
2525                    TimeName=['att:' GetFieldData.Time.TimeName];
2526                    % update the time table
2527                    TimeTable{LineIndex,2}=get_time(Param.IndexRange.MinIndex_i(LineIndex),MinIndex_j,PairString,InputTable,SeriesData.FileInfo{LineIndex},GetFieldData.Time.TimeName);  % Min time     
2528                    TimeTable{LineIndex,3}=get_time(Param.IndexRange.first_i,first_j,PairString,InputTable,SeriesData.FileInfo{LineIndex},GetFieldData.Time.TimeName);  % first time             
2529                    TimeTable{LineIndex,4}=get_time(Param.IndexRange.last_i,last_j,PairString,InputTable,SeriesData.FileInfo{LineIndex},GetFieldData.Time.TimeName);  % last time                     
2530                    TimeTable{LineIndex,5}=get_time(Param.IndexRange.MaxIndex_i(LineIndex),MaxIndex_j,PairString,InputTable,SeriesData.FileInfo{LineIndex},GetFieldData.Time.TimeName);  % Max time
2531                case 'variable'
2532                    set(handles.TimeName,'String',['var:' GetFieldData.Time.TimeName])
2533                    set(handles.NomType,'String','*')
2534                    set(handles.RootFile,'String',[get(handles.RootFile,'String') get(handles.FileIndex,'String')])% A VERIFIER !!!!!!
2535                    set(handles.FileIndex,'String','')
2536                    ParamIn.TimeVarName=GetFieldData.Time.TimeName;
2537                case 'matrix_index'
2538                    TimeName=['dim:' GetFieldData.Time.TimeName];
2539                    set(handles.NomType,'String','*')
2540                    set(handles.RootFile,'String',[get(handles.RootFile,'String') get(handles.FileIndex,'String')])
2541                    set(handles.FileIndex,'String','')
2542                    ParamIn.TimeDimName=GetFieldData.Time.TimeName;
2543            end
2544            TimeTable{LineIndex,1}=TimeName;
2545            set(handles.TimeTable,'Data',TimeTable);
2546        end
2547        set(handles.Coord_x,'String',XName)
2548        set(handles.Coord_y,'String',YName)
2549        set(handles.Coord_x,'Visible','on')
2550        set(handles.Coord_y,'Visible','on')
2551        end
2552    else
2553        msgbox_uvmat('ERROR',[FirstFileName ' does not exist'])
2554    end
2555end
2556
2557function [TimeValue,DtValue]=get_time(ref_i,ref_j,PairString,InputTable,FileInfo,TimeName,DtName)
2558[i1,i2,j1,j2] = get_file_index(ref_i,ref_j,PairString);
2559FileName=fullfile_uvmat(InputTable{1},InputTable{2},InputTable{3},InputTable{5},InputTable{4},i1,i2,j1,j2);
2560Data=nc2struct(FileName,[]);
2561TimeValue=[];
2562DtValue=[];
2563if isequal(FileInfo.FileType,'civdata')
2564    if ismember(TimeName,{'civ1','filter1'})
2565        TimeValue=Data.Civ1_Time;
2566        DtValue=Data.Civ1_Dt;
2567    else
2568        TimeValue=Data.Civ2_Time;
2569        DtValue=Data.Civ2_Dt;
2570    end
2571else
2572    if ~isempty(TimeName)&& isfield(Data,TimeName)
2573        TimeValue=Data.(TimeName);
2574    end
2575    if exist('DtName','var') && isfield(Data,DtName)
2576        DtValue=Data.(DtName);
2577    end
2578end
2579
2580%------------------------------------------------------------------------
2581% --- Executes on selection change in FieldName_1.
2582function FieldName_1_Callback(hObject, eventdata, handles)
2583%------------------------------------------------------------------------
2584field_str=get(handles.FieldName_1,'String');
2585field_index=get(handles.FieldName_1,'Value');
2586field=field_str{field_index(1)};
2587if isequal(field,'get_field...')
2588    hget_field=findobj(allchild(0),'name','get_field');
2589    if ~isempty(hget_field)
2590        delete(hget_field)%delete opened versions of get_field
2591    end
2592    Param=read_GUI(handles.series);
2593    Param.InputTable=Param.InputTable(1,:);
2594    % check the existence of the first file in the series
2595    first_j=[];
2596    if isfield(Param.IndexRange,'first_j'); first_j=Param.IndexRange.first_j; end
2597    if isfield(Param.IndexRange,'last_j'); last_j=Param.IndexRange.last_j; end
2598    PairString='';
2599    if isfield(Param.IndexRange,'PairString'); PairString=Param.IndexRange.PairString; end
2600    [i1,i2,j1,j2] = get_file_index(Param.IndexRange.first_i,first_j,PairString);
2601    FirstFileName=fullfile_uvmat(Param.InputTable{1,1},Param.InputTable{1,2},Param.InputTable{1,3},...
2602        Param.InputTable{1,5},Param.InputTable{1,4},i1,i2,j1,j2);
2603    if exist(FirstFileName,'file')
2604        ParamIn.SeriesInput=1;
2605        GetFieldData=get_field(FirstFileName,ParamIn);
2606        FieldList={};
2607        switch GetFieldData.FieldOption
2608            case 'vectors'
2609                UName=GetFieldData.PanelVectors.vector_x;
2610                VName=GetFieldData.PanelVectors.vector_y;
2611                FieldList={['vec(' UName ',' VName ')'];...
2612                    ['norm(' UName ',' VName ')'];...
2613                    UName;VName};
2614            case {'scalar','pick variables'}
2615                FieldList=GetFieldData.PanelScalar.scalar;
2616                if ischar(FieldList)
2617                    FieldList={FieldList};
2618                end
2619            case '1D plot'
2620
2621            case 'civdata...'
2622                FieldList=set_field_list('U','V','C');
2623                set(handles.FieldName,'Value',2) % set menu to 'velocity
2624        end
2625        if ~strcmp(GetFieldData.FieldOption,'civdata...')
2626            TimeNameStr=GetFieldData.Time.SwitchVarIndexTime;
2627            switch TimeNameStr
2628                case 'file index'
2629                    set(handles.TimeName,'String','');
2630                case 'attribute'
2631                    set(handles.TimeName,'String',['att:' GetFieldData.Time.TimeName]);
2632                case 'variable'
2633                    set(handles.TimeName,'String',['var:' GetFieldData.Time.TimeName])
2634                    set(handles.NomType,'String','*')
2635                    set(handles.RootFile,'String',[get(handles.RootFile,'String') get(handles.FileIndex,'String')])% A VERIFIER !!!!!!
2636                    set(handles.FileIndex,'String','')
2637                    ParamIn.TimeVarName=GetFieldData.Time.TimeName;
2638                case 'matrix_index'
2639                    set(handles.TimeName,'String',['dim:' GetFieldData.Time.TimeName]);
2640                    set(handles.NomType,'String','*')
2641                    set(handles.RootFile,'String',[get(handles.RootFile,'String') get(handles.FileIndex,'String')])
2642                    set(handles.FileIndex,'String','')
2643                    ParamIn.TimeDimName=GetFieldData.Time.TimeName;
2644            end
2645        end
2646        set(handles.FieldName_1,'Value',1)
2647        set(handles.FieldName_1,'String',[FieldList; {'get_field...'}]);
2648    end
2649end   
2650
2651
2652%%%%%%%%%%%%%
2653function [ind_remove]=find_pairs(dirpair,ind_i,last_i)
2654indsel=ind_i;
2655indiff=diff(ind_i); %test index increment to detect multiplets (several pairs with the same index ind_i) and holes in the series
2656indiff=[1 indiff last_i-ind_i(end)+1];%for testing gaps with the imposed bounds
2657if ~isempty(indiff)
2658    indiff2=diff(indiff);
2659    indiffp=[indiff2 1];
2660    indiffm=[1 indiff2];
2661    ind_multi_m=find((indiff==0)&(indiffm<0))-1;%indices of first members of multiplets
2662    ind_multi_p=find((indiff==0)&(indiffp>0));%indices of last members of multiplets
2663    %for each multiplet, select the most recent file
2664    ind_remove=[];
2665    for i=1:length(ind_multi_m)
2666        ind_pairs=ind_multi_m(i):ind_multi_p(i);
2667        for imulti=1:length(ind_pairs)
2668            datepair(imulti)=datenum(dirpair(ind_pairs(imulti)).date);%dates of creation
2669        end
2670        [datenew,indsort2]=sort(datepair); %sort the multiplet by creation date
2671        ind_s=indsort2(1:end-1);%
2672        ind_remove=[ind_remove ind_pairs(ind_s)];%remove these indices, leave the last one
2673    end
2674end
2675
2676%------------------------------------------------------------------------
2677% --- determine the list of index pairstring of processing file
2678function [num_i1,num_i2,num_j1,num_j2,num_i_out,num_j_out]=find_file_indices(num_i,num_j,ind_shift,NomType,mode)
2679%------------------------------------------------------------------------
2680num_i1=num_i;% set of first image numbers by default
2681num_i2=num_i;
2682num_j1=num_j;
2683num_j2=num_j;
2684num_i_out=num_i;
2685num_j_out=num_j;
2686% if isequal (NomType,'_1-2_1') || isequal (NomType,'_1-2')
2687if isequal(mode,'series(Di)')
2688    num_i1_line=num_i+ind_shift(3);% set of first image numbers
2689    num_i2_line=num_i+ind_shift(4);
2690    % adjust the first and last field number
2691        indsel=find(num_i1_line >= 1);
2692    num_i_out=num_i(indsel);
2693    num_i1_line=num_i1_line(indsel);
2694    num_i2_line=num_i2_line(indsel);
2695    num_j1=meshgrid(num_j,ones(size(num_i1_line)));
2696    num_j2=meshgrid(num_j,ones(size(num_i1_line)));
2697    [xx,num_i1]=meshgrid(num_j,num_i1_line);
2698    [xx,num_i2]=meshgrid(num_j,num_i2_line);
2699elseif isequal (mode,'series(Dj)')||isequal (mode,'bursts')
2700    if isequal(mode,'bursts') %case of bursts (png_old or png_2D)
2701        num_j1=ind_shift(1)*ones(size(num_i));
2702        num_j2=ind_shift(2)*ones(size(num_i));
2703    else
2704        num_j1_col=num_j+ind_shift(1);% set of first image numbers
2705        num_j2_col=num_j+ind_shift(2);
2706        % adjust the first field number
2707        indsel=find((num_j1_col >= 1));   
2708        num_j_out=num_j(indsel);
2709        num_j1_col=num_j1_col(indsel);
2710        num_j2_col=num_j2_col(indsel);
2711        [num_i1,num_j1]=meshgrid(num_i,num_j1_col);
2712        [num_i2,num_j2]=meshgrid(num_i,num_j2_col);
2713    end   
2714end
2715
2716%------------------------------------------------------------------------
2717% --- Executes on button press in CheckObject.
2718function CheckObject_Callback(hObject, eventdata, handles)
2719%------------------------------------------------------------------------
2720hset_object=findobj(allchild(0),'tag','set_object');%find the set_object interface handle
2721if get(handles.CheckObject,'Value')
2722    SeriesData=get(handles.series,'UserData');
2723    if isfield(SeriesData,'ProjObject') && ~isempty(SeriesData.ProjObject)
2724        set(handles.ViewObject,'Value',1)
2725        ViewObject_Callback(hObject, eventdata, handles)
2726    else
2727        if ishandle(hset_object)
2728            uistack(hset_object,'top')% show the GUI set_object if opened
2729        else
2730            %get the object file
2731            InputTable=get(handles.InputTable,'Data');
2732            defaultname=InputTable{1,1};
2733            if isempty(defaultname)
2734                defaultname={''};
2735            end
2736            fileinput=uigetfile_uvmat('pick a xml object file (or use uvmat to create it)',defaultname,'.xml');
2737            if isempty(fileinput)% exit if no object file is selected
2738                set(handles.CheckObject,'Value',0)
2739                return
2740            end
2741            %read the file
2742            data=xml2struct(fileinput);
2743            if ~isfield(data,'Type')
2744                msgbox_uvmat('ERROR',[fileinput ' is not an object xml file'])
2745                set(handles.CheckObject,'Value',0)
2746                return
2747            end
2748            if ~isfield(data,'ProjMode')
2749                data.ProjMode='none';
2750            end
2751            hset_object=set_object(data);% call the set_object interface
2752            set(hset_object,'Name','set_object_series')% name to distinguish from set_object used with uvmat
2753        end
2754        ProjObject=read_GUI(hset_object);
2755        set(handles.ProjObject,'String',ProjObject.Name);%display the object name
2756        SeriesData=get(handles.series,'UserData');
2757        SeriesData.ProjObject=ProjObject;
2758        set(handles.series,'UserData',SeriesData);
2759    end
2760    set(handles.EditObject,'Visible','on');
2761    set(handles.DeleteObject,'Visible','on');
2762    set(handles.ViewObject,'Visible','on');
2763    set(handles.ProjObject,'Visible','on');
2764else
2765    set(handles.EditObject,'Visible','off');
2766    set(handles.DeleteObject,'Visible','off');
2767    set(handles.ViewObject,'Visible','off');
2768    if ~ishandle(hset_object)
2769        set(handles.ViewObject,'Value',0);
2770    end
2771    set(handles.ProjObject,'Visible','off');
2772end
2773
2774%------------------------------------------------------------------------
2775% --- Executes on button press in ViewObject.
2776%------------------------------------------------------------------------
2777function ViewObject_Callback(hObject, eventdata, handles)
2778
2779UserData=get(handles.series,'UserData');
2780hset_object=findobj(allchild(0),'Tag','set_object');
2781if ~isempty(hset_object)
2782    delete(hset_object)% refresh set_object if already opened
2783end
2784hset_object=set_object(UserData.ProjObject);
2785set(hset_object,'Name','view_object_series')
2786
2787
2788%------------------------------------------------------------------------
2789% --- Executes on button press in EditObject.
2790function EditObject_Callback(hObject, eventdata, handles)
2791%------------------------------------------------------------------------
2792if get(handles.EditObject,'Value')
2793    set(handles.ViewObject,'Value',0)
2794        UserData=get(handles.series,'UserData');
2795    hset_object=set_object(UserData.ProjObject);
2796    set(hset_object,'Name','edit_object_series')
2797    set(get(hset_object,'Children'),'Enable','on')
2798else
2799    hset_object=findobj(allchild(0),'Tag','set_object');
2800    if ~isempty(hset_object)
2801        set(get(hset_object,'Children'),'Enable','off')
2802    end
2803end
2804
2805%------------------------------------------------------------------------
2806% --- Executes on button press in DeleteObject.
2807function DeleteObject_Callback(hObject, eventdata, handles)
2808%------------------------------------------------------------------------
2809SeriesData=get(handles.series,'UserData');
2810SeriesData.ProjObject=[];
2811set(handles.series,'UserData',SeriesData)
2812set(handles.ProjObject,'String','')
2813set(handles.ProjObject,'Visible','off')
2814set(handles.CheckObject,'Value',0)
2815set(handles.ViewObject,'Visible','off')
2816set(handles.EditObject,'Visible','off')
2817hset_object=findobj(allchild(0),'name','set_object_series');
2818if ~isempty(hset_object)
2819    delete(hset_object)
2820end
2821set(handles.DeleteObject,'Visible','off')
2822
2823%------------------------------------------------------------------------
2824% --- Executed when CheckMask is activated
2825%------------------------------------------------------------------------
2826function CheckMask_Callback(hObject, eventdata, handles)
2827
2828if get(handles.CheckMask,'Value')
2829    InputTable=get(handles.InputTable,'Data');
2830    nbview=size(InputTable,1);
2831    MaskTable=cell(nbview,1);%default
2832    ListMask=cell(nbview,1);%default
2833    MaskData=get(handles.MaskTable,'Data');
2834    MaskData(size(MaskData,1):nbview,1)=cell(size(MaskData,1):nbview,1);%complement if undefined lines
2835    for iview=1:nbview
2836        ListMask{iview,1}=num2str(iview);
2837        RootPath=InputTable{iview,1};
2838        if ~isempty(RootPath)
2839            if isempty(MaskData{iview})
2840                SubDir=InputTable{iview,2};
2841                MaskPath=fullfile(RootPath,[regexprep(SubDir,'\..*','') '.mask']);%take the root part of SubDir, before the first dot '.'
2842                if exist(MaskPath,'dir')
2843                    ListStruct=dir(MaskPath);%look for a mask file
2844                    ListCells=struct2cell(ListStruct);% transform dir struct to a cell arrray
2845                    check_dir=cell2mat(ListCells(4,:));% =1 for directories, =0 for files
2846                    ListFiles=ListCells(1,:);%list of file and dri names
2847                    ListFiles=ListFiles(~check_dir);%list of file names (excluding dir)
2848                    mdetect=0;
2849                    if ~isempty(ListFiles)
2850                        for ifile=1:numel(ListFiles)
2851                            [tild,tild,MaskFile{ifile},i1_series,i2_series,j1_series,j2_series,MaskNomType,MaskFileType]=find_file_series(MaskPath,ListFiles{ifile},0);
2852                            if strcmp(MaskFileType,'image') && isempty(i2_series) && isempty(j2_series)
2853                                mdetect=1;
2854                                MaskName=ListFiles{ifile};
2855                            end
2856                            if ~strcmp(MaskFile{ifile},MaskFile{1})
2857                                mdetect=0;% cancel detection test in case of multiple masks, use the brower for selection
2858                                break
2859                            end
2860                        end
2861                    end
2862                    if mdetect==1
2863                        MaskName=fullfile(MaskPath,'mask_1.png');
2864                    else
2865                        MaskName=uigetfile_uvmat('select a mask file:',MaskPath,'image');
2866                    end
2867                else
2868                    MaskName=uigetfile_uvmat('select a mask file:',RootPath,'image');
2869                end
2870                MaskTable{iview,1}=MaskName ;
2871                ListMask{iview,1}=num2str(iview);
2872            end
2873        end
2874    end
2875    set(handles.MaskTable,'Data',MaskTable)
2876    set(handles.MaskTable,'Visible','on')
2877    set(handles.MaskBrowse,'Visible','on')
2878    set(handles.ListMask,'Visible','on')
2879    set(handles.ListMask,'String',ListMask)
2880    set(handles.ListMask,'Value',1)
2881else
2882    set(handles.MaskTable,'Visible','off')
2883    set(handles.MaskBrowse,'Visible','off')
2884    set(handles.ListMask,'Visible','off')
2885end
2886
2887%------------------------------------------------------------------------
2888% --- Executes on button press in MaskBrowse.
2889%------------------------------------------------------------------------
2890function MaskBrowse_Callback(hObject, eventdata, handles)
2891
2892InputTable=get(handles.InputTable,'Data');
2893iview=get(handles.ListMask,'Value');
2894RootPath=InputTable{iview,1};
2895MaskName=uigetfile_uvmat('select a mask file:',RootPath,'image');
2896if ~isempty(MaskName)
2897    MaskTable=get(handles.MaskTable,'Data');
2898    MaskTable{iview,1}=MaskName ;
2899    set(handles.MaskTable,'Data',MaskTable)
2900end
2901
2902%------------------------------------------------------------------------
2903% --- Executes when selected cell(s) is changed in MaskTable.
2904%------------------------------------------------------------------------
2905function MaskTable_CellSelectionCallback(hObject, eventdata, handles)
2906
2907if numel(eventdata.Indices)>=1
2908set(handles.ListMask,'Value',eventdata.Indices(1))
2909end
2910
2911%-------------------------------------------------------------------
2912function MenuHelp_Callback(hObject, eventdata, handles)
2913%-------------------------------------------------------------------
2914
2915
2916% path_to_uvmat=which ('uvmat');% check the path of uvmat
2917% pathelp=fileparts(path_to_uvmat);
2918% helpfile=fullfile(pathelp,'uvmat_doc','uvmat_doc.html');
2919% if isempty(dir(helpfile)), msgbox_uvmat('ERROR','Please put the help file uvmat_doc.html in the sub-directory /uvmat_doc of the UVMAT package')
2920% else
2921%     addpath (fullfile(pathelp,'uvmat_doc'))
2922%     web([helpfile '#series'])
2923% end
2924
2925%-------------------------------------------------------------------
2926% --- Executes on selection change in TransformName.
2927function TransformName_Callback(hObject, eventdata, handles)
2928%----------------------------------------------------------------------
2929TransformList=get(handles.TransformName,'String');
2930TransformIndex=get(handles.TransformName,'Value');
2931TransformName=TransformList{TransformIndex};
2932TransformPathList=get(handles.TransformName,'UserData');
2933nb_builtin_transform=4;
2934if isequal(TransformName,'more...');     
2935    FileName=uigetfile_uvmat('Pick a transform function',get(handles.TransformPath,'String'),'.m');
2936    if isempty(FileName)
2937        return     %browser closed without choice
2938    end
2939    [TransformPath,TransformName,TransformExt]=fileparts(FileName);% removes extension .m
2940    if ~strcmp(TransformExt,'.m')
2941        msgbox_uvmat('ERROR','a Matlab function .m must be introduced');
2942        return
2943    end
2944     % insert the choice in the menu
2945    TransformIndex=find(strcmp(TransformName,TransformList),1);% look for the selected function in the menu Action
2946    if isempty(TransformIndex)%the input string does not exist in the menu
2947        TransformIndex= length(TransformList);
2948        TransformList=[TransformList(1:end-1);{TransformName};TransformList(end)];% the selected function is appended in the menu, before the last item 'more...'
2949        set(handles.TransformName,'String',TransformList)
2950        TransformPathList=[TransformPathList;{TransformPath}];
2951    else% the input function already exist, we update its path (possibly new)
2952        TransformPathList{TransformIndex}=TransformPath;%
2953        set(handles.TransformName,'Value',TransformIndex)
2954    end
2955   % save the new menu in the personal file 'uvmat_perso.mat'
2956   dir_perso=prefdir;%personal Matalb directory
2957   profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
2958   if exist(profil_perso,'file')
2959       for ilist=nb_builtin_transform+1:numel(TransformPathList)
2960           TransformListUser{ilist-nb_builtin_transform}=TransformList{ilist};
2961           TransformPathListUser{ilist-nb_builtin_transform}=TransformPathList{ilist};
2962       end
2963       TransformPathListUser=TransformPathListUser';
2964       TransformListUser=TransformListUser';
2965       save (profil_perso,'TransformPathListUser','TransformListUser','-append'); %store the root name for future opening of uvmat
2966   end
2967end
2968
2969%display the current function path
2970set(handles.TransformPath,'String',TransformPathList{TransformIndex}); %show the path to the senlected function
2971set(handles.TransformName,'UserData',TransformPathList);
2972
2973%------------------------------------------------------------------------
2974% --- fct activated by the upper bar menu ExportConfig
2975%------------------------------------------------------------------------
2976function MenuDisplayConfig_Callback(hObject, eventdata, handles)
2977
2978global Param
2979Param=read_GUI_series(handles);
2980evalin('base','global Param')%make CurData global in the workspace
2981display('current series config :')
2982evalin('base','Param') %display CurData in the workspace
2983commandwindow; %brings the Matlab command window to the front
2984
2985%------------------------------------------------------------------------
2986% --- fct activated by the upper bar menu InportConfig: import
2987%     menu settings from an xml file (stored in /0_XML for each run)
2988%------------------------------------------------------------------------
2989function MenuImportConfig_Callback(hObject, eventdata, handles)
2990
2991%% use a browser to choose the xml file containing the processing config
2992InputTable=get(handles.InputTable,'Data');
2993oldfile=InputTable{1,1};%current path in InputTable
2994if isempty(oldfile)
2995    % use a file name stored in prefdir
2996    dir_perso=prefdir;
2997    profil_perso=fullfile(dir_perso,'uvmat_perso.mat');
2998    if exist(profil_perso,'file')
2999        h=load (profil_perso);
3000        if isfield(h,'RootPath') && ischar(h.RootPath)
3001            oldfile=h.RootPath;
3002        end
3003    end
3004end
3005filexml=uigetfile_uvmat('pick a xml parameter file',oldfile,'.xml');% get the xml file containing processing parameters
3006if isempty(filexml), return, end % quit function if an xml file has not been opened
3007
3008%% fill the GUI series with the content of the xml file
3009Param=xml2struct(filexml);% read the input xml file as a Matlab structure
3010
3011% ask to stop current Action if button RUN is in action (another process is already running)
3012if isequal(get(handles.RUN,'Value'),1)
3013    answer= msgbox_uvmat('INPUT_Y-N','stop current Action process?');
3014    if strcmp(answer,'Yes')
3015        STOP_Callback(hObject, eventdata, handles)
3016    else
3017        return
3018    end
3019end
3020Param.Action.RUN=0; %desactivate the input RUN=1
3021
3022fill_GUI(Param,handles.series)% fill the elements of the GUI series with the input parameters
3023SeriesData=get(handles.series,'UserData');
3024if isfield(Param,'InputFields')
3025    ListField=Param.InputFields.FieldName;
3026    if ischar(ListField),ListField={ListField}; end
3027    set(handles.FieldName,'String',[ListField;{'get-field...'}])
3028     set(handles.FieldName,'Value',1:numel(ListField))
3029     set(handles.FieldName,'Visible','on')
3030end       
3031if isfield(Param,'ActionInput')%  introduce  parameters specific to an Action fct, for instance PIV parameters
3032    set(handles.ActionInput,'Visible','on')
3033    set(handles.ActionInput,'Value',0)
3034    Param.ActionInput.ConfigSource=filexml;% record the source of config for future info
3035    SeriesData.ActionInput=Param.ActionInput;
3036end
3037if isfield(Param,'ProjObject') %introduce projection object if relevant
3038    SeriesData.ProjObject=Param.ProjObject;
3039end
3040set(handles.series,'UserData',SeriesData)
3041if isfield(Param,'CheckObject') && isequal(Param.CheckObject,1)
3042    set(handles.ProjObject,'String',Param.ProjObject.Name)
3043    set(handles.ViewObject,'Visible','on')
3044    set(handles.EditObject,'Visible','on')
3045    set(handles.DeleteObject,'Visible','on')
3046else     
3047    set(handles.ProjObject,'String','')
3048    set(handles.ProjObject,'Visible','off')
3049    set(handles.ViewObject,'Visible','off')
3050    set(handles.EditObject,'Visible','off')
3051    set(handles.DeleteObject,'Visible','off')     
3052end     
3053set(handles.REFRESH,'BackgroundColor',[1 0 1]); %paint REFRESH button in magenta to indicate that it should be activated
3054
3055
3056%------------------------------------------------------------------------
3057% --- Executes when the GUI series is resized.
3058%------------------------------------------------------------------------
3059function series_ResizeFcn(hObject, eventdata, handles)
3060
3061%% input table
3062set(handles.InputTable,'Unit','pixel')
3063Pos=get(handles.InputTable,'Position');
3064set(handles.InputTable,'Unit','normalized')
3065ColumnWidth=round([0.5 0.14 0.14 0.14 0.08]*(Pos(3)-52));
3066ColumnWidth=num2cell(ColumnWidth);
3067set(handles.InputTable,'ColumnWidth',ColumnWidth)
3068
3069%% MinIndex_j and MaxIndex_i
3070unit=get(handles.MinIndex_i,'Unit');
3071set(handles.MinIndex_i,'Unit','pixel')
3072Pos=get(handles.MinIndex_i,'Position');
3073set(handles.MinIndex_i,'Unit',unit)
3074set(handles.MinIndex_i,'ColumnWidth',{Pos(3)-18})
3075set(handles.MaxIndex_i,'ColumnWidth',{Pos(3)-18})
3076set(handles.MinIndex_j,'ColumnWidth',{Pos(3)-18})
3077set(handles.MaxIndex_j,'ColumnWidth',{Pos(3)-18})
3078
3079%% TimeTable
3080set(handles.TimeTable,'Unit','pixel')
3081Pos=get(handles.TimeTable,'Position');
3082set(handles.TimeTable,'Unit','normalized')
3083% ColumnWidth=get(handles.TimeTable,'ColumnWidth');
3084ColumnWidth=num2cell(floor([0.2 0.2 0.2 0.2 0.2]*(Pos(3)-20)));
3085set(handles.TimeTable,'ColumnWidth',ColumnWidth)
3086
3087
3088%% PairString
3089set(handles.PairString,'Unit','pixel')
3090Pos=get(handles.PairString,'Position');
3091set(handles.PairString,'Unit','normalized')
3092set(handles.PairString,'ColumnWidth',{Pos(3)-5})
3093
3094%% MaskTable
3095set(handles.MaskTable,'Unit','pixel')
3096Pos=get(handles.MaskTable,'Position');
3097set(handles.MaskTable,'Unit','normalized')
3098set(handles.MaskTable,'ColumnWidth',{Pos(3)-5})
3099
3100%------------------------------------------------------------------------
3101% --- Executes on button press in status.
3102%------------------------------------------------------------------------
3103function status_Callback(hObject, eventdata, handles)
3104
3105if get(handles.status,'Value')
3106    set(handles.status,'BackgroundColor',[1 1 0])
3107    drawnow
3108    Param=read_GUI(handles.series);
3109    RootPath=Param.InputTable{1,1};
3110    if ~isfield(Param,'OutputSubDir')   
3111        msgbox_uvmat('ERROR','no standard sub-directory definition for output files, use a browser to check the output')
3112        set(handles.status,'BackgroundColor',[0 1 0])
3113        return
3114    end
3115    OutputSubDir=[Param.OutputSubDir Param.OutputDirExt];% subdirectory for output files
3116    OutputDir=fullfile(RootPath,OutputSubDir);
3117    if exist(OutputDir,'dir')
3118        uigetfile_uvmat('status_display',OutputDir)
3119    else
3120        msgbox_uvmat('ERROR','output folder not created yet: calculation did not start')
3121        set(handles.status,'BackgroundColor',[0 1 0])
3122    end
3123else
3124    %% delete current display fig if selection is off
3125    set(handles.status,'BackgroundColor',[0 1 0])
3126    hfig=findobj(allchild(0),'name','status_display');
3127    if ~isempty(hfig)
3128        delete(hfig)
3129    end
3130    return
3131end
3132
3133
3134%------------------------------------------------------------------------   
3135% launched by selecting a file on the list
3136%------------------------------------------------------------------------
3137function view_file(hObject, eventdata)
3138
3139list=get(hObject,'String');
3140index=get(hObject,'Value');
3141rootroot=get(hObject,'UserData');
3142selectname=list{index};
3143ind_dot=regexp(selectname,'\.\.\.');
3144if ~isempty(ind_dot)
3145    selectname=selectname(1:ind_dot-1);
3146end
3147FullSelectName=fullfile(rootroot,selectname);
3148if exist(FullSelectName,'dir')% a directory has been selected
3149    ListFiles=dir(FullSelectName);
3150    ListDisplay=cell(numel(ListFiles),1);
3151    for ilist=2:numel(ListDisplay)% suppress the first line '.'
3152        ListDisplay{ilist-1}=ListFiles(ilist).name;
3153    end
3154    set(hObject,'Value',1)
3155    set(hObject,'String',ListDisplay)
3156    if strcmp(selectname,'..')
3157        FullSelectName=fileparts(fileparts(FullSelectName));
3158    end
3159    set(hObject,'UserData',FullSelectName)
3160    hfig=get(hObject,'parent');
3161    htitlebox=findobj(hfig,'tag','titlebox');   
3162    set(htitlebox,'String',FullSelectName)
3163elseif exist(FullSelectName,'file')%visualise the vel field if it exists
3164    FileInfo=get_file_info(FullSelectName);   
3165    if strcmp(FileInfo.FileType,'txt')
3166        edit(FullSelectName)
3167    elseif strcmp(FileInfo.FileType,'xml')
3168        editxml(FullSelectName)
3169    else
3170        uvmat(FullSelectName)
3171    end
3172    set(gcbo,'Value',1)
3173end
3174
3175
3176%------------------------------------------------------------------------   
3177% launched by refreshing the status figure
3178%------------------------------------------------------------------------
3179function refresh_GUI(hfig)
3180
3181htitlebox=findobj(hfig,'tag','titlebox');
3182hlist=findobj(hfig,'tag','list');
3183hseries=findobj(allchild(0),'tag','series');
3184hstatus=findobj(hseries,'tag','status');
3185StatusData=get(hstatus,'UserData');
3186OutputDir=get(htitlebox,'String');
3187if ischar(OutputDir),OutputDir={OutputDir};end
3188ListFiles=dir(OutputDir{1});
3189if numel(ListFiles)<1
3190    return
3191end
3192ListFiles(1)=[];%removes the first line ='.'
3193ListDisplay=cell(numel(ListFiles),1);
3194testrecent=0;
3195datnum=zeros(numel(ListDisplay),1);
3196for ilist=1:numel(ListDisplay)
3197    ListDisplay{ilist}=ListFiles(ilist).name;
3198      if ~ListFiles(ilist).isdir && isfield(ListFiles(ilist),'datenum')
3199            datnum(ilist)=ListFiles(ilist).datenum;%only available in recent matlab versions
3200            testrecent=1;
3201       end
3202end
3203set(hlist,'String',ListDisplay)
3204
3205%% Look at date of creation
3206ListDisplay=ListDisplay(datnum~=0);
3207datnum=datnum(datnum~=0);%keep the non zero values corresponding to existing files
3208NbOutputFile=[];
3209if isempty(datnum)
3210    if testrecent
3211        message='no civ result created yet';
3212    else
3213        message='';
3214    end
3215else
3216    [first,indfirst]=min(datnum);
3217    [last,indlast]=max(datnum);
3218    NbOutputFile_str='?';
3219    NbOutputFile=[];
3220    if isfield(StatusData,'NbOutputFile')
3221        NbOutputFile=StatusData.NbOutputFile;
3222        NbOutputFile_str=num2str(NbOutputFile);
3223    end
3224    message={[num2str(numel(datnum)) ' file(s) done over ' NbOutputFile_str] ;['oldest modification:  ' ListDisplay{indfirst} ' : ' datestr(first)];...
3225        ['latest modification:  ' ListDisplay{indlast} ' : ' datestr(last)]};
3226end
3227set(htitlebox,'String', [OutputDir{1};message])
3228
3229%% update the waitbar
3230hwaitbar=findobj(hfig,'tag','waitbar');
3231if ~isempty(NbOutputFile)
3232    BarPosition=get(hwaitbar,'Position');
3233    BarPosition(3)=0.9*numel(datnum)/NbOutputFile;
3234    set(hwaitbar,'Position',BarPosition)
3235end
3236
3237%------------------------------------------------------------------------
3238% --- Executes on selection change in ActionExt.
3239%------------------------------------------------------------------------
3240function ActionExt_Callback(hObject, eventdata, handles)
3241
3242ActionExtList=get(handles.ActionExt,'String');
3243ActionExt=ActionExtList{get(handles.ActionExt,'Value')};
3244if strcmp(ActionExt,'.py (in dev.)')
3245    set(handles.RunMode,'Value',2)
3246end
3247
3248function num_NbProcess_Callback(hObject, eventdata, handles)
3249
3250
3251function num_NbSlice_Callback(hObject, eventdata, handles)
3252NbSlice=str2num(get(handles.num_NbSlice,'String'));
3253set(handles.num_NbProcess,'String',num2str(NbSlice))
3254
3255%------------------------------------------------------------------------
3256% --- set the visibility of relevant velocity type menus:
3257function menu=set_veltype_display(Civ,FileType)
3258%------------------------------------------------------------------------
3259if ~exist('FileType','var')
3260    FileType='civx';
3261end
3262switch FileType
3263    case 'civx'
3264        menu={'civ1';'interp1';'filter1';'civ2';'interp2';'filter2'};
3265        if isequal(Civ,0)
3266            imax=0;
3267        elseif isequal(Civ,1) || isequal(Civ,2)
3268            imax=1;
3269        elseif isequal(Civ,3)
3270            imax=3;
3271        elseif isequal(Civ,4) || isequal(Civ,5)
3272            imax=4;
3273        elseif isequal(Civ,6) %patch2
3274            imax=6;
3275        end
3276    case 'civdata'
3277        menu={'civ1';'filter1';'civ2';'filter2'};
3278        if isequal(Civ,0)
3279            imax=0;
3280        elseif isequal(Civ,1) || isequal(Civ,2)
3281            imax=1;
3282        elseif isequal(Civ,3)
3283            imax=2;
3284        elseif isequal(Civ,4) || isequal(Civ,5)
3285            imax=3;
3286        elseif isequal(Civ,6) %patch2
3287            imax=4;
3288        end
3289end
3290menu=menu(1:imax);
3291
3292
3293% --- Executes on mouse motion over figure - except title and menu.
3294function series_WindowButtonMotionFcn(hObject, eventdata, handles)
3295set(hObject,'Pointer','arrow');
3296
3297
3298% --- Executes on button press in SetPairs.
3299function SetPairs_Callback(hObject, iview, handles)
3300
3301%% delete previous occurrence of 'set_pairs'
3302hfig=findobj(allchild(0),'Tag','set_pairs');
3303if ~isempty(hfig)
3304delete(hfig)
3305end
3306
3307%% create the GUI set_pairs
3308set(0,'Unit','points')
3309ScreenSize=get(0,'ScreenSize');% get the size of the screen, to put the fig on the upper right
3310Width=220;% fig width in points (1/72 inch)
3311Height=min(0.8*ScreenSize(4),300);
3312Left=ScreenSize(3)- Width-40; %right edge close to the right, with margin=40
3313Bottom=ScreenSize(4)-Height-40; %put fig at top right
3314hfig=findobj(allchild(0),'Tag','set_slice');
3315if ~isempty(hfig),delete(hfig), end; %delete existing version of the GUI
3316hfig=figure('name','set_pairs','tag','set_pairs','MenuBar','none','NumberTitle','off','Unit','points','Position',[Left,Bottom,Width,Height]);
3317BackgroundColor=get(hfig,'Color');
3318SeriesData=get(handles.series,'UserData');
3319TimeUnit=get(handles.TimeUnit,'String');
3320PairString=get(handles.PairString,'Data');
3321ListViewLines=find(cellfun('isempty',PairString)==0);%find list of non empty pairs
3322ListViewMenu=cell(numel(ListViewLines),1);
3323for ilist=1:numel(ListViewLines)
3324    ListViewMenu{ilist}=num2str(ListViewLines(ilist));
3325end
3326if isempty(iview)
3327    ListViewValue=numel(ListViewLines);% we work by default on the pair option for the last line which requires pairs
3328    iview=ListViewLines(end);
3329else
3330    ListViewValue=find(ListViewLines==iview);
3331end
3332ref_i=str2num(get(handles.num_first_i,'String'));
3333ref_j=1;%default
3334if strcmp(get(handles.num_first_j,'String'),'Visible')
3335    ref_j=str2num(get(handles.num_first_j,'String'));
3336end
3337[ModeMenu,ModeValue]=update_mode(SeriesData.i1_series{iview},SeriesData.i2_series{iview},SeriesData.j2_series{iview});
3338displ_pair=update_listpair(SeriesData.i1_series{iview},SeriesData.i2_series{iview},SeriesData.j1_series{iview},SeriesData.j2_series{iview},ModeMenu{ModeValue},...
3339                                                     SeriesData.Time{iview},TimeUnit,ref_i,ref_j,SeriesData.FileInfo{iview});
3340% first raw of the GUI
3341uicontrol('Style','text','Units','normalized', 'Position', [0.05 0.88 0.5 0.1],'BackgroundColor',BackgroundColor,...
3342    'String','row to edit #','FontUnits','points','FontSize',12,'FontWeight','bold','ForegroundColor','blue','HorizontalAlignment','right');%title
3343uicontrol('Style','popupmenu','Units','normalized', 'Position', [0.54 0.8 0.3 0.2],'BackgroundColor',[1 1 1],...
3344    'Callback',@(hObject,eventdata)ListView_Callback(hObject,eventdata),'String',ListViewMenu,'Value',ListViewValue,'FontUnits','points','FontSize',12,'FontWeight','bold',...
3345    'Tag','ListView','TooltipString','''ListView'':choice of the file series w for pair display');
3346% second raw of the GUI
3347uicontrol('Style','text','Units','normalized', 'Position', [0.05 0.79 0.7 0.1],'BackgroundColor',BackgroundColor,...
3348    'String','mode of index pairing:','FontUnits','points','FontSize',12,'FontWeight','bold','ForegroundColor','blue','HorizontalAlignment','left');%title
3349uicontrol('Style','popupmenu','Units','normalized', 'Position', [0.05 0.62 0.9 0.2],'BackgroundColor',[1 1 1],...
3350    'Callback',@(hObject,eventdata)Mode_Callback(hObject,eventdata),'String',ModeMenu,'Value',ModeValue,'FontUnits','points','FontSize',12,'FontWeight','bold',...
3351    'Tag','Mode','TooltipString','''Mode'': choice of the image pair mode');
3352% third raw
3353uicontrol('Style','text','Units','normalized', 'Position', [0.05 0.6 0.7 0.1],'BackgroundColor',BackgroundColor,...
3354    'String','pair choice:','FontUnits','points','FontSize',12,'FontWeight','bold','ForegroundColor','blue','HorizontalAlignment','left');%title
3355uicontrol('Style','listbox','Units','normalized', 'Position', [0.05 0.42 0.9 0.2],'BackgroundColor',[1 1 1],...
3356    'Callback',@(hObject,eventdata)ListPair_Callback(hObject,eventdata),'String',displ_pair,'Value',1,'FontUnits','points','FontSize',12,'FontWeight','bold',...
3357    'Tag','ListPair','TooltipString','''ListPair'': menu for selecting the image pair');
3358uicontrol('Style','text','Units','normalized', 'Position', [0.1 0.22 0.8 0.1],'BackgroundColor',BackgroundColor,...
3359    'String','ref_i           ref_j','FontUnits','points','FontSize',12,'FontWeight','bold','ForegroundColor','blue','HorizontalAlignment','center');%title
3360uicontrol('Style','edit','Units','normalized', 'Position', [0.15 0.17 0.3 0.08],'BackgroundColor',[1 1 1],...
3361    'Callback',@(hObject,eventdata)num_ref_i_Callback(hObject,eventdata),'String',num2str(ref_i),'FontUnits','points','FontSize',12,'FontWeight','bold',...
3362    'Tag','num_ref_i','TooltipString','''num_ref_i'': reference field index i used to display dt in ''list_pair_civ''');
3363uicontrol('Style','edit','Units','normalized', 'Position', [0.55 0.17 0.3 0.08],'BackgroundColor',[1 1 1],...
3364    'Callback',@(hObject,eventdata)num_ref_j_Callback(hObject,eventdata),'String',num2str(ref_j),'FontUnits','points','FontSize',12,'FontWeight','bold',...
3365    'Tag','num_ref_j','TooltipString','''num_ref_j'': reference field index i used to display dt in ''list_pair_civ''');
3366uicontrol('Style','pushbutton','Units','normalized', 'Position', [0.01 0.01 0.3 0.12],'BackgroundColor',[0 1 0],...
3367    'Callback',@(hObject,eventdata)OK_Callback(hObject,eventdata),'String','OK','FontUnits','points','FontSize',12,'FontWeight','bold',...
3368    'Tag','OK','TooltipString','''OK'': validate the choice');
3369%  last raw  of the GUI: pushbuttons
3370% uicontrol('Style','pushbutton','Units','normalized', 'Position', [0.35 0.01 0.3 0.15],'BackgroundColor',[0 1 0],'String','OK','Callback',@(hObject,eventdata)OK_Callback(hObject,eventdata),...
3371%     'FontWeight','bold','FontUnits','points','FontSize',12,'TooltipString','''OK'': apply the output to the current field series in uvmat');
3372drawnow
3373
3374%------------------------------------------------------------------------
3375function ListView_Callback(hObject,eventdata)
3376Mode_Callback(hObject,eventdata)
3377
3378%------------------------------------------------------------------------   
3379function Mode_Callback(hObject,eventdata)
3380%% get input info
3381hseries=findobj(allchild(0),'tag','series');%handles of the GUI series
3382hhseries=guidata(hseries);%handles of the elements in the GUI series
3383TimeUnit=get(hhseries.TimeUnit,'String');
3384SeriesData=get(hseries,'UserData');
3385mode_list=get(hObject,'String');
3386mode=mode_list{get(hObject,'Value')};
3387hListView=findobj(get(hObject,'parent'),'Tag','ListView');
3388iview=get(hListView,'Value');
3389i1_series=SeriesData.i1_series{iview};
3390i2_series=SeriesData.i2_series{iview};
3391j1_series=SeriesData.j1_series{iview};
3392j2_series=SeriesData.j2_series{iview};
3393
3394%% enable j index visibility after the new choice
3395status_j='on';%default
3396if isempty(find(~cellfun(@isempty,SeriesData.j1_series), 1)); % case of empty j indices
3397    status_j='off'; % no j index needed
3398elseif strcmp(get(handles.PairString,'Visible'),'on')
3399    check_burst=cellfun(@isempty,regexp(PairString,'^j'));%=0 for burst case, 1 otherwise
3400    if isempty(find(check_burst, 1))% if all pair string begins by j (burst)
3401        status_j='off'; % no j index needed for bust case
3402    end
3403end
3404enable_j(handles,status_j) % no j index needed
3405
3406%% get the reference indices for the time interval Dt
3407href_i=findobj(get(hObject,'parent'),'Tag','ref_i');
3408ref_i=[];ref_j=[];
3409if strcmp(get(href_i,'Visible'),'on')
3410    ref_i=str2num(get(href_i,'String'));
3411end
3412if isempty(ref_i)
3413    ref_i=1;
3414end
3415if isempty(ref_j)
3416    ref_j=1;
3417end
3418
3419%% update the menu ListPair
3420Menu=update_listpair(i1_series,i2_series,j1_series,j2_series,mode,SeriesData.Time{iview},TimeUnit,ref_i,ref_j,FileInfo);
3421hlist_pairs=findobj(get(hObject,'parent'),'Tag','ListPair');
3422set(hlist_pairs,'Value',1)% set the first choice by default in ListPair
3423set(hlist_pairs,'String',Menu)% set the menu in ListPair
3424ListPair_Callback(hlist_pairs,[])% apply the default choice in ListPair
3425
3426%-------------------------------------------------------------
3427% --- Executes on selection in ListPair.
3428function ListPair_Callback(hObject,eventdata)
3429%------------------------------------------------------------
3430list_pair=get(hObject,'String');%get the menu of image pairs
3431if isempty(list_pair)
3432    string='';
3433else
3434    string=list_pair{get(hObject,'Value')};
3435   % string=regexprep(string,',.*','');%removes time indication (after ',')
3436end
3437hseries=findobj(allchild(0),'tag','series');
3438hPairString=findobj(hseries,'tag','PairString');
3439PairString=get(hPairString,'Data');
3440hListView=findobj(get(hObject,'parent'),'Tag','ListView');
3441iview=get(hListView,'Value');
3442PairString{iview,1}=string;
3443% report the selected pair string to the table PairString
3444set(hPairString,'Data',PairString)
3445
3446
3447%------------------------------------------------------------------------
3448function num_ref_i_Callback(hObject, eventdata)
3449%------------------------------------------------------------------------
3450Mode_Callback([],[])
3451
3452%------------------------------------------------------------------------
3453function num_ref_j_Callback(hObject, eventdata)
3454%------------------------------------------------------------------------
3455Mode_Callback([],[])
3456
3457%------------------------------------------------------------------------
3458function OK_Callback(hObject, eventdata)
3459%------------------------------------------------------------------------
3460delete(get(hObject,'parent'))
3461
3462
3463%------------------------------------------------------------------------
3464% --- Executes on button press in ClearLine.
3465%------------------------------------------------------------------------
3466function ClearLine_Callback(hObject, eventdata, handles)
3467InputTable=get(handles.InputTable,'Data');
3468iline=str2double(get(handles.InputLine,'String'));
3469if size(InputTable,1)>1
3470    InputTable(iline,:)=[];% suppress the current line if not the first
3471    set(handles.InputTable,'Data',InputTable);
3472end
3473
3474
3475% --- Executes on button press in MonitorCluster.
3476function MonitorCluster_Callback(hObject, eventdata, handles)
3477web('https://www.legi.grenoble-inp.fr/servload/monika')
3478
3479
3480
3481function OutputSubDir_Callback(hObject, eventdata, handles)
3482set(handles.OutputSubDir,'BackgroundColor',[1 1 1])
3483% hObject    handle to OutputSubDir (see GCBO)
3484% eventdata  reserved - to be defined in a future version of MATLAB
3485% handles    structure with handles and user data (see GUIDATA)
3486
3487% Hints: get(hObject,'String') returns contents of OutputSubDir as text
3488%        str2double(get(hObject,'String')) returns contents of OutputSubDir as a double
Note: See TracBrowser for help on using the repository browser.