From fa281e2d6909ffe85eb7278d3ed62893d125b5a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santtu=20S=C3=B6derholm?= Date: Wed, 18 Oct 2023 10:30:50 +0300 Subject: [PATCH 1/7] Add functions core.preconditioners.{jacobi,ssor} --- +core/+preconditioners/jacobi.m | 14 ++++++++++++++ +core/+preconditioners/ssor.m | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 +core/+preconditioners/jacobi.m create mode 100644 +core/+preconditioners/ssor.m diff --git a/+core/+preconditioners/jacobi.m b/+core/+preconditioners/jacobi.m new file mode 100644 index 000000000..53c1b1093 --- /dev/null +++ b/+core/+preconditioners/jacobi.m @@ -0,0 +1,14 @@ +function prec = jacobi ( A ) +% +% prec = jacobi ( A ) +% +% Computes the Jacobi preconditioner for the matrix A of a system Ax = b. +% + + arguments + A (:,:) + end + + prec = diag ( diag ( A ) ) \ eye ( size ( A ) ) ; + +end % function diff --git a/+core/+preconditioners/ssor.m b/+core/+preconditioners/ssor.m new file mode 100644 index 000000000..ab7948485 --- /dev/null +++ b/+core/+preconditioners/ssor.m @@ -0,0 +1,32 @@ +function prec = ssor ( A, kwargs ) +% +% prec = ssor ( A, kwargs ) +% +% Computes the SSOR preconditioner for the matrix A of a system Ax = b. +% +% kwargs: +% +% - coeff = 1 +% +% The preconditioner constant used in the computation. The default value of 1 +% corresponds to the Gauss--Seidel preconditioner. +% + + arguments + A (:,:) + kwargs.coeff (1,1) double { mustBeInRange(kwargs.coeff, 0, 2) } = 1 + end + + L = tril ( A ) ; + + U = triu ( A ) ; + + D = diag ( diag ( A ) ) ; + + invD = D \ eye ( size ( D ) ) ; + + coeff = kwargs.coeff ; + + prec = ( D + coeff * L ) * invD * ( D + coeff * U ) ; + +end % function From a2a0a317663ff7cbc1803e372f77fdf1f8edad19 Mon Sep 17 00:00:00 2001 From: GitFernandoGalaz Date: Wed, 29 Nov 2023 18:05:54 +0200 Subject: [PATCH 2/7] Add files via upload --- plugins/ZeffiroESWorkbench/m/zef_ES_4x1_fun.m | 2 +- .../ZeffiroESWorkbench/m/zef_ES_4x1_sensors.m | 62 +-- .../m/zef_ES_clear_plot_data.m | 4 +- .../m/zef_ES_error_criteria.m | 6 +- .../m/zef_ES_find_currents.m | 35 +- .../m/zef_ES_find_parameters.m | 64 +-- .../m/zef_ES_fix_active_electrodes.m | 4 +- .../m/zef_ES_init_parameter_table.m | 4 +- .../m/zef_ES_objective_function.m | 4 +- .../m/zef_ES_optimization.m | 6 +- .../m/zef_ES_optimization_init.m | 11 +- .../m/zef_ES_optimization_update.m | 10 - .../m/zef_ES_optimization_window.m | 6 +- .../m/zef_ES_optimize_current.m | 380 +++++++++--------- .../m/zef_ES_optimizer_properties.m | 4 +- .../m/zef_ES_optimizer_properties_show.m | 26 +- .../ZeffiroESWorkbench/m/zef_ES_plot_4x1.m | 2 +- .../m/zef_ES_plot_4x1_fun.m | 2 +- .../m/zef_ES_plot_barplot.m | 30 +- .../m/zef_ES_plot_current_pattern.m | 6 +- .../m/zef_ES_plot_distance_curves.m | 32 +- .../m/zef_ES_plot_error_chart.m | 12 +- plugins/ZeffiroESWorkbench/m/zef_ES_rwnnz.m | 14 +- plugins/ZeffiroESWorkbench/m/zef_ES_table.m | 85 ++-- .../m/zef_ES_update_parameter_values.m | 7 +- .../ZeffiroESWorkbench/m/zef_cvx_linprog.m | 70 ++-- .../ZeffiroESWorkbench/m/zef_cvx_quadprog.m | 70 ++-- .../m/zef_cvx_semidefprog.m | 74 ++-- .../ZeffiroESWorkbench/m/zef_mosek_linprog.m | 70 ++-- 29 files changed, 546 insertions(+), 556 deletions(-) diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_fun.m b/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_fun.m index c4b658809..e8c8447aa 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_fun.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_fun.m @@ -15,7 +15,7 @@ scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'r','filled'); elseif ismember(i,ell_idx(2:5)) scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'b','filled'); - else + else scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'.','k'); end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_sensors.m b/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_sensors.m index 5e950378d..de7bb3f83 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_sensors.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_4x1_sensors.m @@ -19,50 +19,50 @@ [~,m_ind] = min(d_norm); p_1 = sensor_coord((m_ind),:); -ell_idx(1) = m_ind; + ell_idx(1) = m_ind; -v_1 = p_1; -p_1_norm = sqrt(sum(p_1.^2,2)); + v_1 = p_1; + p_1_norm = sqrt(sum(p_1.^2,2)); -v_1 = v_1./p_1_norm; -v_2 = source_ori./sqrt(sum(source_ori.^2,2)); -v_3 = cross(v_1',v_2')'; + v_1 = v_1./p_1_norm; + v_2 = source_ori./sqrt(sum(source_ori.^2,2)); + v_3 = cross(v_1',v_2')'; -source_index = [1:size(sensor_coord,1)]; %#ok + source_index = [1:size(sensor_coord,1)]; %#ok -source_index = setdiff(source_index, source_index(m_ind)); -sensor_coord_aux = sensor_coord; -sensor_coord = sensor_coord_aux(source_index,:); + source_index = setdiff(source_index, source_index(m_ind)); + sensor_coord_aux = sensor_coord; + sensor_coord = sensor_coord_aux(source_index,:); p_2 = p_1 + p_1_norm*tan(pi*separation_angle/180)*v_2; -d_norm = sqrt(sum((p_2 - sensor_coord).^2,2)); -[~,m_ind] = min(d_norm); -ell_idx(2) = source_index(m_ind); + d_norm = sqrt(sum((p_2 - sensor_coord).^2,2)); + [~,m_ind] = min(d_norm); + ell_idx(2) = source_index(m_ind); -%sensor_coord_aux = sensor_coord; -source_index = setdiff(source_index, source_index(m_ind)); -sensor_coord = sensor_coord_aux(source_index,:); + %sensor_coord_aux = sensor_coord; + source_index = setdiff(source_index, source_index(m_ind)); + sensor_coord = sensor_coord_aux(source_index,:); p_3 = p_1 + p_1_norm*tan(-pi*separation_angle/180)*v_2; -d_norm = sqrt(sum((p_3 - sensor_coord).^2,2)); -[~,m_ind] = min(d_norm); -ell_idx(3) = source_index(m_ind); + d_norm = sqrt(sum((p_3 - sensor_coord).^2,2)); + [~,m_ind] = min(d_norm); + ell_idx(3) = source_index(m_ind); -%sensor_coord_aux = sensor_coord; -source_index = setdiff(source_index, source_index(m_ind)); -sensor_coord = sensor_coord_aux(source_index,:); + %sensor_coord_aux = sensor_coord; + source_index = setdiff(source_index, source_index(m_ind)); + sensor_coord = sensor_coord_aux(source_index,:); p_4 = p_1 + p_1_norm*tan(pi*separation_angle/180)*v_3; -d_norm = sqrt(sum((p_4 - sensor_coord).^2,2)); -[~,m_ind] = min(d_norm); -ell_idx(4) = source_index(m_ind); + d_norm = sqrt(sum((p_4 - sensor_coord).^2,2)); + [~,m_ind] = min(d_norm); + ell_idx(4) = source_index(m_ind); -%sensor_coord_aux = sensor_coord; -source_index = setdiff(source_index, source_index(m_ind)); -sensor_coord = sensor_coord_aux(source_index,:); + %sensor_coord_aux = sensor_coord; + source_index = setdiff(source_index, source_index(m_ind)); + sensor_coord = sensor_coord_aux(source_index,:); p_5 = p_1 + p_1_norm*tan(-pi*separation_angle/180)*v_3; -d_norm = sqrt(sum((p_5 - sensor_coord).^2,2)); -[~,m_ind] = min(d_norm); -ell_idx(5) = source_index(m_ind); + d_norm = sqrt(sum((p_5 - sensor_coord).^2,2)); + [~,m_ind] = min(d_norm); + ell_idx(5) = source_index(m_ind); end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_clear_plot_data.m b/plugins/ZeffiroESWorkbench/m/zef_ES_clear_plot_data.m index cbf70a104..c64f74747 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_clear_plot_data.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_clear_plot_data.m @@ -1,7 +1,7 @@ function zef = zef_ES_clear_plot_data(zef) -if nargin == 0 - zef = eval('zef'); +if nargin == 0 +zef = eval('zef'); end switch eval('zef.ES_plot_type'); diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_error_criteria.m b/plugins/ZeffiroESWorkbench/m/zef_ES_error_criteria.m index 7824d7bfc..b2f82a8c1 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_error_criteria.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_error_criteria.m @@ -1,11 +1,11 @@ -function vec = zef_ES_error_criteria(zef) +function vec = zef_ES_error_criteria(zef) -if nargin == 0 +if nargin == 0 zef = evalin('base','zef'); end %% Variables and parameters setup -load_aux = eval('zef.y_ES_interval'); + load_aux = eval('zef.y_ES_interval'); B = cell2mat(load_aux.residual); B = B/max(abs(B(:))); diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m index 088480a02..8f428516a 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m @@ -7,9 +7,9 @@ else zef = varargin{1}; end - [alpha, beta] = zef_ES_find_parameters(zef); + [alpha, epsilon] = zef_ES_find_parameters(zef); case {3} - [zef, alpha, beta] = deal(varargin{1}, varargin{2}, varargin{3}); + [zef, alpha, epsilon] = deal(varargin{1}, varargin{2}, varargin{3}); otherwise error('ZI: Too many input arguments.') end @@ -42,8 +42,8 @@ else error('ZI: unable to find relevant mosek folder. Are you initializing your calculations outside the main-branch working directory?') end - - + + end if isequal(lower(zef_data.solver_package),'mosek') @@ -108,9 +108,10 @@ error('ZI: No discretized sources found. Perhaps you forgot to calculate or load them...?') end %% waitbar +zef.use_waitbar = 0; if zef.use_waitbar == 1 wait_bar_temp = zef_waitbar(... - [0 0], [1 1]... + [0 0], ... sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: i = %d, j = d%' '.'], 0, 0)... ); end @@ -146,18 +147,18 @@ p_ind_max = min(step_size - j, n_parallel); parfor parallel_ind = 1:p_ind_max %parfor run_time{parallel_ind} = now; - + [y_ES{parallel_ind}, ... volumetric_current_density{parallel_ind}, ... residual{parallel_ind}, ... flag{parallel_ind}, ... source_amplitude{parallel_ind}, ... source_position_index{parallel_ind}, ... - source_directions{parallel_ind}] = zef_ES_optimize_current(zef_data, alpha(parallel_ind + j), beta(i)); %#ok - + source_directions{parallel_ind}] = zef_ES_optimize_current(zef_data, alpha(parallel_ind + j), epsilon(i)); %#ok + run_time{parallel_ind} = 86400*(now - run_time{parallel_ind}); end - + for parallel_ind = 1:p_ind_max j = j + 1; zef.y_ES_interval.run_time{i,j} = run_time{parallel_ind}; @@ -172,7 +173,7 @@ for running_index = 1:length(source_position_index{parallel_ind}) vec_1 = source_amplitude{parallel_ind}(running_index)*source_directions{parallel_ind}(running_index,:); norm_vec_1 = norm(vec_1, 2); - + if isequal(zef.ES_roi_range, 0) source_running_ind = source_position_index{parallel_ind}(running_index); else @@ -181,7 +182,7 @@ zef.ES_roi_range); source_running_ind = source_running_ind{1}; end - + vec_2 = mean(volumetric_current_density{parallel_ind}(:,source_running_ind),2); norm_vec_2 = norm(vec_2,2); if isequal(norm_vec_2,0) @@ -206,18 +207,18 @@ end end end - + if zef.use_waitbar - zef_waitbar([j i], [length(alpha) length(beta)] , wait_bar_temp, sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: %1.2e -- %1.2e' '.'], beta(i), alpha(j))); + zef_waitbar([j/length(alpha) i/length(epsilon)] , wait_bar_temp, sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: %1.2e -- %1.2e' '.'], epsilon(i), alpha(j))); end end if zef.use_waitbar - zef_waitbar([j i], [length(alpha) length(beta)] , wait_bar_temp, sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: %1.2e -- %1.2e' '.'], beta(i), alpha(j))); + zef_waitbar([j/length(alpha) i/length(epsilon)] , wait_bar_temp, sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: %1.2e -- %1.2e' '.'], epsilon(i), alpha(j))); end end -zef.y_ES_interval.alpha = alpha; -zef.y_ES_interval.beta = beta; +zef.y_ES_interval.alpha = alpha; +zef.y_ES_interval.epsilon = epsilon; if exist('wait_bar_temp') %#ok close(wait_bar_temp) @@ -227,4 +228,4 @@ %assignin('base','zef',zef); assignin('caller','zef',zef); end -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_find_parameters.m b/plugins/ZeffiroESWorkbench/m/zef_ES_find_parameters.m index cf95dab20..7a125129f 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_find_parameters.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_find_parameters.m @@ -1,32 +1,32 @@ -function [alpha, beta] = zef_ES_find_parameters(varargin) +function [alpha, epsilon] = zef_ES_find_parameters(varargin) switch nargin - case {0,1,2} - if nargin == 0 - zef = evalin('base','zef'); - warning('ZI: no input argument.') - else - zef = varargin{1}; - end - alpha = zef.ES_alpha; - alpha_max = zef.ES_alpha_max; - beta_min = zef.ES_beta_min; - beta = zef.ES_beta; - if nargin < 2 - step_size = zef.ES_step_size; - else - step_size = varargin{2}; - end - case {3} - [aux1, aux2, step_size] = deal(varargin{1}, varargin{2}, varargin{3}); - alpha = aux1(1); - alpha_max = aux1(end); - beta = aux2(1); - beta_min = aux2(end); - case {5} - [alpha, alpha_max, beta_min, beta, step_size] = deal(varargin{1}, varargin{2}, varargin{3}, varargin{4}, varargin{5}); - otherwise - error('ZI: Insufficient number of arguments'); +case {0,1,2} +if nargin == 0 +zef = evalin('base','zef'); +warning('ZI: no input argument.') +else +zef = varargin{1}; +end +alpha = zef.ES_alpha; +alpha_max = zef.ES_alpha_max; +epsilon_min = zef.ES_epsilon_min; +epsilon = zef.ES_epsilon; +if nargin < 2 +step_size = zef.ES_step_size; +else +step_size = varargin{2}; +end +case {3} +[aux1, aux2, step_size] = deal(varargin{1}, varargin{2}, varargin{3}); +alpha = aux1(1); +alpha_max = aux1(end); +epsilon = aux2(1); +epsilon_min = aux2(end); +case {5} +[alpha, alpha_max, epsilon_min, epsilon, step_size] = deal(varargin{1}, varargin{2}, varargin{3}, varargin{4}, varargin{5}); +otherwise +error('ZI: Insufficient number of arguments'); end %% @@ -34,16 +34,16 @@ alpha = 1; end -if beta == 0 - beta = 1; +if epsilon == 0 + epsilon = 1; end if alpha ~= alpha_max alpha = exp(log(alpha):(log(alpha_max)-log(alpha))/(step_size-1):log(alpha_max))'; end -if beta ~= beta_min - beta = exp(log(beta):(log(beta_min)-log(beta))/(step_size-1):log(beta_min))'; +if epsilon ~= epsilon_min + epsilon = exp(log(epsilon):(log(epsilon_min)-log(epsilon))/(step_size-1):log(epsilon_min))'; end -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_fix_active_electrodes.m b/plugins/ZeffiroESWorkbench/m/zef_ES_fix_active_electrodes.m index 9d624287f..d618faaff 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_fix_active_electrodes.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_fix_active_electrodes.m @@ -9,12 +9,12 @@ ES_active_electrodes = []; return end - + if isempty(sr) ES_active_electrodes = []; else y_ES_interval = zef.y_ES_interval; - + [~,I] = maxk(abs(y_ES_interval.y_ES{sr,sc}), zef.ES_score_dose); ES_active_electrodes = sort(I); end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_init_parameter_table.m b/plugins/ZeffiroESWorkbench/m/zef_ES_init_parameter_table.m index 51e5138b4..b9588d79e 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_init_parameter_table.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_init_parameter_table.m @@ -74,9 +74,9 @@ zef.h_ES_parameter_table.Data{2,1} = 'Alpha maximum (dB)'; zef.h_ES_parameter_table.Data{2,2} = num2str(db(zef.ES_alpha_max)); zef.h_ES_parameter_table.Data{3,1} = 'Nuisance field weight minimum (dB)'; -zef.h_ES_parameter_table.Data{3,2} = num2str(db(zef.ES_beta_min)); +zef.h_ES_parameter_table.Data{3,2} = num2str(db(zef.ES_epsilon_min)); zef.h_ES_parameter_table.Data{4,1} = 'Nuisance field weight maximum (dB)'; -zef.h_ES_parameter_table.Data{4,2} = num2str(db(zef.ES_beta)); +zef.h_ES_parameter_table.Data{4,2} = num2str(db(zef.ES_epsilon)); zef.h_ES_parameter_table.Data{5,1} = 'Total current in montage'; zef.h_ES_parameter_table.Data{5,2} = num2str(zef.ES_total_max_current); zef.h_ES_parameter_table.Data{6,1} = 'Max current allowed per electrode'; diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_objective_function.m b/plugins/ZeffiroESWorkbench/m/zef_ES_objective_function.m index 6974d87ad..46fff5474 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_objective_function.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_objective_function.m @@ -12,7 +12,7 @@ obj2 = zef.ES_obj_fun_2; AT = zef.ES_acceptable_threshold; TT = zef.ES_threshold_condition; - if nargin == 2 + if nargin == 2 if istable(varargin{2}) vec = varargin{2}; else @@ -73,4 +73,4 @@ [~, Idx_2] = max(abs(obj_fun_2(Idx))); end [sr, sc] = ind2sub(size(obj_fun_2), Idx(Idx_2)); -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization.m index ca8bce2c5..593b9aadb 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization.m @@ -4,10 +4,10 @@ function zef_ES_optimization(zef) zef = evalin('base','zef'); end -%org_val = zef.font_size; -%zef.font_size = 14; +org_val = zef.font_size; +zef.font_size = 14; zef = zef_tool_start(zef, 'zef_ES_optimization_window', 1/5, 1); -%zef.font_size = org_val; +zef.font_size = org_val; if nargout == 0 assignin('base','zef',zef); diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m index 01009d6c0..61c9afc58 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m @@ -72,11 +72,11 @@ if not(isfield(zef,'ES_volumetric_current_density')) zef.ES_volumetric_current_density = []; end -if not(isfield(zef,'ES_beta')) - zef.ES_beta = 1; +if not(isfield(zef,'ES_epsilon')) + zef.ES_epsilon = 1; end -if not(isfield(zef,'ES_beta_min')) - zef.ES_beta_min = 1E-8; +if not(isfield(zef,'ES_epsilon_min')) + zef.ES_epsilon_min = 1E-8; end if not(isfield(zef,'ES_alpha')) zef.ES_alpha = 1E-5; @@ -93,9 +93,6 @@ if not(isfield(zef,'ES_negativity_constraint')) zef.ES_negativity_constraint = []; end -if not(isfield(zef,'ES_max_current_channel')) - zef.ES_max_current_channel = 0.002; -end if not(isfield(zef,'ES_cortex_thickness')) zef.ES_cortex_thickness = 4; end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_update.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_update.m index dd5d530ef..88a304a9a 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_update.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_update.m @@ -8,14 +8,6 @@ zef.ES_obj_fun_2 = zef.h_ES_obj_fun_2.Value; zef.ES_threshold_condition = zef.h_ES_threshold_condition.Value; - -if zef.h_ES_HPO_search_method.Value ~= 2; - zef.h_ES_HPO_recursive_instances.Visible = 'off'; - zef.h_ES_recursive_instances_label.Visible = 'off'; -else; - zef.h_ES_HPO_recursive_instances.Visible = 'on'; - zef.h_ES_recursive_instances_label.Visible = 'on'; -end; zef.ES_HPO_search_method = zef.h_ES_HPO_search_method.Value; zef.ES_inv_colormap = get(zef.h_ES_inv_colormap,'Value'); @@ -39,8 +31,6 @@ zef.ES_HPO_search_method = zef.h_ES_HPO_search_method.Value; -%zef.ES_solver_package = zef.h_ES_opt_type.Items{ismember(zef.h_ES_opt_type.ItemsData,zef.ES_search_type)}; - zef.ES_inv_colormap = get(zef.h_ES_inv_colormap,'Value'); zef.ES_plot_type = get(zef.h_ES_plot_type,'Value'); diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_window.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_window.m index dd7a15d50..52a37a01e 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_window.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_window.m @@ -93,7 +93,7 @@ zef.h_ES_threshold_condition.Value = zef.ES_threshold_condition; zef.h_ES_HPO_search_method.Items = zef.ES_HPO_search_method_list; -zef.h_ES_HPO_search_method.ValueChangedFcn = 'zef_ES_optimization_update;'; +zef.h_ES_HPO_search_method.ValueChangedFcn = 'if zef.h_ES_HPO_search_method.Value ~= 2; zef.h_ES_HPO_recursive_instances.Visible = ''off''; zef.h_ES_recursive_instances_label.Visible = ''off''; else; zef.h_ES_HPO_recursive_instances.Visible = ''on''; zef.h_ES_recursive_instances_label.Visible = ''on''; end;'; zef.h_ES_HPO_search_method.ItemsData = 1:length(zef.h_ES_HPO_search_method.Items); zef.h_ES_HPO_search_method.Value = zef.ES_HPO_search_method; @@ -129,12 +129,8 @@ set(findobj(zef.h_ES_workbench.Children,'-property','FontSize'), 'FontSize', 14); zef_ES_init_parameter_table; -zef.h_ES_opt_method.Value = zef.ES_opt_method; -zef.h_ES_opt_algorithm.Value = zef.h_ES_opt_algorithm.ItemsData(find(ismember(zef.h_ES_opt_algorithm.Items, zef.ES_opt_algorithm), 1)); zef_ES_optimization_update; - - if nargout == 0 assignin('base','zef',zef); end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimize_current.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimize_current.m index c47a763f7..f202b55a0 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimize_current.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimize_current.m @@ -1,17 +1,17 @@ function [y_ES, ES_optimized_current_density, residual, flag_val, source_magnitude, source_position_index, source_directions] = zef_ES_optimize_current(zef_data, varargin) %% varargin if nargin >= 2 - alpha = varargin{1}; +alpha = varargin{1}; end if nargin >= 3 - eps_val = varargin{2}; +eps_val = varargin{2}; end %% Source properties source_position_index = zeros(size(zef_data.source_positions,1),1); for i = 1:size(zef_data.source_positions, 1) - [~, aux_index] = min(sqrt(sum((zef_data.source_positions_aux - zef_data.source_positions(i,:)).^2,2))); - source_position_index(i) = aux_index; +[~, aux_index] = min(sqrt(sum((zef_data.source_positions_aux - zef_data.source_positions(i,:)).^2,2))); +source_position_index(i) = aux_index; end zef_data.source_directions = zef_data.source_directions./sqrt(sum(zef_data.source_directions.^2,2)); @@ -20,31 +20,31 @@ J_x_ES = []; for running_index = 1:length(source_position_index) - J_x_ES = [J_x_ES ; [3*(source_position_index(running_index)-1)+1:3*source_position_index(running_index)]']; %#ok - for ell_ind = 1:3 - L_ES_projection(running_index,:) = L_ES_projection(running_index,:) + zef_data.L_aux(3*(source_position_index(running_index)-1)+ell_ind,:).*zef_data.source_directions(running_index,ell_ind); - end - x_ES_projection(running_index) = zef_data.source_density; +J_x_ES = [J_x_ES ; [3*(source_position_index(running_index)-1)+1:3*source_position_index(running_index)]']; %#ok +for ell_ind = 1:3 +L_ES_projection(running_index,:) = L_ES_projection(running_index,:) + zef_data.L_aux(3*(source_position_index(running_index)-1)+ell_ind,:).*zef_data.source_directions(running_index,ell_ind); +end +x_ES_projection(running_index) = zef_data.source_density; end source_magnitude = max(abs(x_ES_projection)); J_x_ES = setdiff((1:size(zef_data.L_aux,1))',J_x_ES); %% L_ES_projection if ismember(zef_data.search_method, [1 2]) - alpha = norm(zef_data.L_aux, 1)*alpha; - L_ES_projection = [zef_data.L_aux(J_x_ES, :); L_ES_projection]; +alpha = norm(zef_data.L_aux, 1)*alpha; +L_ES_projection = [zef_data.L_aux(J_x_ES, :); L_ES_projection]; elseif ismember(zef_data.search_method,[3 4 5]) - singular_value_max = svds(zef_data.L_aux, 1); - L_ES_projection = [alpha*eps_val*zef_data.L_aux(J_x_ES,:); L_ES_projection]; - alpha = singular_value_max*alpha; +singular_value_max = svds(zef_data.L_aux, 1); +L_ES_projection = [alpha*eps_val*zef_data.L_aux(J_x_ES,:); L_ES_projection]; +alpha = singular_value_max*alpha; end x_ES_projection = [zeros(length(J_x_ES),1); x_ES_projection]; %% Active Electrodes if not(isempty(zef_data.active_electrodes)) - L_ES_projection = L_ES_projection(:, zef_data.active_electrodes); +L_ES_projection = L_ES_projection(:, zef_data.active_electrodes); else - zef_data.active_electrodes = 1:size(L_ES_projection, 2); - L_ES_projection = L_ES_projection(:, zef_data.active_electrodes); +zef_data.active_electrodes = 1:size(L_ES_projection, 2); +L_ES_projection = L_ES_projection(:, zef_data.active_electrodes); end M_mat = eye(size(L_ES_projection, 2)) - ones(size(L_ES_projection, 2))/size(L_ES_projection, 2); @@ -53,163 +53,163 @@ addpath(genpath('external')) switch zef_data.search_method - case 1 %% LP setup - L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; - x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; - - g = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; - - if ismember(lower(zef_data.solver_package), {'matlab'}) - [y_ES,~,flag_val] = zef_data.h_linprog(g, ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - - elseif ismember(lower(zef_data.solver_package), {'gurobi'}) - [y_ES,~,flag_val] = zef_gurobi_linprog(g, ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - - elseif ismember(lower(zef_data.solver_package), {'mosek'}) - [y_ES,~,flag_val] = zef_mosek_linprog(g, ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - - elseif ismember(lower(zef_data.solver_package), {'sdpt3','sedumi'}) - [y_ES,~,flag_val] = zef_cvx_linprog(g, ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - end - - try - if not(isempty(y_ES)) - y_ES = y_ES(1:size(L_ES_projection,2)); - else - y_ES = zeros(size(L_ES_projection,1)); - end - catch - y_ES = zeros(size(L_ES_projection,1)); - end - - if flag_val ~= 1 - y_ES = zeros(size(L_ES_projection,2),1); - end - case 2 - %% SDP setup - - L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; - x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; - - g_1 = [zeros(size(L_ES_projection,2),1); zeros(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; - g_2 = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; zeros(size(L_ES_projection,2),1) ]; - - if ismember(lower(zef_data.solver_package),{'sdpt3','sedumi'}) - [y_ES,~,flag_val] = zef_cvx_semidefprog(g_1,g_2, ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - end - - if not(isempty(y_ES)) - y_ES = y_ES(1:size(L_ES_projection,2)); - else - y_ES = zeros(size(L_ES_projection,1)); - end - - if flag_val ~= 1 - y_ES = zeros(size(L_ES_projection,2),1); - end - case 3 - y_ES = ((L_ES_projection)' * (L_ES_projection) + alpha^2*eye(size(L_ES_projection,2))) \ L_ES_projection'*x_ES_projection; - flag_val = 1; - case 4 - y_ES = L_ES_projection'*x_ES_projection; - flag_val = 1; - case 5 - %% QP setup - - L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; - x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; - - g = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; - - - if ismember(lower(zef_data.solver_package), {'matlab','mosek'}) - - [y_ES,~,flag_val] = zef_data.h_quadprog(diag(g.^2), zeros(size(g)), ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zeros(size(g)),... - zef_data.opts); - - elseif ismember(lower(zef_data.solver_package), {'sdpt3','sedumi'}) - [y_ES,~,flag_val] = zef_cvx_quadprog(diag(g),zeros(size(g)), ... - [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... - [-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... - [], ... - [], ... - [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... - [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... - zef_data.opts); - - elseif ismember(lower(zef_data.solver_package), {'osqp'}) - - prob = osqp; - P = diag(g.^2); - q = zeros(size(g)); - A = [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ]; - l = -Inf*ones(size(A,1),1); - u = [-x_ES_projection ; x_ES_projection; zef_data.total_max_current]; - A = [A; eye(length(g))]; - l = [l ; [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ]]; - u = [u ; [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ] ]; - verbose_on = 1; - if isequal(zef_data.opts.Display,'off') - verbose_on = 0; - end - prob.setup(P, q, A, l, u, 'eps_abs', zef_data.opts.TolAbs,'eps_rel',zef_data.opts.TolRel,'max_iter',zef_data.opts.MaxIter,'verbose',verbose_on); - res = prob.solve(); - y_ES = res.x; - flag_val = res.info.status_val; - - end - - if not(isempty(y_ES)) - y_ES = y_ES(1:size(L_ES_projection,2)); - else - y_ES = zeros(size(L_ES_projection,1)); - end - - if flag_val ~= 1 - y_ES = zeros(size(L_ES_projection,2),1); - end +case 1 %% LP setup +L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; +x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; + +g = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; + +if ismember(lower(zef_data.solver_package), {'matlab'}) +[y_ES,~,flag_val] = zef_data.h_linprog(g, ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); + +elseif ismember(lower(zef_data.solver_package), {'gurobi'}) +[y_ES,~,flag_val] = zef_gurobi_linprog(g, ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); + +elseif ismember(lower(zef_data.solver_package), {'mosek'}) +[y_ES,~,flag_val] = zef_mosek_linprog(g, ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); + +elseif ismember(lower(zef_data.solver_package), {'sdpt3','sedumi'}) +[y_ES,~,flag_val] = zef_cvx_linprog(g, ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); +end + +try +if not(isempty(y_ES)) +y_ES = y_ES(1:size(L_ES_projection,2)); +else +y_ES = zeros(size(L_ES_projection,1)); +end +catch +y_ES = zeros(size(L_ES_projection,1)); +end + +if flag_val ~= 1 +y_ES = zeros(size(L_ES_projection,2),1); +end +case 2 +%% SDP setup + +L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; +x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; + +g_1 = [zeros(size(L_ES_projection,2),1); zeros(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; +g_2 = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; zeros(size(L_ES_projection,2),1) ]; + +if ismember(lower(zef_data.solver_package),{'sdpt3','sedumi'}) +[y_ES,~,flag_val] = zef_cvx_semidefprog(g_1,g_2, ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); +end + +if not(isempty(y_ES)) +y_ES = y_ES(1:size(L_ES_projection,2)); +else +y_ES = zeros(size(L_ES_projection,1)); +end + +if flag_val ~= 1 +y_ES = zeros(size(L_ES_projection,2),1); +end +case 3 +y_ES = ((L_ES_projection)' * (L_ES_projection) + alpha^2*eye(size(L_ES_projection,2))) \ L_ES_projection'*x_ES_projection; +flag_val = 1; +case 4 +y_ES = L_ES_projection'*x_ES_projection; +flag_val = 1; +case 5 +%% QP setup + +L_ES_projection = [L_ES_projection; eye(size(L_ES_projection,2))]; +x_ES_projection = [x_ES_projection; zeros(size(L_ES_projection,2),1)]; + +g = [zeros(size(L_ES_projection,2),1); ones(size(L_ES_projection,1)-size(L_ES_projection,2),1) ; alpha*ones(size(L_ES_projection,2),1) ]; + + +if ismember(lower(zef_data.solver_package), {'matlab','mosek'}) + +[y_ES,~,flag_val] = zef_data.h_quadprog(diag(g.^2), zeros(size(g)), ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zeros(size(g)),... +zef_data.opts); + +elseif ismember(lower(zef_data.solver_package), {'sdpt3','sedumi'}) +[y_ES,~,flag_val] = zef_cvx_quadprog(diag(g),zeros(size(g)), ... +[-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ], ... +[-x_ES_projection ; x_ES_projection; zef_data.total_max_current], ... +[], ... +[], ... +[-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ], ... +[ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ],... +zef_data.opts); + +elseif ismember(lower(zef_data.solver_package), {'osqp'}) + +prob = osqp; +P = diag(g.^2); +q = zeros(size(g)); +A = [-L_ES_projection -eye(size(L_ES_projection,1)) ; L_ES_projection -eye(size(L_ES_projection,1)); zeros(1, size(L_ES_projection,1)) ones(1, size(L_ES_projection,2)) ]; +l = -Inf*ones(size(A,1),1); +u = [-x_ES_projection ; x_ES_projection; zef_data.total_max_current]; +A = [A; eye(length(g))]; +l = [l ; [-zef_data.max_current_channel*ones(size(L_ES_projection,2),1); eps_val*max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2)-length(source_position_index),1); zeros(size(L_ES_projection,2)+length(source_position_index),1) ]]; +u = [u ; [ zef_data.max_current_channel*ones(size(L_ES_projection,2),1); max(source_magnitude)*ones(size(L_ES_projection,1)-size(L_ES_projection,2),1); zef_data.max_current_channel*ones(size(L_ES_projection,2),1) ] ]; +verbose_on = 1; +if isequal(zef_data.opts.Display,'off') +verbose_on = 0; +end +prob.setup(P, q, A, l, u, 'eps_abs', zef_data.opts.TolAbs,'eps_rel',zef_data.opts.TolRel,'max_iter',zef_data.opts.MaxIter,'verbose',verbose_on); +res = prob.solve(); +y_ES = res.x; +flag_val = res.info.status_val; + +end + +if not(isempty(y_ES)) +y_ES = y_ES(1:size(L_ES_projection,2)); +else +y_ES = zeros(size(L_ES_projection,1)); +end + +if flag_val ~= 1 +y_ES = zeros(size(L_ES_projection,2),1); +end end %% Postprocess y_ES = M_mat*y_ES; @@ -222,31 +222,31 @@ y_ES = zef_data.total_max_current * y_ES ./ sum(abs(y_ES)); if max(abs(y_ES)) >= zef_data.max_current_channel - y_ES = zef_data.max_current_channel * y_ES ./ max(abs(y_ES)); +y_ES = zef_data.max_current_channel * y_ES ./ max(abs(y_ES)); end if not(isempty(zef_data.active_electrodes)) - y_ES_aux = zeros(size(zef_data.L_aux,2),1); - y_ES_aux(zef_data.active_electrodes) = y_ES; - y_ES = y_ES_aux; +y_ES_aux = zeros(size(zef_data.L_aux,2),1); +y_ES_aux(zef_data.active_electrodes) = y_ES; +y_ES = y_ES_aux; end %% Flag value if ismember(flag_val,[1 3]) - ES_optimized_current_density = reshape(zef_data.L_aux*y_ES,3,size(zef_data.L_aux,1)/3); - if not(isempty(zef_data.active_electrodes)) - residual_1 = L_ES_projection'*x_ES_projection; - residual_1 = residual_1/norm(residual_1,1); - residual_2 = L_ES_projection'*(L_ES_projection*y_ES(zef_data.active_electrodes)); - residual_2 = residual_2/norm(residual_2,1); - residual = norm(residual_2 - residual_1,1); - end +ES_optimized_current_density = reshape(zef_data.L_aux*y_ES,3,size(zef_data.L_aux,1)/3); +if not(isempty(zef_data.active_electrodes)) +residual_1 = L_ES_projection'*x_ES_projection; +residual_1 = residual_1/norm(residual_1,1); +residual_2 = L_ES_projection'*(L_ES_projection*y_ES(zef_data.active_electrodes)); +residual_2 = residual_2/norm(residual_2,1); +residual = norm(residual_2 - residual_1,1); +end else - y_ES = zeros(size(zef_data.L_aux,2),1); - ES_optimized_current_density = zeros(size(zef_data.L_aux,2),1); - residual = 1; +y_ES = zeros(size(zef_data.L_aux,2),1); +ES_optimized_current_density = zeros(size(zef_data.L_aux,2),1); +residual = 1; end source_directions = zef_data.source_directions; -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties.m index 14e72d841..e1199d9a5 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties.m @@ -11,10 +11,10 @@ zef.h_ES_optimizer_properties.Position(3) = 1.5 * zef.h_ES_optimizer_properties.Position(3); zef.h_ES_optimizer_properties_table.Position(3) = 1.54* zef.h_ES_optimizer_properties_table.Position(3); -zef.h_ES_optimizer_properties_table.ColumnName = {'Parameter name','Value','Average deviation','Maximum deviation'}; +zef.h_ES_optimizer_properties_table.ColumnName = {'Parameter name','Unit','Value','Average deviation','Maximum deviation'}; set(findobj(zef.h_ES_optimizer_properties.Children,'-property','FontUnits'),'FontUnits','pixels'); -set(findobj(zef.h_ES_optimizer_properties.Children,'-property','FontSize'),'FontSize',zef.font_size); +set(findobj(zef.h_ES_optimizer_properties.Children,'-property','FontSize'), 'FontSize', zef.font_size); zef.h_ES_optimizer_properties_copy_all.MenuSelectedFcn = 'zef.ES_temp = zef.h_ES_optimizer_properties_table.Data''; clipboard(''copy'',sprintf(''%s\t%5.10g\n'', zef.ES_temp{:})); zef = rmfield(zef,''ES_temp'');'; %% Autoresize diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties_show.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties_show.m index b243bc5b9..f13bd15e8 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties_show.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimizer_properties_show.m @@ -8,37 +8,39 @@ vec = zef_ES_table(zef.y_ES_interval); [sr, sc] = zef_ES_objective_function(zef); -for i_aux = 1:size(vec, 2)-1 % Last one are the ES channels. +for i_aux = 1:width(vec)-1 % Last one are the ES channels. zef.h_ES_optimizer_properties_table.Data{i_aux, 1} = vec.Properties.VariableNames{i_aux}; + zef.h_ES_optimizer_properties_table.Data{i_aux, 2} = vec.Properties.VariableUnits{i_aux}; if not(isempty(vec{:, i_aux})) - + if i_aux == 13 % alpha - zef.h_ES_optimizer_properties_table.Data{i_aux, 2} = round(vec{:, i_aux}{1}(sc), 4); - elseif i_aux == 14 % beta or k-val - zef.h_ES_optimizer_properties_table.Data{i_aux, 2} = round(vec{:, i_aux}{1}(sr), 4); + zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = round(vec{:, i_aux}{1}(sc), 4); + elseif i_aux == 14 % epsilon!! + zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = round(vec{:, i_aux}{1}(sr), 4); else - zef.h_ES_optimizer_properties_table.Data{i_aux, 2} = vec{:, i_aux}{1}(sr,sc); + zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = vec{:, i_aux}{1}(sr,sc); end if i_aux <= 12 - zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = zef_lattice_deviation(vec{:, i_aux}{1},'avg',0.5,sr,sc); - zef.h_ES_optimizer_properties_table.Data{i_aux, 4} = zef_lattice_deviation(vec{:, i_aux}{1},'max',0.5,sr,sc); + zef.h_ES_optimizer_properties_table.Data{i_aux, 4} = zef_lattice_deviation(vec{:, i_aux}{1},'avg',0.5,sr,sc); + zef.h_ES_optimizer_properties_table.Data{i_aux, 5} = zef_lattice_deviation(vec{:, i_aux}{1},'max',0.5,sr,sc); end else - zef.h_ES_optimizer_properties_table.Data{i_aux,2} = ''; + zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = ''; end end i_aux = i_aux + 1; -zef.h_ES_optimizer_properties_table.Data{i_aux,1} = 'Lattice run time (s)'; -zef.h_ES_optimizer_properties_table.Data{i_aux,2} = sum(vec{:,12}{1},'all'); +zef.h_ES_optimizer_properties_table.Data{i_aux, 1} = 'Total computing (s)'; +zef.h_ES_optimizer_properties_table.Data{i_aux, 2} = 's'; +zef.h_ES_optimizer_properties_table.Data{i_aux, 3} = sum(vec{:,12}{1},'all'); zef.h_ES_optimizer_properties.Name = [zef.h_ES_optimizer_properties.Name ' . ' vec.Properties.Description]; clear sr sc i_aux; -%zef = rmfield(zef,'table_aux'); + zef.h_optimizer_properties.Visible = zef.use_display; diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1.m index 1b19479d8..7a80d7b2f 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1.m @@ -12,7 +12,7 @@ scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'r','filled'); elseif ismember(i,ell_idx(2:5)) scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'b','filled'); - else + else scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'.','k'); end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1_fun.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1_fun.m index ebbc42292..28437e8e4 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1_fun.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_4x1_fun.m @@ -12,7 +12,7 @@ scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'r','filled'); elseif ismember(i,ell_idx(2:5)) scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'b','filled'); - else + else scatter3(sensors(i,1),sensors(i,2),sensors(i,3),'.','k'); end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_barplot.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_barplot.m index 4e1e2a047..53fe049bb 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_barplot.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_barplot.m @@ -31,15 +31,15 @@ function zef_ES_plot_barplot(varargin) end y_ES = vec.("ES Channels"){1,1}{sr, sc}; case {3} - try - vec = zef_ES_table(varargin{1}); - zef = evalin('base','zef'); - warning('ZI: No zef were called as an input argument.') - [sr, sc] = zef_ES_objective_function(zef, vec); - catch - vec = zef_ES_table(varargin{1}.y_ES_interval); - [sr, sc] = zef_ES_objective_function(varargin{1}, zef_ES_table(varargin{1}.y_ES_interval)); - end + try + vec = zef_ES_table(varargin{1}); + zef = evalin('base','zef'); + warning('ZI: No zef were called as an input argument.') + [sr, sc] = zef_ES_objective_function(zef, vec); + catch + vec = zef_ES_table(varargin{1}.y_ES_interval); + [sr, sc] = zef_ES_objective_function(varargin{1}, zef_ES_table(varargin{1}.y_ES_interval)); + end y_ES = vec.("ES Channels"){1,1}{sr, sc}; otherwise error('Too many input arguments.') @@ -83,8 +83,8 @@ function zef_ES_plot_barplot(varargin) max_current_montage = zef.ES_total_max_current; max_current_channel = zef.ES_max_current_channel; else - max_current_montage = 0.004; - max_current_channel = 0.002; + max_current_montage = 4; + max_current_channel = 2; end h_axes.XLim = [0 length(y_ES)]; @@ -116,9 +116,9 @@ function zef_ES_plot_barplot(varargin) grid on; if exist('zef','var') - h_fig.Visible = zef.use_display; - zef.h_ES_barplot = h_fig; - %h_barplot_ES = [h_axes; h_barplot_ES]; +h_fig.Visible = zef.use_display; +zef.h_ES_barplot = h_fig; +%h_barplot_ES = [h_axes; h_barplot_ES]; end -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_current_pattern.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_current_pattern.m index ee917d7d8..abfd80348 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_current_pattern.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_current_pattern.m @@ -190,8 +190,8 @@ function zef_ES_plot_current_pattern(varargin) sensor_explosion_parameter_1 = 3.25; sensor_explosion_parameter_2 = 0.1; h_ES_current(i) = surf( sensors(i,1)*(1 + sensor_explosion_parameter_2*exp(sensor_explosion_parameter_1 * ( (max(sensors(:,3)) - sensors(i,3)) / (max(sensors(:,3)) - min(sensors(:,3)))) )) + X_s, ... - sensors(i,2)*(1 + sensor_explosion_parameter_2*exp(sensor_explosion_parameter_1 * ( (max(sensors(:,3)) - sensors(i,3)) / (max(sensors(:,3)) - min(sensors(:,3)))) )) + Y_s, ... - max(sensors(:,3)) + Z_s ); + sensors(i,2)*(1 + sensor_explosion_parameter_2*exp(sensor_explosion_parameter_1 * ( (max(sensors(:,3)) - sensors(i,3)) / (max(sensors(:,3)) - min(sensors(:,3)))) )) + Y_s, ... + max(sensors(:,3)) + Z_s ); view(0,90) end @@ -231,4 +231,4 @@ function zef_ES_plot_current_pattern(varargin) zef.h_ES_current_coords = h_ES_current_coords; assignin('caller','zef',zef); -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_distance_curves.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_distance_curves.m index 3388197b5..7e86bf01c 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_distance_curves.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_distance_curves.m @@ -1,11 +1,11 @@ function zef = zef_ES_plot_distance_curves(zef) if nargin == 0 - zef = evalin('base','zef'); +zef = evalin('base','zef'); end -h_f = figure('Name','ZEFFIRO Interface: ES distance curves','NumberTitle','off', ... - 'ToolBar','figure','MenuBar','none'); + h_f = figure('Name','ZEFFIRO Interface: ES distance curves','NumberTitle','off', ... + 'ToolBar','figure','MenuBar','none'); distance_window = 10; n_distances = 2000; @@ -27,13 +27,13 @@ for i = 1 : n_distances - [position_ind] = find(distance_vec_aux >= distance_vec(i) & distance_vec_aux <= distance_vec(i)+distance_window); - amplitude_vec(i) = mean(amplitude_vec_aux(position_ind)); - angle_vec(i) = mean(180/pi*acos(sum(dipole_vec_aux(:,ones(1,length(position_ind))).*rec_vec_aux(:,position_ind)))); +[position_ind] = find(distance_vec_aux >= distance_vec(i) & distance_vec_aux <= distance_vec(i)+distance_window); +amplitude_vec(i) = mean(amplitude_vec_aux(position_ind)); +angle_vec(i) = mean(180/pi*acos(sum(dipole_vec_aux(:,ones(1,length(position_ind))).*rec_vec_aux(:,position_ind)))); end -subplot(2,1,1); +subplot(2,1,1); amplitude_vec = smooth(amplitude_vec,smooth_range); pbaspect([3 1 1]) hold on; @@ -46,12 +46,12 @@ vert_pos_3 = distance_vec(find(amplitude_vec <= quantile_aux_3,1)); I1 = find(distance_vec <= vert_pos_3); -fill([distance_vec(I1) ;distance_vec(I1(end)) ;distance_vec(I1(1)) ;distance_vec(I1(1))],[amplitude_vec(I1); 0; 0 ;amplitude_vec(I1(1))],'m') +fill([distance_vec(I1) ;distance_vec(I1(end)) ;distance_vec(I1(1)) ;distance_vec(I1(1))],[amplitude_vec(I1); 0; 0 ;amplitude_vec(I1(1))],'m') I2 = find(distance_vec <= vert_pos_2); I2 = setdiff(I2,I1); if not(isempty(I2)) - fill([distance_vec(I2) ;distance_vec(I2(end)) ;distance_vec(I2(1)) ;distance_vec(I2(1))],[amplitude_vec(I2); 0; 0 ;amplitude_vec(I2(1))],'c') +fill([distance_vec(I2) ;distance_vec(I2(end)) ;distance_vec(I2(1)) ;distance_vec(I2(1))],[amplitude_vec(I2); 0; 0 ;amplitude_vec(I2(1))],'c') end @@ -59,7 +59,7 @@ I3 = setdiff(I3, I1); I3 = setdiff(I3, I2); if not(isempty(I3)) - fill([distance_vec(I3) ;distance_vec(I3(end)) ;distance_vec(I3(1)) ;distance_vec(I3(1))],[amplitude_vec(I3); 0; 0 ;amplitude_vec(I3(1))],'g') +fill([distance_vec(I3) ;distance_vec(I3(end)) ;distance_vec(I3(1)) ;distance_vec(I3(1))],[amplitude_vec(I3); 0; 0 ;amplitude_vec(I3(1))],'g') end I4 = [1:length(distance_vec)]; @@ -67,7 +67,7 @@ I4 = setdiff(I4, I2); I4 = setdiff(I4, I3); if not(isempty(I4)) - fill([distance_vec(I4) ;distance_vec(I4(end)) ;distance_vec(I4(1)) ;distance_vec(I4(1))],[amplitude_vec(I4); 0; 0 ;amplitude_vec(I4(1))],'y') +fill([distance_vec(I4) ;distance_vec(I4(end)) ;distance_vec(I4(1)) ;distance_vec(I4(1))],[amplitude_vec(I4); 0; 0 ;amplitude_vec(I4(1))],'y') end set(gca,'ylim',[0 1.25*max(amplitude_vec)]) @@ -85,7 +85,7 @@ hold off -subplot(2,1,2); +subplot(2,1,2); angle_vec = smooth(angle_vec,smooth_range); pbaspect([3 1 1]) hold on; @@ -98,19 +98,19 @@ vert_pos_3 = distance_vec(find(angle_vec >= quantile_aux_3,1)); I1 = find(distance_vec <= vert_pos_3); -fill([distance_vec(I1) ;distance_vec(I1(end)) ;distance_vec(I1(1)) ;distance_vec(I1(1))],[angle_vec(I1); 0; 0 ;angle_vec(I1(1))],'m') +fill([distance_vec(I1) ;distance_vec(I1(end)) ;distance_vec(I1(1)) ;distance_vec(I1(1))],[angle_vec(I1); 0; 0 ;angle_vec(I1(1))],'m') I2 = find(distance_vec <= vert_pos_2); I2 = setdiff(I2,I1); if not(isempty(I2)) - fill([distance_vec(I2) ;distance_vec(I2(end)) ;distance_vec(I2(1)) ;distance_vec(I2(1))],[angle_vec(I2); 0; 0 ;angle_vec(I2(1))],'c') +fill([distance_vec(I2) ;distance_vec(I2(end)) ;distance_vec(I2(1)) ;distance_vec(I2(1))],[angle_vec(I2); 0; 0 ;angle_vec(I2(1))],'c') end I3 = find(distance_vec <= vert_pos_1); I3 = setdiff(I3, I1); I3 = setdiff(I3, I2); if not(isempty(I3)) - fill([distance_vec(I3) ;distance_vec(I3(end)) ;distance_vec(I3(1)) ;distance_vec(I3(1))],[angle_vec(I3); 0; 0 ;angle_vec(I3(1))],'g') +fill([distance_vec(I3) ;distance_vec(I3(end)) ;distance_vec(I3(1)) ;distance_vec(I3(1))],[angle_vec(I3); 0; 0 ;angle_vec(I3(1))],'g') end I4 = [1:length(distance_vec)]; @@ -118,7 +118,7 @@ I4 = setdiff(I4, I2); I4 = setdiff(I4, I3); if not(isempty(I4)) - fill([distance_vec(I4) ;distance_vec(I4(end)) ;distance_vec(I4(1)) ;distance_vec(I4(1))],[angle_vec(I4); 0; 0 ;angle_vec(I4(1))],'y') +fill([distance_vec(I4) ;distance_vec(I4(end)) ;distance_vec(I4(1)) ;distance_vec(I4(1))],[angle_vec(I4); 0; 0 ;angle_vec(I4(1))],'y') end set(gca,'ylim',[0 1.25*max(angle_vec)]) diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_error_chart.m b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_error_chart.m index df2af159c..386a58237 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_plot_error_chart.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_plot_error_chart.m @@ -29,10 +29,10 @@ function zef_ES_plot_error_chart(varargin) vec = zef_ES_table(arg_aux); end [sr, sc] = zef_ES_objective_function(zef, vec); - + case {3} [vec, sr, sc] = deal(varargin{1}, varargin{2}, varargin{2}); - + otherwise error('ZI: Invalid number of arguments.') end @@ -87,8 +87,8 @@ function printing_imagesc(vec, fieldnames_table, sr, sc) ax.YLabel.String = 'Nuisance field weight (dB)'; ax.YLabel.FontSize = 10; ax.YLabel.FontWeight = 'bold'; - ax.YTickLabel = {num2str((vec.('Beta'){:}),'%1.0f')}; - ax.YTick = 1:length(vec.('Beta'){:}); + ax.YTickLabel = {num2str((vec.('Epsilon'){:}),'%1.0f')}; + ax.YTick = 1:length(vec.('Epsilon'){:}); ax.YTickLabelRotation = 0; %%% Colorbar TickLabels @@ -119,7 +119,7 @@ function printing_imagesc(vec, fieldnames_table, sr, sc) plot(ax, sc, sr, 'yp','MarkerFaceColor','w','MarkerEdgeColor','w','MarkerSize',12); lgd = legend('Location','SouthWest', 'FontName', 'FixedWidth'); lgd.String(1) = {['\alpha : ' num2str((vec.('Alpha'){:}(sc)), '%1.0f')]}; - lgd.String(2) = {['\epsilon : ' num2str((vec.('Beta'){:}(sr)), '%1.0f')]}; + lgd.String(2) = {['\epsilon : ' num2str((vec.('Epsilon'){:}(sr)), '%1.0f')]}; lgd.AutoUpdate = 'off'; plot(ax, sc, sr, 'yp','MarkerFaceColor','y','MarkerEdgeColor','k','MarkerSize',12); @@ -138,4 +138,4 @@ function printing_imagesc(vec, fieldnames_table, sr, sc) assignin('caller','zef',zef); end -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_rwnnz.m b/plugins/ZeffiroESWorkbench/m/zef_ES_rwnnz.m index 0e6c36a00..1bee0df8f 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_rwnnz.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_rwnnz.m @@ -15,7 +15,7 @@ end if not(isequal(current_score_nnz_lim, 2)) - + sorted_y = sort(abs(y),'descend'); sorted_sum_y = sum(sorted_y); if sorted_sum_y == 0 @@ -31,18 +31,18 @@ current_score_ind = []; end end - + if not(isempty(current_score_ind)) y(current_score_ind) = 0; end - + else - + [~, y_positive] = max(y(:)); [~, y_negative] = min(y(:)); - + current_score_nnz = 2; - + y(setdiff(1:length(y), [y_negative y_positive])) = 0; end -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_table.m b/plugins/ZeffiroESWorkbench/m/zef_ES_table.m index eeda4a8ff..6d9c6b160 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_table.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_table.m @@ -1,45 +1,46 @@ function vec = zef_ES_table(data_aux) -%% Pre-allocate table and properties -var_names = {... - 'Residual', ... - 'Maximum current', ... - 'Sparsity (2-norm/1-norm) ratio',... - 'Focused current density', ... - 'Nuisance current density', ... - 'Angle error', ... - 'Relative magnitude difference', ... - 'Relative difference measure', ... - 'Field ratio',... - 'NNZ',... - 'Total dose', ... - 'Run time',... - 'Alpha', ... - 'Beta',... - 'Optimizer flag value',... - 'ES Channels', ... - }; -var_units = {'%' 'mA' '%' 'A/m^2' 'A/m^2' 'deg' '%' '%' '%' 'NNZ' 'mA' 's' 'dB' 'dB' 'flag' 'ell'}; +%% Pre-allocate table and properties + var_names = {... + 'Residual', ... + 'Maximum current', ... + 'Sparsity (2-norm/1-norm) ratio',... + 'Focused current density', ... + 'Nuisance current density', ... + 'Angle error', ... + 'Relative magnitude difference', ... + 'Relative difference measure', ... + 'Field ratio',... + 'NNZ',... + 'Total dose', ... + 'Run time',... + 'Alpha', ... + 'Epsilon',... + 'Optimizer flag value',... + 'ES Channels', ... + }; -meta_type = {... - 'minimum', ... - 'maximum', ... - 'maximum', ... - 'maximum', ... - 'minimum', ... - 'minimum', ... - 'minimum', ... - 'minimum', ... - 'maximum', ... - 'minimum', ... - 'minimum', ... - 'none', ... - 'none', ... - 'none', ... - 'none',... - 'none', ... - }; + var_units = {'%' 'mA' '%' 'A/m^2' 'A/m^2' 'deg' '%' '%' '%' 'NNZ' 'mA' 's' 'dB' 'dB' 'flag' 'ell'}; + meta_type = {... + 'minimum', ... + 'maximum', ... + 'maximum', ... + 'maximum', ... + 'minimum', ... + 'minimum', ... + 'minimum', ... + 'minimum', ... + 'maximum', ... + 'minimum', ... + 'minimum', ... + 'none', ... + 'none', ... + 'none', ... + 'none',... + 'none', ... + }; + if nargin == 0 residual = []; max_current = []; @@ -54,7 +55,7 @@ y_ES = []; run_time = []; alpha = []; - beta = []; + epsilon = []; flag_value = []; channels = []; else @@ -72,7 +73,7 @@ run_time = cell2mat(data_aux.run_time); flag_value = cell2mat(data_aux.flag); alpha = db(data_aux.alpha); - beta = db(data_aux.beta); + epsilon = db(data_aux.epsilon); channels = data_aux.y_ES; for i_aux = 1:size(data_aux.y_ES, 1) @@ -98,7 +99,7 @@ y_ES ... run_time,... alpha, ... - beta, ... + epsilon, ... flag_value, ... channels... }); @@ -106,4 +107,4 @@ vec = array2table(vec_temp, 'VariableNames', var_names); vec.Properties.VariableUnits = var_units; vec.Properties.VariableDescriptions = meta_type; -end +end \ No newline at end of file diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_update_parameter_values.m b/plugins/ZeffiroESWorkbench/m/zef_ES_update_parameter_values.m index 2e601b5f0..b417dc4e6 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_update_parameter_values.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_update_parameter_values.m @@ -7,6 +7,7 @@ zef.ES_total_max_current = str2double(zef.h_ES_parameter_table.Data{1,2}); zef.ES_max_current_channel = str2double(zef.h_ES_parameter_table.Data{2,2}); zef.ES_relative_weight_nnz = str2double(zef.h_ES_parameter_table.Data{3,2}); + zef.ES_score_dose = str2double(zef.h_ES_parameter_table.Data{4,2}); zef.ES_boundary_color_limit = str2double(zef.h_ES_parameter_table.Data{5,2}); zef.ES_roi_range = str2double(zef.h_ES_parameter_table.Data{6,2}); @@ -20,11 +21,13 @@ function zef = assign_common_parameters(zef) zef.ES_alpha = 10^(str2double(zef.h_ES_parameter_table.Data{1,2})/20); zef.ES_alpha_max = 10^(str2double(zef.h_ES_parameter_table.Data{2,2})/20); -zef.ES_beta_min = 10^(str2double(zef.h_ES_parameter_table.Data{3,2})/20); -zef.ES_beta = 10^(str2double(zef.h_ES_parameter_table.Data{4,2})/20); +zef.ES_epsilon_min = 10^(str2double(zef.h_ES_parameter_table.Data{3,2})/20); +zef.ES_epsilon = 10^(str2double(zef.h_ES_parameter_table.Data{4,2})/20); + zef.ES_total_max_current = str2double(zef.h_ES_parameter_table.Data{5,2}); zef.ES_max_current_channel = str2double(zef.h_ES_parameter_table.Data{6,2}); zef.ES_relative_weight_nnz = str2double(zef.h_ES_parameter_table.Data{7,2}); + zef.ES_score_dose = str2double(zef.h_ES_parameter_table.Data{8,2}); zef.ES_step_size = str2double(zef.h_ES_parameter_table.Data{9,2}); zef.ES_source_density = str2double(zef.h_ES_parameter_table.Data{10,2}); diff --git a/plugins/ZeffiroESWorkbench/m/zef_cvx_linprog.m b/plugins/ZeffiroESWorkbench/m/zef_cvx_linprog.m index 7a3d99c7b..9a7a7007c 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_cvx_linprog.m +++ b/plugins/ZeffiroESWorkbench/m/zef_cvx_linprog.m @@ -4,7 +4,7 @@ %otherwise) %Arguments: z (size: [n x 1]), A (size: [m x n]), b %(size: [m x 1]) -%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) +%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) @@ -17,7 +17,7 @@ function_val = []; if not(isempty(varargin)) - opts = varargin{1}; + opts = varargin{1}; end flag_val = -2; @@ -28,7 +28,7 @@ end try - cvx_solver(solver_package) +cvx_solver(solver_package) end if isfield(opts,'TolFun') @@ -36,42 +36,42 @@ end if isequal(opts.Display,'off') - cvx_begin quiet - variable x(n) - minimize sum(z.*x) - subject to: - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end - cvx_end +cvx_begin quiet +variable x(n) +minimize sum(z.*x) +subject to: +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end +cvx_end else - cvx_begin - variable x(n) - minimize sum(z.*x) - subject to: - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end - cvx_end + cvx_begin +variable x(n) +minimize sum(z.*x) +subject to: +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end +cvx_end end if isequal(cvx_status,'Solved') - flag_val = 1; + flag_val = 1; function_val = norm(A*x-b,1); - + end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_cvx_quadprog.m b/plugins/ZeffiroESWorkbench/m/zef_cvx_quadprog.m index 7639e237b..5b466573f 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_cvx_quadprog.m +++ b/plugins/ZeffiroESWorkbench/m/zef_cvx_quadprog.m @@ -4,7 +4,7 @@ %otherwise) %Arguments: z (size: [n x 1]), A (size: [m x n]), b %(size: [m x 1]) -%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) +%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) @@ -17,7 +17,7 @@ function_val = []; if not(isempty(varargin)) - opts = varargin{1}; + opts = varargin{1}; end flag_val = -2; @@ -28,7 +28,7 @@ end try - cvx_solver(solver_package) +cvx_solver(solver_package) end if isfield(opts,'TolVal') @@ -37,44 +37,44 @@ if isequal(opts.Display,'off') - cvx_begin quiet - variable x(n) - minimize norm(Q*x-z) - subject to: - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end +cvx_begin quiet +variable x(n) +minimize norm(Q*x-z) +subject to: +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end - cvx_end +cvx_end else - cvx_begin - variable x(n) - minimize 0.5*sum(x.*(Q*x)) + sum(z'.*x) - subject to: - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end + cvx_begin +variable x(n) +minimize 0.5*sum(x.*(Q*x)) + sum(z'.*x) +subject to: +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end - cvx_end +cvx_end end if isequal(cvx_status,'Solved') - flag_val = 1; + flag_val = 1; function_val = norm(A*x-b,1); - + end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_cvx_semidefprog.m b/plugins/ZeffiroESWorkbench/m/zef_cvx_semidefprog.m index 67bb70ba3..d2fee1376 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_cvx_semidefprog.m +++ b/plugins/ZeffiroESWorkbench/m/zef_cvx_semidefprog.m @@ -4,7 +4,7 @@ %otherwise) %Arguments: z (size: [n x 1]), A (size: [m x n]), b %(size: [m x 1]) -%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) +%Variable argument list: max_1_norm (size: [1 x 1], maximum 1-norm for x), max_infty_norm (size: [1 x 1], maximum infinity norm for x) @@ -17,7 +17,7 @@ solver_package = 'sdpt3'; if not(isempty(varargin)) - opts = varargin{1}; + opts = varargin{1}; end flag_val = -2; @@ -28,7 +28,7 @@ end try - cvx_solver(solver_package) +cvx_solver(solver_package) end if isfield(opts,'TolVal') @@ -37,47 +37,47 @@ if isequal(opts.Display,'off') - cvx_begin quiet - variable x(n) - minimize(norm(z.*x) + sum(y.*x)) - subject to: +cvx_begin quiet +variable x(n) +minimize(norm(z.*x) + sum(y.*x)) +subject to: - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end - cvx_end +cvx_end else - cvx_begin quiet - variable x(n) - minimize(norm(z.*x) + sum(y.*x)) - subject to: - - A*x - b <= 0; %#ok<*VUNUS> - if not(isempty(lb)) - x >= lb; - end - if not(isempty(ub)) - x <= ub; - end - if not(isempty(Aeq)) - Aeq*x == beq; - end - - cvx_end + cvx_begin quiet +variable x(n) +minimize(norm(z.*x) + sum(y.*x)) +subject to: + +A*x - b <= 0; %#ok<*VUNUS> +if not(isempty(lb)) +x >= lb; +end +if not(isempty(ub)) +x <= ub; +end +if not(isempty(Aeq)) +Aeq*x == beq; +end + +cvx_end end if isequal(cvx_status,'Solved') - flag_val = 1; + flag_val = 1; function_val = norm(A*x-b,1); - + end end diff --git a/plugins/ZeffiroESWorkbench/m/zef_mosek_linprog.m b/plugins/ZeffiroESWorkbench/m/zef_mosek_linprog.m index 52db025a7..326c0d6e4 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_mosek_linprog.m +++ b/plugins/ZeffiroESWorkbench/m/zef_mosek_linprog.m @@ -1,30 +1,30 @@ function [x,fval,exitflag] = zef_mosek_linprog(f,A,b,Aeq,beq,lb,ub,options) exitflag = -1; -fval = []; +fval = []; x = []; if nargin < 4 - Aeq = []; + Aeq = []; end if nargin < 5 - beq = []; +beq = []; end if nargin > 5 if not(isempty(lb)) - model.lb = lb; - else - model.lb = -Inf*ones(size(A,2),1); +model.lb = lb; +else + model.lb = -Inf*ones(size(A,2),1); + end end -end if nargin > 6 if not(isempty(ub)) - model.ub = ub; - else - model.ub = Inf*ones(size(A,2),1); +model.ub = ub; +else + model.ub = Inf*ones(size(A,2),1); end end @@ -34,23 +34,23 @@ param.MSK_DPAR_BASIS_TOL_S = options.TolFun; param.MSK_DPAR_OPTIMIZER_MAX_TIME = options.MaxTime; if isequal(lower(options.Algorithm),'interior-point') - param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_INTPNT'; +param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_INTPNT'; elseif isequal(lower(options.Algorithm),'primal-simplex') - param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_PRIMAL_SIMPLEX'; -elseif isequal(lower(options.Algorithm),'dual-simplex') - param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_DUAL_SIMPLEX'; + param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_PRIMAL_SIMPLEX'; + elseif isequal(lower(options.Algorithm),'dual-simplex') + param.MSK_IPAR_OPTIMIZER = 'MSK_OPTIMIZER_DUAL_SIMPLEX'; end -n = length(f); +n = length(f); [r,b,beq,lb,ub] = mskcheck('linprog',verb,n,size(A),b,size(Aeq),beq,lb,ub); if not(isequal(r,0)) - exitflag = r; - output = []; - fval = []; - lambda = []; - return; -end + exitflag = r; + output = []; + fval = []; + lambda = []; + return; +end model = []; [n_ineq,t] = size(A); @@ -58,10 +58,10 @@ model.c = reshape(f,n,1); model.a = [A;Aeq]; if ( isempty(model.a) ) - model.a = sparse(0,length(f)); + model.a = sparse(0,length(f)); elseif not(issparse(model.a)) - model.a = sparse(model.a); -end + model.a = sparse(model.a); +end model.blc = [-inf*ones(size(b));beq]; model.buc = [b;beq]; model.blx = lb; @@ -71,23 +71,23 @@ [rcode,res] = mosekopt(cmd,model,param); mskstatus('linprog',verb,0,rcode,res); - + if ( isfield(res,'sol') ) - if ( isfield(res.sol,'itr') ) - x = res.sol.itr.xx; - else - x = res.sol.bas.xx; - end + if ( isfield(res.sol,'itr') ) + x = res.sol.itr.xx; + else + x = res.sol.bas.xx; + end else - x = []; + x = []; end if isequal(length(model.c), length(x)) - fval = model.c'*x; + fval = model.c'*x; else - fval = []; + fval = []; end -exitflag = mskeflag(rcode,res); + exitflag = mskeflag(rcode,res); -end +end \ No newline at end of file From 5fc67a185937865b9d808843ba6863b57ae452bf Mon Sep 17 00:00:00 2001 From: GitFernandoGalaz Date: Thu, 30 Nov 2023 11:58:46 +0200 Subject: [PATCH 3/7] Update zef_ES_find_currents.m --- plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m index 8f428516a..654c017b1 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m @@ -108,12 +108,8 @@ error('ZI: No discretized sources found. Perhaps you forgot to calculate or load them...?') end %% waitbar -zef.use_waitbar = 0; -if zef.use_waitbar == 1 - wait_bar_temp = zef_waitbar(... - [0 0], ... - sprintf(['Optimizer: ' zef_data.solver_package ', ' 'Algorithm: ' zef_data.opts.Algorithm ', Optimizing: i = %d, j = d%' '.'], 0, 0)... - ); +if zef.use_waitbar == 1 && ~strcmpi(zef.ES_opt_method_list{zef.ES_opt_method},'Backpropagation') + wait_bar_temp = zef_waitbar([0 0],'ES Workbench'); end %% The real task... zef.y_ES_interval = []; @@ -228,4 +224,4 @@ %assignin('base','zef',zef); assignin('caller','zef',zef); end -end \ No newline at end of file +end From ba85772ad005e5d55b09fa4315d8ad3ad9fb5517 Mon Sep 17 00:00:00 2001 From: GitFernandoGalaz Date: Thu, 30 Nov 2023 12:17:26 +0200 Subject: [PATCH 4/7] Update zef_ES_find_currents.m --- plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m index 654c017b1..ec00a260c 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_find_currents.m @@ -109,7 +109,7 @@ end %% waitbar if zef.use_waitbar == 1 && ~strcmpi(zef.ES_opt_method_list{zef.ES_opt_method},'Backpropagation') - wait_bar_temp = zef_waitbar([0 0],'ES Workbench'); + wait_bar_temp = zef_waitbar(0,1,['ES Workbench']); end %% The real task... zef.y_ES_interval = []; From 36b064f971cdaabb922dbb9ab5fd5032690b0132 Mon Sep 17 00:00:00 2001 From: GitFernandoGalaz Date: Thu, 30 Nov 2023 13:41:36 +0200 Subject: [PATCH 5/7] Update zef_ES_optimization_init.m --- .../ZeffiroESWorkbench/m/zef_ES_optimization_init.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m index 61c9afc58..1c2bef10b 100644 --- a/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m +++ b/plugins/ZeffiroESWorkbench/m/zef_ES_optimization_init.m @@ -24,14 +24,14 @@ if not(isfield(zef,'gurobi_path')) zef.gurobi_path = ''; end -if not(isfield(zef,'ES_effective_nnz')) %??? +if not(isfield(zef,'ES_effective_nnz')) zef.ES_effective_nnz = 20; end -if not(isfield(zef,'ES_score_dose')) %% number of electrodes??? +if not(isfield(zef,'ES_score_dose')) zef.ES_score_dose = 20; end if not(isfield(zef,'ES_obj_fun')) - zef.ES_obj_fun = 2; + zef.ES_obj_fun = 4; end if not(isfield(zef,'ES_obj_fun_2')) zef.ES_obj_fun_2 = 4; @@ -54,6 +54,9 @@ if not(isfield(zef,'ES_total_max_current')) zef.ES_total_max_current = 0.004; end +if not(isfield(zef,'ES_max_current_channel')) + zef.ES_max_current_channel = 0.002; +end if not(isfield(zef,'ES_relative_weight_nnz')) zef.ES_relative_weight_nnz = 1e-3; end @@ -125,4 +128,4 @@ end if not(isfield(zef,'ES_HPO_recursive_instances')) zef.ES_HPO_recursive_instances = 3; -end \ No newline at end of file +end From aa46ed93428fac12b833e31173ad69948fcc909d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santtu=20S=C3=B6derholm?= Date: Tue, 5 Dec 2023 14:36:53 +0200 Subject: [PATCH 6/7] Add Sampsa's changes to NSE Tool and its dependecies in m/ - Apparently there was a mix-up with folder contents, so NSE Tool needed fixing. --- m/barycentric/zef_surface_scalar_vector_Fn.m | 2 +- .../nse/zef_nse_poisson_dynamic.m | 84 ++++++++++- .../NSE_tool/m/zef_nse_calculate_perfusion.m | 56 +++++++ plugins/NSE_tool/m/zef_nse_dir_v_node.m | 16 ++ .../NSE_tool/m/zef_nse_mean_velocity_roi.m | 2 +- plugins/NSE_tool/m/zef_nse_plot_epoched.m | 54 ++++++- plugins/NSE_tool/m/zef_nse_plot_graph.m | 41 +++-- plugins/NSE_tool/m/zef_nse_plot_roi.m | 9 +- .../NSE_tool/m/zef_nse_separate_waves_roi.m | 142 +++++++++++------- plugins/NSE_tool/m/zef_nse_tool_init.m | 12 ++ plugins/NSE_tool/m/zef_nse_tool_window.m | 23 ++- plugins/NSE_tool/m/zef_nse_vel_dir.m | 10 ++ plugins/NSE_tool/mlapp/zef_nse_app.mlapp | Bin 67463 -> 70041 bytes 13 files changed, 364 insertions(+), 87 deletions(-) create mode 100644 plugins/NSE_tool/m/zef_nse_calculate_perfusion.m create mode 100644 plugins/NSE_tool/m/zef_nse_dir_v_node.m create mode 100644 plugins/NSE_tool/m/zef_nse_vel_dir.m diff --git a/m/barycentric/zef_surface_scalar_vector_Fn.m b/m/barycentric/zef_surface_scalar_vector_Fn.m index 3b753861a..b97d22eb7 100644 --- a/m/barycentric/zef_surface_scalar_vector_Fn.m +++ b/m/barycentric/zef_surface_scalar_vector_Fn.m @@ -38,7 +38,7 @@ N = size(nodes,1); -if nargin < 3 +if nargin < 4 scalar_field = ones(size(tetra,1),1); end diff --git a/m/forward_simulation/nse/zef_nse_poisson_dynamic.m b/m/forward_simulation/nse/zef_nse_poisson_dynamic.m index f15cf378f..f0fcf2a31 100644 --- a/m/forward_simulation/nse/zef_nse_poisson_dynamic.m +++ b/m/forward_simulation/nse/zef_nse_poisson_dynamic.m @@ -74,6 +74,11 @@ area_arteries = sum(area(I)); param_aux_integral_mean = param_aux_integral_mean/area_arteries; +param_aux_ones = zeros(size(param_aux)); +param_aux_ones(t_ind) = 1; +w_3 = zef_surface_scalar_vector_F(v_1_nodes, v_1_tetra, param_aux_ones); +sum_w_3 = sum(w_3); + gravity_amplitude = nse_field.gravity_amplitude; gravity_x = nse_field.gravity_x; gravity_y = nse_field.gravity_y; @@ -110,6 +115,10 @@ Q_2_v1 = spdiags(1./c_vec,0,size(v_1_nodes,1),size(v_1_nodes,1))*Q_2; Q_3_v1 = spdiags(1./c_vec,0,size(v_1_nodes,1),size(v_1_nodes,1))*Q_3; +Q_1_v12 = Q_1_v1; +Q_2_v12 = Q_2_v1; +Q_3_v12 = Q_3_v1; + Q_1_v2 = Q_1_v1(:,i_node_ind); Q_2_v2 = Q_2_v1(:,i_node_ind); Q_3_v2 = Q_3_v1(:,i_node_ind); @@ -268,15 +277,15 @@ end KDMD = @(x) zef_KDMD(x,K_1,M_1,D_1,nse_field.use_gpu); - + for i = 1 : n_time pressure_aux = (p + pressure_reference + p_hydrostatic)/hgmm_conversion; - total_flow_aux = sum(sqrt(u_1.^2 + u_2.^2 + u_3.^2).*w_1)/(ml_min_conversion); + total_flow_aux = (sum(((p + pressure_reference)/hgmm_conversion).*w_3)/sum_w_3)*nse_field.total_flow/nse_field.pressure; zef_waitbar(i,n_time,h_waitbar,['NSE solver: compute, total flow (ml/min): ' sprintf('%0.3g',total_flow_aux) ', 90 % pressure quantile (Hgmm): ' sprintf('%0.3g',quantile(pressure_aux,0.9)) ', 10 % pressure quantile (Hgmm): ' sprintf('%0.3g',quantile(pressure_aux,0.1)) '.']); y_0 = y(i); - + for quadrature_step_ind = 1 : n_q_steps if nse_field.nse_type == 2 @@ -311,8 +320,10 @@ if quadrature_step_ind == 1 if i == 1 b = D_1 * (M_1 * (D_1 * (p_1 + source_vec * (y_0 - 2*y_1)))); + else - b = D_1 * (M_1 * (D_1 * (2*p_1 - p_2 + source_vec * (y_0 - 2*y_1 + y_2)))); + b = D_1 * (M_1 * (D_1 * (2*p_1 - p_2 + source_vec * (y_0 - 2*y_1 + y_2)))); + end g_mu_1 = Q_1_v1*mu_vec(i_node_ind); @@ -364,6 +375,8 @@ p_2 = p_1; p_1 = p; + max(p_1); + min(p_1); y_2 = y_1; y_1 = y_0; @@ -411,7 +424,7 @@ bp_vessels_aux(nse_field.bp_vessel_node_ind) = abs(p + pressure_reference); bf_vessels_to_capillaries = bp_vessels_aux(nse_field.bf_capillary_node_ind); I_boundary = find(bf_vessels_to_capillaries); - total_flow_estimate= sum(sqrt(u_1.^2 + u_2.^2 + u_3.^2).*w_1); + total_flow_estimate = (sum(((p + pressure_reference)/hgmm_conversion).*w_3)/sum_w_3)*nse_field.total_flow/nse_field.pressure; r = total_flow_estimate*bf_vessels_to_capillaries./sum(pressure_reference.*w_2(I_boundary)); if nse_field.use_gpu @@ -487,29 +500,82 @@ end end + + u_1_2 = zeros(size(K_1,1),1); + u_1_2(i_node_ind,1) = u_1; + u_2_2 = zeros(size(K_1,1),1); + u_2_2(i_node_ind,1) = u_2; + u_3_2 = zeros(size(K_1,1),1); + u_3_2(i_node_ind,1) = u_3; +% collect1{i}=gather(u_1_2); +% collect2{i}=gather(u_2_2); +% collect3{i}=gather(u_3_2); + % trace_strain_rate2 = rateofshear(adj1,dist1,u_1_2,u_2_2,u_3_2); +% trace_strain_rate = Q_1_v12*u_1_2; + trace_strain_rate = 4.*(Q_1_v12*u_1_2).^2 + 4.*(Q_2_v12*u_2_2).^2 + 4.*(Q_3_v12*u_3_2).^2 + 2.*(Q_2_v12*u_1_2+Q_1_v12*u_2_2).^2 +... + 2.*(Q_3_v12*u_1_2+Q_1_v12*u_3_2).^2+2.*(Q_3_v12*u_2_2+Q_2_v12*u_3_2).^2; + trace_strain_rate = sqrt((1/2).*trace_strain_rate); +% if i >= n_time*0.5 if nse_field.viscosity_model == 2 - trace_strain_rate = abs(Q_1_v2*u_1) + abs(Q_2_v2*u_2) + abs(Q_3_v2*u_3); +% trace_strain_rate = abs(Q_1_v2*u_1) + abs(Q_2_v2*u_2) + abs(Q_3_v2*u_3); mu_vec = nse_field.mu*trace_strain_rate.^(nse_field.viscosity_exponent-1); elseif nse_field.viscosity_model == 3 - trace_strain_rate = abs(Q_1_v2*u_1) + abs(Q_2_v2*u_2) + abs(Q_3_v2*u_3); +% trace_strain_rate = abs(Q_1_v2*u_1) + abs(Q_2_v2*u_2) + abs(Q_3_v2*u_3); mu_vec = nse_field.mu + nse_field.viscosity_delta.*(1 + (nse_field.viscosity_relaxation_time*trace_strain_rate).^nse_field.viscosity_transition).^((nse_field.viscosity_exponent-1)./nse_field.viscosity_transition); + + elseif nse_field.viscosity_model == 4 + + C1 = 0.00797; + C2 = 0.0608; + C3 = 0.00499; + C4 = 14.585; + Hem = 40; + TPMA = 25.9; + mu_vec = 0.1*C1*exp(C2*Hem)*exp(C4*(TPMA/(Hem^2))).*trace_strain_rate.^-(C3*Hem); + mu_vec(mu_vec>0.056) = 0.056; + mu_vec(mu_vec<0.00345) = 0.00345; + elseif nse_field.viscosity_model == 5 + + lambda_g = zeros(size(K_1,1),1); + n_g = zeros(size(K_1,1),1); +% trace_strain_rate2 = abs(Q_1_v2*u_1) + abs(Q_2_v2*u_2) + abs(Q_3_v2*u_3); +% trace_strain_rate = rateofshear(kk,u_1_2,u_2_2,u_3_2); + lambda_g(trace_strain_rate>0.01) = 0.0345 + 0.25.*exp(-(1+trace_strain_rate(trace_strain_rate>0.01)./50).*exp(-3.*(trace_strain_rate(trace_strain_rate>0.01)).^-1)); + n_g(trace_strain_rate>0.01) = 1 - 0.45.*exp(-(1+trace_strain_rate(trace_strain_rate>0.01)./50).*exp(-4.*(trace_strain_rate(trace_strain_rate>0.01)).^-1)); + mu_vec(trace_strain_rate>0.01) = 0.1*lambda_g(trace_strain_rate>0.01).*trace_strain_rate(trace_strain_rate>0.01).^(n_g(trace_strain_rate>0.01)-1); + mu_vec(trace_strain_rate<=0.01)=0.056; + mu_vec(mu_vec>0.056) = 0.056; + mu_vec(mu_vec<0.00345)=0.00345; + + elseif nse_field.viscosity_model == 6 + mu_vec(trace_strain_rate>0.4e-3) = (sqrt(0.0012*((1-0.35)^(-5/2))) + sqrt(0.01*((0.625*0.35)^3)./trace_strain_rate(trace_strain_rate>0.4e-3))).^2; + mu_vec(mu_vec>0.056) = 0.056; + mu_vec(mu_vec<0.00345)=0.00345; end +% end - if ismember(nse_field.viscosity_model,[2 3]) + + if ismember(nse_field.viscosity_model,[2 3 4 5 6])%2 3 4 5 6 if nse_field.viscosity_smoothing > 0 if nse_field.use_gpu mu_vec = pcg_iteration_gpu(S_mu,I_mu*mu_vec,nse_field.pcg_tol,nse_field.pcg_maxit,DM_S_mu); + strain_rate2 = pcg_iteration_gpu(S_mu,I_mu*trace_strain_rate,nse_field.pcg_tol,nse_field.pcg_maxit,DM_S_mu); else mu_vec = pcg_iteration(S_mu,I_mu*mu_vec,nse_field.pcg_tol,nse_field.pcg_maxit,DM_S_mu); + strain_rate2 = pcg_iteration(S_mu,I_mu*trace_strain_rate,nse_field.pcg_tol,nse_field.pcg_maxit,DM_S_mu); end + else + strain_rate2 = trace_strain_rate; end D_1 = spdiags(sqrt(mu_vec),0,size(M_1,1),size(M_1,2)); KDMD = @(x) zef_KDMD(x,K_1,M_1,D_1,nse_field.use_gpu); + else + strain_rate2 = trace_strain_rate; end @@ -517,6 +583,7 @@ i_aux = i_aux + 1; + nse_field.shearrate1{i_aux} = zeros(size(K_1,1),1); nse_field.bp_vessels{i_aux} = zeros(size(K_1,1),1); nse_field.mu_vessels{i_aux} = zeros(size(K_1,1),1); nse_field.bv_vessels_1{i_aux} = zeros(size(K_1,1),1); @@ -526,6 +593,7 @@ nse_field.bv_vessels_2{i_aux}(i_node_ind) = gather(u_2); nse_field.bv_vessels_3{i_aux}(i_node_ind) = gather(u_3); nse_field.bp_vessels{i_aux} = gather(p)/hgmm_conversion + gather(p_hydrostatic)/hgmm_conversion + gather(pressure_reference)/hgmm_conversion; + nse_field.shearrate1{i_aux} = gather(strain_rate2); nse_field.mu_vessels{i_aux} = gather(mu_vec); if nse_field.microcirculation_model nse_field.bf_capillaries{i_aux} = gather(mc_vec); diff --git a/plugins/NSE_tool/m/zef_nse_calculate_perfusion.m b/plugins/NSE_tool/m/zef_nse_calculate_perfusion.m new file mode 100644 index 000000000..b79c80eb8 --- /dev/null +++ b/plugins/NSE_tool/m/zef_nse_calculate_perfusion.m @@ -0,0 +1,56 @@ +function perfusion_estimate = zef_nse_calculate_perfusion(nse_field,nodes,tetra,domain_labels,mvd_length) + +mm_conversion = 0.001; +ml_min_conversion = 1e-6/60; +hgmm_conversion = 101325/760; + +mvd_length = 1E6.*mvd_length(:,1); + +c_ind_1_domain = find(ismember(domain_labels,nse_field.artery_domain_ind)); +[v_1_nodes, v_1_tetra, nse_field.bp_vessel_node_ind] = zef_get_submesh(nodes, tetra, c_ind_1_domain); +v_1_nodes = mm_conversion*v_1_nodes; +[~, det] = zef_volume_barycentric(v_1_nodes,v_1_tetra); +volume = abs(det)/6; + +[~,~,t_ind,~,~,~,~,f_ind] = zef_surface_mesh(v_1_tetra); +[t_ind_2, f_ind_2] = zef_find_adjacent_tetra(tetra, c_ind_1_domain(t_ind), f_ind); +[b_vec,det] = zef_volume_barycentric(v_1_nodes,v_1_tetra(t_ind,:),f_ind); +area = (abs(det)/2).*sqrt(sum(b_vec(:,1:3).^2,2)); + +param_aux = zeros(length(c_ind_1_domain),1); +param_aux(t_ind) = mvd_length(t_ind_2); +param_aux_integral_mean = zef_surface_scalar_vector_F(v_1_nodes, v_1_tetra, param_aux); +param_aux_integral_mean = sum(param_aux_integral_mean); +I = find(param_aux(t_ind)); +area_arteries = sum(area(I)); + +param_aux_ones = zeros(size(param_aux)); +param_aux_ones(t_ind) = 1; +w_3 = zef_surface_scalar_vector_F(v_1_nodes, v_1_tetra,param_aux_ones); +perfusion_estimate = zeros(size(nse_field.bv_vessels_1,2),1); + +gravity_amplitude = nse_field.gravity_amplitude; +gravity_x = nse_field.gravity_x; +gravity_y = nse_field.gravity_y; +gravity_z = nse_field.gravity_z; + +gravity_vec = gravity_x.*v_1_nodes(:,1) + gravity_y.*v_1_nodes(:,2) + gravity_z.*v_1_nodes(:,3); +gravity_vec = gravity_vec - min(gravity_vec); +p_hydrostatic = nse_field.rho*gravity_vec; + +%n_1 = zef_surface_scalar_vector_Fn(v_1_nodes, v_1_tetra, 1); +%n_2 = zef_surface_scalar_vector_Fn(v_1_nodes, v_1_tetra, 2); +%n_3 = zef_surface_scalar_vector_Fn(v_1_nodes, v_1_tetra, 3); + +for i = 1 : size(nse_field.bv_vessels_1,2) + +perfusion_estimate(i) = (sum((nse_field.bp_vessels{i}-p_hydrostatic/hgmm_conversion).*w_3)/sum(w_3))*nse_field.total_flow/nse_field.pressure; + +end + +end + + + + + diff --git a/plugins/NSE_tool/m/zef_nse_dir_v_node.m b/plugins/NSE_tool/m/zef_nse_dir_v_node.m new file mode 100644 index 000000000..31e2afc65 --- /dev/null +++ b/plugins/NSE_tool/m/zef_nse_dir_v_node.m @@ -0,0 +1,16 @@ +h_axes = gca; +if isempty(findobj(allchild(h_axes),'Type','DataTip'))~=1 + h_datatip = findobj(allchild(h_axes),'Type','DataTip'); + zef.nse_field.dir_v_x = []; + zef.nse_field.dir_v_y = []; + zef.nse_field.dir_v_z = []; + for i=1:size(h_datatip,1) + zef.nse_field.dir_v_x = [zef.nse_field.dir_v_x h_datatip(i).X]; + zef.nse_field.dir_v_y = [zef.nse_field.dir_v_y h_datatip(i).Y]; + zef.nse_field.dir_v_z = [zef.nse_field.dir_v_z h_datatip(i).Z]; + end + zef.nse_field.h_dir_v_x.Value = num2str(zef.nse_field.dir_v_x); + zef.nse_field.h_dir_v_y.Value = num2str(zef.nse_field.dir_v_y); + zef.nse_field.h_dir_v_z.Value = num2str(zef.nse_field.dir_v_z); + +end diff --git a/plugins/NSE_tool/m/zef_nse_mean_velocity_roi.m b/plugins/NSE_tool/m/zef_nse_mean_velocity_roi.m index 3e99deb12..b0b3e6057 100644 --- a/plugins/NSE_tool/m/zef_nse_mean_velocity_roi.m +++ b/plugins/NSE_tool/m/zef_nse_mean_velocity_roi.m @@ -10,7 +10,7 @@ v_2 = v_2 + mean(zef.nse_field.bv_vessels_2{i}(roi_ind)); v_3 = v_3 + mean(zef.nse_field.bv_vessels_3{i}(roi_ind)); end -v_vec = [v_1 v_2 v_3]./length(nse_field.bv_vessels_1); +v_vec = [v_1 v_2 v_3]./length(zef.nse_field.bv_vessels_1); v_mag = sqrt(sum(v_vec.^2)); v_dir = v_vec/v_mag; diff --git a/plugins/NSE_tool/m/zef_nse_plot_epoched.m b/plugins/NSE_tool/m/zef_nse_plot_epoched.m index 46fb44b10..e0b9a09b2 100755 --- a/plugins/NSE_tool/m/zef_nse_plot_epoched.m +++ b/plugins/NSE_tool/m/zef_nse_plot_epoched.m @@ -1,11 +1,19 @@ -function zef_nse_plot_epoched(zef, nse_field, plot_vec, y_label) +function zef_nse_plot_epoched(zef, nse_field, plot_vec, y_label, plot_vec_ref) h_axes = zef.h_axes1; axes(h_axes); +perform_shift = true; + +if nargin < 5 +plot_vec_ref = []; +elseif isempty(plot_vec_ref) + perform_shift = false; +end + plot_colors = {'c', 'c'}; -plot_quantiles = [ 0.25 0.5 0.75]; +plot_quantiles = [ 0.0 0.5 1]; plot_linestyle = {'--','-','--'}; n_time = length(plot_vec); time_step_length_aux = (nse_field.time_length - nse_field.start_time)/(n_time-1); @@ -13,22 +21,60 @@ function zef_nse_plot_epoched(zef, nse_field, plot_vec, y_label) n_epoch = find(time_vec_aux-nse_field.start_time >= nse_field.cycle_length,1,'first')-1; epoch_data = zeros(n_epoch,ceil(n_time/n_epoch)); +if not(isempty(plot_vec_ref)) + epoch_data_2 = epoch_data; +end for i = 1 : ceil(n_time/n_epoch) start_ind = n_epoch*(i-1)+1; end_ind = min(n_time,n_epoch*i); epoch_data(1:end_ind-start_ind+1,i) = plot_vec(start_ind:end_ind); +if not(isempty(plot_vec_ref)) +epoch_data_2(1:end_ind-start_ind+1,i) = plot_vec_ref(start_ind:end_ind); +end end plot_data = zeros(n_epoch,length(plot_quantiles)); +if not(isempty(plot_vec_ref)) +plot_data_2 = plot_data; +end + +if end_ind-start_ind+1 < size(epoch_data,1) + epoch_data(end_ind-start_ind+2:end,end) = mean(epoch_data(end_ind-start_ind+2:end,1:end-1),2); +if not(isempty(plot_vec_ref)) +epoch_data_2(end_ind-start_ind+2:end,end) = mean(epoch_data_2(end_ind-start_ind+2:end,1:end-1),2); +end +end for i = 1 : length(plot_quantiles) +% if plot_quantiles(i)==0.5 +% plot_data(:,i) = 0.5*(quantile(epoch_data,0,2)+quantile(epoch_data,1,2)); +% else +aux_plot_vec = repmat(quantile(epoch_data,plot_quantiles(i),2),3,1); +aux_plot_vec = reshape(movmean(aux_plot_vec, ceil(0.05*size(epoch_data,1))),size(epoch_data,1),3); +aux_plot_vec = aux_plot_vec(:,2); +plot_data(:,i) = aux_plot_vec; +if not(isempty(plot_vec_ref)) +aux_plot_vec = repmat(quantile(epoch_data_2,plot_quantiles(i),2),3,1); +aux_plot_vec = reshape(movmean(aux_plot_vec, ceil(0.05*size(epoch_data,1))),size(epoch_data,1),3); +aux_plot_vec = aux_plot_vec(:,2); +plot_data_2(:,i) = aux_plot_vec; +end + +%end +end -plot_data(:,i) = quantile(epoch_data,plot_quantiles(i),2); +if not(isempty(plot_vec_ref)) + [~, index_shift] = max(plot_data_2(:,length(plot_quantiles)-1)/2); +else + if perform_shift +[~, index_shift] = max(plot_data(:,length(plot_quantiles)-1)/2); + else + index_shift = 0; + end end -[~,index_shift] = max(plot_data(:,length(plot_quantiles)-1)/2); index_shift = index_shift + floor(size(plot_data,1)/2); p_vec_aux = round(mod(index_shift+1:n_epoch+index_shift,n_epoch+0.1)); diff --git a/plugins/NSE_tool/m/zef_nse_plot_graph.m b/plugins/NSE_tool/m/zef_nse_plot_graph.m index 69b79dcc4..e18b5d8e8 100755 --- a/plugins/NSE_tool/m/zef_nse_plot_graph.m +++ b/plugins/NSE_tool/m/zef_nse_plot_graph.m @@ -20,7 +20,7 @@ function zef_nse_plot_graph(zef, nse_field) for i = 1 : length(nse_field.bp_vessels) plot_vec(i) = mean(nse_field.bp_vessels{i}(roi_ind)); end - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)',[]); end if zef.nse_field.graph_type == 3 @@ -31,12 +31,12 @@ function zef_nse_plot_graph(zef, nse_field) if zef.nse_field.graph_type == 4 [plot_vec] = zef_nse_separate_waves_roi(zef, nse_field); - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)',[]); end if zef.nse_field.graph_type == 5 [~, plot_vec] = zef_nse_separate_waves_roi(zef, nse_field); - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Pressure (mmHg)',[]); end if zef.nse_field.graph_type == 6 @@ -51,9 +51,11 @@ function zef_nse_plot_graph(zef, nse_field) if zef.nse_field.graph_type == 7 roi_ind = zef_nse_roi_ind(zef, nse_field); [~, dir_aux] = zef_nse_mean_velocity_roi(zef,nse_field); + dir_aux = zef_nse_vel_dir(zef,nse_field); plot_vec = zeros(length(nse_field.bv_vessels_1),1); - for i = 1 : length(nse_field.bv_vessels_1) - plot_vec(i) = dir_aux(1).*mean(nse_field.bv_vessels_1{i}(roi_ind))+dir_aux(2).*mean(nse_field.bv_vessels_2{i}(roi_ind))+dir_aux(3).*mean(nse_field.bv_vessels_3{i}(roi_ind)); + for i=1:length(nse_field.bv_vessels_1) + plot_vec(i) = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{i}(roi_ind,1)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i}(roi_ind,1)); +% plot_vec(i) = dir_aux(1).*mean(nse_field.bv_vessels_1{i}(roi_ind))+dir_aux(2).*mean(nse_field.bv_vessels_2{i}(roi_ind))+dir_aux(3).*mean(nse_field.bv_vessels_3{i}(roi_ind)); end zef_nse_plot_full(zef,zef.nse_field,plot_vec,'Velocity (m/s)'); end @@ -61,11 +63,13 @@ function zef_nse_plot_graph(zef, nse_field) if zef.nse_field.graph_type == 8 roi_ind = zef_nse_roi_ind(zef, nse_field); [~, dir_aux] = zef_nse_mean_velocity_roi(zef,nse_field); + dir_aux = zef_nse_vel_dir(zef,nse_field); plot_vec = zeros(length(nse_field.bv_vessels_1),1); for i = 1 : length(nse_field.bv_vessels_1) - plot_vec(i) = dir_aux(1).*mean(nse_field.bv_vessels_1{i}(roi_ind))+dir_aux(2).*mean(nse_field.bv_vessels_2{i}(roi_ind))+dir_aux(3).*mean(nse_field.bv_vessels_3{i}(roi_ind)); + plot_vec(i) = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{i}(roi_ind,1)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i}(roi_ind,1)); +% plot_vec(i) = dir_aux(1).*mean(nse_field.bv_vessels_1{i}(roi_ind))+dir_aux(2).*mean(nse_field.bv_vessels_2{i}(roi_ind))+dir_aux(3).*mean(nse_field.bv_vessels_3{i}(roi_ind)); end - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)',[]); end if zef.nse_field.graph_type == 9 @@ -76,12 +80,12 @@ function zef_nse_plot_graph(zef, nse_field) if zef.nse_field.graph_type == 10 [~, ~,plot_vec] = zef_nse_separate_waves_roi(zef, nse_field); - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)',[]); end if zef.nse_field.graph_type == 11 [~, ~,~, plot_vec] = zef_nse_separate_waves_roi(zef, nse_field); - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Velocity (m/s)',[]); end if zef.nse_field.graph_type == 12 @@ -110,7 +114,7 @@ function zef_nse_plot_graph(zef, nse_field) for i = 1 : length(nse_field.mu_vessels) plot_vec(i) = mean(nse_field.mu_vessels{i}(roi_ind)); end - zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Viscosity (Pa s)'); + zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Viscosity (Pa s)',[]); end if zef.nse_field.graph_type == 15 @@ -123,10 +127,25 @@ function zef_nse_plot_graph(zef, nse_field) end if zef.nse_field.graph_type == 16 - zef_nse_plot_signal_pulse(zef, zef.nse_field); +plot_vec = zef_nse_calculate_perfusion(zef.nse_field,zef.nodes,zef.tetra,zef.domain_labels,zef.mvd_length); +zef_nse_plot_full(zef,zef.nse_field,plot_vec,'Perfusion (ml / min)'); end if zef.nse_field.graph_type == 17 +plot_vec = zef_nse_calculate_perfusion(zef.nse_field,zef.nodes,zef.tetra,zef.domain_labels,zef.mvd_length); +zef_nse_plot_epoched(zef,zef.nse_field,plot_vec,'Perfusion (ml / min)',[]); +end + +if zef.nse_field.graph_type == 18 +plot_vec = zef_nse_calculate_perfusion(zef.nse_field,zef.nodes,zef.tetra,zef.domain_labels,zef.mvd_length); +zef_nse_plot_histogram(zef,zef.nse_field,plot_vec,'Perfusion (ml / min)'); +end + +if zef.nse_field.graph_type == 19 + zef_nse_plot_signal_pulse(zef, zef.nse_field); +end + +if zef.nse_field.graph_type == 20 mmhg_conversion = 101325/760; plot_vec = zef_nse_signal_pulse([0:zef.nse_field.time_step_length:zef.nse_field.cycle_length],zef.nse_field)/mmhg_conversion; zef_nse_plot_histogram(zef,plot_vec(:),'Pressure (mmHg)'); diff --git a/plugins/NSE_tool/m/zef_nse_plot_roi.m b/plugins/NSE_tool/m/zef_nse_plot_roi.m index 23d4e5c54..9faaeeae1 100644 --- a/plugins/NSE_tool/m/zef_nse_plot_roi.m +++ b/plugins/NSE_tool/m/zef_nse_plot_roi.m @@ -12,13 +12,12 @@ function zef_nse_plot_roi(h_axes,zef,nse_field) hold(h_axes,'on'); end -h_sphere = findobj(h_axes.Children,'Tag','additional:nse_sphere'); +h_sphere = findobj(h_axes.Children,'Tag','additional: nse_sphere'); delete(h_sphere); h_arrow = findobj(h_axes.Children,'Tag','additional: mean velocity in roi'); delete(h_arrow); - [X,Y,Z] = sphere(100); if not(isempty(nse_field.bv_vessels_1)) @@ -26,13 +25,13 @@ function zef_nse_plot_roi(h_axes,zef,nse_field) end h_surf = surf(nse_field.roi_radius*X + nse_field.roi_x, nse_field.roi_radius*Y + nse_field.roi_y, nse_field.roi_radius*Z + nse_field.roi_z); - h_arrow = zef_plot_3D_arrow(nse_field.roi_x,nse_field.roi_y,nse_field.roi_z,dir_vec(1),dir_vec(2),dir_vec(3),3*nse_field.roi_radius,2,'r'); - set(h_arrow,'Tag','additional: mean velocity in roi'); +h_arrow = zef_plot_3D_arrow(nse_field.roi_x,nse_field.roi_y,nse_field.roi_z,-dir_vec(1),-dir_vec(2),-dir_vec(3),2.*nse_field.roi_radius,2,'r'); +set(h_arrow,'Tag','additional: mean velocity in roi'); set(h_surf,'FaceColor',[0.5 0.5 0.5]); set(h_surf,'EdgeColor','none'); set(h_surf,'FaceAlpha',0.5); -set(h_surf,'Tag','additional:nse_sphere'); +set(h_surf,'Tag','additional: nse_sphere'); if not(hold_val) diff --git a/plugins/NSE_tool/m/zef_nse_separate_waves_roi.m b/plugins/NSE_tool/m/zef_nse_separate_waves_roi.m index 9da85cf79..aa77f5270 100644 --- a/plugins/NSE_tool/m/zef_nse_separate_waves_roi.m +++ b/plugins/NSE_tool/m/zef_nse_separate_waves_roi.m @@ -2,31 +2,46 @@ function [forward_pressure, backward_pressure, forward_velocity, backward_velocity, intensities] = zef_nse_separate_waves_roi(zef, nse_field) roi_ind = zef_nse_roi_ind(zef,nse_field); -[~, dir_aux] = zef_nse_mean_velocity_roi(zef,nse_field); -n_time = length(nse_field.bp_vessels); +dir_aux = zef_nse_vel_dir(zef,nse_field); +% [~, dir_aux] = zef_nse_mean_velocity_roi(zef,nse_field); +n_time = length(zef.nse_field.bp_vessels); d_time = (nse_field.time_length - nse_field.start_time)/(n_time-1); mmhg_conversion = 101325/760; n_cycle = floor(nse_field.cycle_length/d_time); - pressure_sum = zeros(n_time,1); - velocity_sum = zeros(n_time,1); + pressure_sum = zeros(n_time,1); + velocity_sum = zeros(n_time,1); for j=1:n_time-1 - pressure_sum(j) = (mean(mmhg_conversion*nse_field.bp_vessels{j+1}(roi_ind))-mean(mmhg_conversion*nse_field.bp_vessels{j}(roi_ind))).^2; - aux_velocity_wave1 = mean(dir_aux(:,1).*nse_field.bv_vessels_1{j}(roi_ind,1)+dir_aux(:,2).*nse_field.bv_vessels_2{j}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{j}(roi_ind,1)); - aux_velocity_wave2 = mean(dir_aux(:,1).*nse_field.bv_vessels_1{j+1}(roi_ind,1)+dir_aux(:,2).*nse_field.bv_vessels_2{j+1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{j+1}(roi_ind,1)); - velocity_sum(j) = (aux_velocity_wave2-aux_velocity_wave1).^2; - end - c = sqrt(sqrt(movmean(pressure_sum,2*n_cycle))./(sqrt(movmean(velocity_sum,2*n_cycle))*nse_field.rho)); + pressure_sum(j) = (mean(mmhg_conversion*zef.nse_field.bp_vessels{j+1}(roi_ind))-mean(mmhg_conversion*zef.nse_field.bp_vessels{j}(roi_ind))).^2; + aux_velocity_wave1 = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{j}(roi_ind,1)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{j}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{j}(roi_ind,1)); + aux_velocity_wave2 = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{j+1}(roi_ind,1)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{j+1}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{j+1}(roi_ind,1)); + velocity_sum(j) =(aux_velocity_wave2-aux_velocity_wave1).^2; + + end +% c = zeros(n_time-1,1); +% c = sqrt(sqrt(abs(pressure_sum))/(sqrt(abs(velocity_sum))*nse_field.rho)); + c = (1/nse_field.rho)*sqrt(movmean(pressure_sum,2*n_cycle))./(sqrt(movmean(velocity_sum,2*n_cycle))); +% c = sqrt(pressure_sum/velocity_sum)/nse_field.rho; +% c(1:end,1) = (1/nse_field.rho)*sqrt(mean(pressure_sum)/mean(velocity_sum)); + - forward_pressure = zeros(n_time,1); - backward_pressure = zeros(n_time,1); - forward_velocity = zeros(n_time,1); - backward_velocity = zeros(n_time,1); - pressure_vec = zeros(n_time,1); - - pressure_vec(1) = mean(mmhg_conversion*(nse_field.bp_vessels{1}(roi_ind))); - velocity_vec(1) = mean(dir_aux(:,1).*nse_field.bv_vessels_1{1}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{1}(roi_ind,1)); - + forward_pressure = zeros(n_time-1,1); + backward_pressure = zeros(n_time-1,1); + forward_velocity = zeros(n_time-1,1); + backward_velocity = zeros(n_time-1,1); + pressure_total_sum_plus = 0; + pressure_total_sum_minus = 0; + velocity_total_sum_plus = 0; + velocity_total_sum_minus = 0; + +% pressure_vec = zeros(n_time,1); +% velocity_vec = zeros(n_time,1); +% +% pressure_vec(1) = mean(mmhg_conversion*(nse_field.bp_vessels{1}(roi_ind))); +% velocity_vec(1) = mean(dir_aux(:,1).*nse_field.bv_vessels_1{1}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{1}(roi_ind,1)); + + + for i =1:n_time-1 if i == 1 @@ -37,40 +52,61 @@ int_param = 0.5; end - - pressure_vec(i+1) = mean(mmhg_conversion*(nse_field.bp_vessels{i+1}(roi_ind))); - velocity_vec(i+1) = mean(dir_aux(:,1).*nse_field.bv_vessels_1{i+1}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{i+1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{i+1}(roi_ind,1)); - aux_velocity_wave1 = mean(dir_aux(:,1).*nse_field.bv_vessels_1{i}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{i}(roi_ind,1)); - aux_velocity_wave2 = mean(dir_aux(:,1).*nse_field.bv_vessels_1{i+1}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{i+1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{i+1}(roi_ind)); - dP_minus =0.5* (mean(mmhg_conversion*(nse_field.bp_vessels{i+1}(roi_ind) - nse_field.bp_vessels{i}(roi_ind))) - int_param*nse_field.rho*c(i).^2*(aux_velocity_wave2-aux_velocity_wave1)); - dP_plus = 0.5*(mean(mmhg_conversion*(nse_field.bp_vessels{i+1}(roi_ind) - nse_field.bp_vessels{i}(roi_ind))) + int_param*nse_field.rho*c(i).^2*(aux_velocity_wave2-aux_velocity_wave1)); - forward_pressure(i+1) = forward_pressure(i) + 2*dP_plus; - backward_pressure(i+1) = backward_pressure(i) + 2*dP_minus; - forward_velocity(i+1) = forward_velocity(i) + 2*dP_plus./(nse_field.rho.*c(i).^2); - backward_velocity(i+1) = backward_velocity(i) + 2*dP_minus./(nse_field.rho.*c(i).^2); + aux_velocity_wave1 = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{i}(roi_ind)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i}(roi_ind,1)); + aux_velocity_wave2 = mean(dir_aux(:,1).*zef.nse_field.bv_vessels_1{i+1}(roi_ind)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i+1}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i+1}(roi_ind)); + + dP_plus = 1/2*((mean(mmhg_conversion*zef.nse_field.bp_vessels{i+1}(roi_ind)-mmhg_conversion*zef.nse_field.bp_vessels{i}(roi_ind)))+nse_field.rho*c(i)*(aux_velocity_wave2-aux_velocity_wave1)); + dP_minus = 1/2*((mean(mmhg_conversion*zef.nse_field.bp_vessels{i+1}(roi_ind)-mmhg_conversion*zef.nse_field.bp_vessels{i}(roi_ind)))-nse_field.rho*c(i)*(aux_velocity_wave2-aux_velocity_wave1)); + + dU_plus = 1/2*((aux_velocity_wave2-aux_velocity_wave1)+(mean(mmhg_conversion*zef.nse_field.bp_vessels{i+1}(roi_ind)-mmhg_conversion*zef.nse_field.bp_vessels{i}(roi_ind)))/(nse_field.rho*c(i))); + dU_minus = 1/2*((aux_velocity_wave2-aux_velocity_wave1)-(mean(mmhg_conversion*zef.nse_field.bp_vessels{i+1}(roi_ind)-mmhg_conversion*zef.nse_field.bp_vessels{i}(roi_ind)))/(nse_field.rho*c(i))); + + dP_plus = dP_plus/mmhg_conversion; + dP_minus = dP_minus/mmhg_conversion; + + pressure_total_sum_plus = pressure_total_sum_plus + dP_plus; + pressure_total_sum_minus = pressure_total_sum_minus + dP_minus; + + forward_pressure(i) = pressure_total_sum_plus + nse_field.pressure; + backward_pressure(i) = pressure_total_sum_minus + nse_field.pressure; + + velocity_total_sum_plus = velocity_total_sum_plus - 0.5*dU_plus; + velocity_total_sum_minus = velocity_total_sum_minus + 0.5*dU_minus; + forward_velocity(i) = velocity_total_sum_plus; + backward_velocity(i) = velocity_total_sum_minus; + +% forward_velocity(i) = dP_plus./(nse_field.rho.*c(i)); +% backward_velocity(i) = dP_minus./(nse_field.rho.*c(i)); end - - - - forward_pressure = (mean(pressure_vec) - mean(forward_pressure) + forward_pressure)/mmhg_conversion; - backward_pressure = (mean(pressure_vec) - mean(backward_pressure) + backward_pressure)/mmhg_conversion; - - forward_velocity = mean(velocity_vec) - mean(forward_velocity) + forward_velocity; - backward_velocity = mean(velocity_vec) - mean(backward_velocity) + backward_velocity; - - -% intensities = zeros(n_time-1,1); - -% for i=1:n_time-1 -% aux_velocity_wave1 = dir_aux(:,1).*nse_field.bv_vessels_1{i}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{i}(roi_ind); -% aux_velocity_wave2 = dir_aux(:,1).*nse_field.bv_vessels_1{i+1}(roi_ind)+dir_aux(:,2).*nse_field.bv_vessels_2{i+1}(roi_ind)+dir_aux(:,3).*nse_field.bv_vessels_3{i+1}(roi_ind,1); -% intensities(i) = mean((nse_field.bp_vessels{i+1}(roi_ind)-nse_field.bp_vessels{i}(roi_ind)).*(aux_velocity_wave2-aux_velocity_wave1)); -% end - -%forward_pressure = interp1(1:n_time-1,forward_pressure,linspace(1,n_time-1,n_time)); -%backward_pressure = interp1(1:n_time-1,backward_pressure,linspace(1,n_time-1,n_time)); -%forward_velocity = interp1(1:n_time-1,forward_velocity,linspace(1,n_time-1,n_time)); -%backward_velocity = interp1(1:n_time-1,backward_velocity,linspace(1,n_time-1,n_time)); -%intensities = interp1(1:n_time-1,intensities,linspace(1,n_time-1,n_time)); + +intensities = zeros(n_time-1,1); + +for i=1:n_time-1 + aux_velocity_wave1 = dir_aux(:,1).*zef.nse_field.bv_vessels_1{i}(roi_ind)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i}(roi_ind); + aux_velocity_wave2 = dir_aux(:,1).*zef.nse_field.bv_vessels_1{i+1}(roi_ind)+dir_aux(:,2).*zef.nse_field.bv_vessels_2{i+1}(roi_ind)+dir_aux(:,3).*zef.nse_field.bv_vessels_3{i+1}(roi_ind,1); + intensities(i) = mean((zef.nse_field.bp_vessels{i+1}(roi_ind)-zef.nse_field.bp_vessels{i}(roi_ind)).*(aux_velocity_wave2-aux_velocity_wave1)); +end + +forward_pressure = interp1(1:n_time-1,forward_pressure,linspace(1,n_time-1,n_time)); +backward_pressure = interp1(1:n_time-1,backward_pressure,linspace(1,n_time-1,n_time)); +forward_velocity = interp1(1:n_time-1,forward_velocity,linspace(1,n_time-1,n_time)); +backward_velocity = interp1(1:n_time-1,backward_velocity,linspace(1,n_time-1,n_time)); +intensities = interp1(1:n_time-1,intensities,linspace(1,n_time-1,n_time)); + +min_correction = min([forward_velocity(:); backward_velocity(:)]); +forward_velocity = forward_velocity - min_correction; +backward_velocity = backward_velocity - min_correction; + +if sum(forward_velocity) < sum(backward_velocity) +aux_vec = forward_velocity; +forward_velocity = backward_velocity; +backward_velocity = aux_vec; + +aux_vec = forward_pressure; +forward_pressure = backward_pressure; +backward_pressure = aux_vec; +end + + end diff --git a/plugins/NSE_tool/m/zef_nse_tool_init.m b/plugins/NSE_tool/m/zef_nse_tool_init.m index f5f921989..047714ab4 100644 --- a/plugins/NSE_tool/m/zef_nse_tool_init.m +++ b/plugins/NSE_tool/m/zef_nse_tool_init.m @@ -111,6 +111,18 @@ zef.nse_field.roi_z = 0; end +if not(isfield(zef.nse_field,'dir_v_x')) + zef.nse_field.dir_v_x = 0; +end + +if not(isfield(zef.nse_field,'dir_v_y')) + zef.nse_field.dir_v_y = 0; +end + +if not(isfield(zef.nse_field,'dir_v_z')) + zef.nse_field.dir_v_z = 0; +end + if not(isfield(zef.nse_field,'cycle_length')) zef.nse_field.cycle_length = 1; diff --git a/plugins/NSE_tool/m/zef_nse_tool_window.m b/plugins/NSE_tool/m/zef_nse_tool_window.m index 26d2b2e9d..77a8c6080 100644 --- a/plugins/NSE_tool/m/zef_nse_tool_window.m +++ b/plugins/NSE_tool/m/zef_nse_tool_window.m @@ -9,6 +9,7 @@ zef.nse_field.h_plot_graph = zef_data.h_plot_graph; zef.nse_field.h_apply_roi = zef_data.h_apply_roi; zef.nse_field.h_apply_source_coordinates = zef_data.h_apply_source_coordinates; +zef.nse_field.h_apply_dir_v = zef_data.h_apply_dir_v; zef.nse_field.h_nse_tool = zef_data.h_nse_tool; zef.nse_field.h_nse_tool.Name = 'ZEFFIRO Interface: NSE tool'; @@ -63,6 +64,14 @@ zef.nse_field.h_roi_z = zef_data.h_roi_z; zef.nse_field.h_roi_z.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; + +zef.nse_field.h_dir_v_x = zef_data.h_dir_v_x; +zef.nse_field.h_dir_v_x.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; +zef.nse_field.h_dir_v_y = zef_data.h_dir_v_y; +zef.nse_field.h_dir_v_y.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; +zef.nse_field.h_dir_v_z = zef_data.h_dir_v_z; +zef.nse_field.h_dir_v_z.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; + zef.nse_field.h_gravity_amplitude = zef_data.h_gravity_amplitude; zef.nse_field.h_gravity_amplitude.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; zef.nse_field.h_time_length = zef_data.h_time_length; @@ -208,6 +217,11 @@ zef.nse_field.h_roi_y.Value = num2str(zef.nse_field.roi_y); zef.nse_field.h_roi_z.Value = num2str(zef.nse_field.roi_z); + +zef.nse_field.h_dir_v_x.Value = num2str(zef.nse_field.dir_v_x); +zef.nse_field.h_dir_v_y.Value = num2str(zef.nse_field.dir_v_y); +zef.nse_field.h_dir_v_z.Value = num2str(zef.nse_field.dir_v_z); + zef.nse_field.h_viscosity_smoothing.Value = zef.nse_field.viscosity_smoothing; zef.nse_field.h_gravity_amplitude.Value = zef.nse_field.gravity_amplitude; @@ -241,11 +255,11 @@ zef.nse_field.h_capillary_diameter.Value = zef.nse_field.capillary_diameter; zef.nse_field.h_pressure.Value = zef.nse_field.pressure; -zef.nse_field.h_viscosity_model.Items = {'Constant','Power law','Carreau-Yasuda'}; +zef.nse_field.h_viscosity_model.Items = {'Constant','Power law','Carreau-Yasuda','Walburn-Schneck','Genaralized power law','Casson'}; zef.nse_field.h_viscosity_model.ItemsData = [1 : length(zef.nse_field.h_viscosity_model.Items)]; zef.nse_field.h_viscosity_model.Value = zef.nse_field.viscosity_model; -zef.nse_field.h_graph_type.Items = {'Pressure (full)','Pressure (epoch)','Pressure (full seperated)','Pressure (epoch forward separation)','Pressure (epoch backward separation)','Pressure histogram', 'Velocity (full)', 'Velocity (epoch)', 'Velocity (full seperated)','Velocity (epoch forward separation)','Velocity (epoch backward separation)','Velocity histogram', 'Viscosity (full)','Viscosity (epoch)' ,'Viscosity histogram','Pulse function','Pulse histogram'}; +zef.nse_field.h_graph_type.Items = {'Pressure (full)','Pressure (epoch)','Pressure (full seperated)','Pressure (epoch forward separation)','Pressure (epoch backward separation)','Pressure histogram', 'Velocity (full)', 'Velocity (epoch)', 'Velocity (full seperated)','Velocity (epoch forward separation)','Velocity (epoch backward separation)','Velocity histogram', 'Viscosity (full)','Viscosity (epoch)' ,'Viscosity histogram','Perfusion (full)', 'Perfusion (epoch)', 'Perfusion histogram', 'Pulse function','Pulse histogram'}; zef.nse_field.h_graph_type.ItemsData = [1 : length(zef.nse_field.h_graph_type.Items)]; zef.nse_field.h_graph_type.Value = zef.nse_field.graph_type; @@ -266,13 +280,14 @@ zef.nse_field.h_time_integration.Value = zef.nse_field.time_integration; zef.nse_field.h_solve_system.ButtonPushedFcn = 'zef_nse_run_solver'; -zef.nse_field.h_parse_reconstruction.ButtonPushedFcn = 'zef.inv_time_1 = zef.nse_field.inv_time_1; zef.inv_time_2 = zef.nse_field.inv_time_2; zef.inv_time_3 = zef.nse_field.inv_time_3; [zef.reconstruction, zef.reconstruction_information] = zef_nse_struction(zef.nse_field,zef.nse_field.h_reconstruction_type.Value);'; +zef.nse_field.h_parse_reconstruction.ButtonPushedFcn = 'zef.inv_time_1 = zef.nse_field.inv_time_1; zef.inv_time_2 = zef.nse_field.inv_time_2; zef.inv_time_3 = zef.nse_field.inv_time_3; [zef.reconstruction, zef.reconstruction_information] = zef_nse_reconstruction(zef.nse_field,zef.nse_field.h_reconstruction_type.Value);'; zef.nse_field.h_interpolate.ButtonPushedFcn = 'zef = zef_nse_interpolate(zef,zef.nse_field.h_reconstruction_type.Value);'; zef.nse_field.h_nse_sigma.ButtonPushedFcn = 'zef.nse_sigma = zef_nse_sigma(zef.nse_field,zef.nodes,zef.tetra,zef.domain_labels,zef.sigma,zef.source_interpolation_ind{1});'; zef.nse_field.h_plot_sphere.ButtonPushedFcn = 'zef_nse_plot_sphere;'; zef.nse_field.h_plot_roi.ButtonPushedFcn = 'zef_nse_plot_roi;'; -zef.nse_field.h_apply_roi.ButtonPushedFcn = 'zef_nse_apply_roi;'; +zef.nse_field.h_apply_roi.ButtonPushedFcn = 'zef_nse_apply_roi'; zef.nse_field.h_apply_source_coordinates.ButtonPushedFcn = 'zef_nse_apply_source'; +zef.nse_field.h_apply_dir_v.ButtonPushedFcn = 'zef_nse_dir_v_node;'; zef.nse_field.h_plot_graph.ButtonPushedFcn = 'zef_nse_plot_graph;'; diff --git a/plugins/NSE_tool/m/zef_nse_vel_dir.m b/plugins/NSE_tool/m/zef_nse_vel_dir.m new file mode 100644 index 000000000..bafce5572 --- /dev/null +++ b/plugins/NSE_tool/m/zef_nse_vel_dir.m @@ -0,0 +1,10 @@ +function direction = zef_nse_vel_dir(zef,nse_field) +% roi_ind = zef_nse_roi_ind(str2double(zef.nse_field.h_roi_x),str2double(zef.nse_field.h_roi_y),str2double(zef.nse_field.h_roi_z)); + +roi_ind = find(sqrt(sum((zef.source_positions - repmat([str2double(nse_field.h_roi_x.Value) str2double(nse_field.h_roi_y.Value) str2double(nse_field.h_roi_z.Value)],size(zef.source_positions,1),1)).^2,2))<= nse_field.roi_radius); +towards = [nse_field.dir_v_x nse_field.dir_v_y nse_field.dir_v_z]; +c_ind_1_domain = find(ismember(zef.domain_labels,nse_field.artery_domain_ind)); +[v_1_nodes, ~, ~] = zef_get_submesh(zef.nodes, zef.tetra, c_ind_1_domain); +dir_aux = -v_1_nodes(roi_ind,:)+towards; +direction = dir_aux./sqrt(dir_aux(:,1).^2+dir_aux(:,2).^2+dir_aux(:,3).^2); +end diff --git a/plugins/NSE_tool/mlapp/zef_nse_app.mlapp b/plugins/NSE_tool/mlapp/zef_nse_app.mlapp index 3f7fde3edff07e8acf05770f1ee560367878e78a..3a9d8cb84c640d6413313612ab693dada2b76225 100644 GIT binary patch delta 67981 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 delta 65356 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�-?)B{C&!M1ErducTxZ9vjcC90jsc z_qV#|Z>8pM<-3;jOx&Bx*}Z-6!8_d+MBjbGXu15io(shU_^>(rq2M9`?1Y{zNkBEf z_4KNjgl`-5U|aiPjRt3ngnv-x01u^H_btLrC$v&|0_um*`TR>wc5>IZ61&Bc0PaUU zcP*Si1;~hAWj3A4`yP(ru?gw1Kw~d@gLVypmoJ&Pvm;}R@Obu@FIl*=53rpFLi_VC zG2NZ|yStJ~Eem5BeeGrahds}T*9P(8T>sg+Cot$3lPMyOVs@^<+<*6@clK(>TBf5| z??62|v5JU&QFIFsy3>gTB2urxRSvOOZKK1UUQxJ81j+zUsJ(u8PxP>7MSPbM6iiM2 z1k*k#zMBXnZye(cz~L(X*_Bj@sJ$uR+ua2mM7=dd6$c=n3nv=Hdh7oXART- zWHk}6J36{=IJ7@X#m&*FaqZ<(8v3x#PSxE}5cm5FLY~(3)_<|_ZVeHoFEOzVR6+T4 zf%$g=dAVE1hCj*8blwNPTceW7vK1h8RtOURP6=7Na_Kq4@duua(dNp2tHNJ5*K0q`? zg2#lVy&gm6USl`YmbAt8z9q0hwkrG`Vg)&CeaKL}IV=Z9jD=5@aI;!g` zVD)SW;FLZ6{PA+;kib8}h)BpT+1;7wo&vM|qIPIj;(ws^5A)CWKW-nlF`EJEU!(=V zy-6y-9TPXBj~<=Mi-f9=ILTV}THbl`>&_Ex+{W!-E@b86t}j^|ykk=ERACEMDP?px zYR<~LVn-lLuu7`B1S`tft_ZYHK*}o>xPO{*5j$)ax)xpF zRn@j`8-Fr^IWI*X8E0Jq{}Y^l5`(iTN$(!Ag$7PVp^iAY?M@mg@RE$$GrB=Bieg4x z-?hZZ|9?#^B(r7kVtHuG(c_@kdD;0}P*A-b>SEBNVrp^ECnecEl-uCd`gV=J@yQ!& zfn;mt&tXfeG(P-IG}eg~YLg!~9@hukv??6G&42k7K1tE99k-soqV9R;err)iumNnF zIWH-MaNt>b(Vt|xC8nr0$7`m-G-h;Kjx4=g;?-@f&k6Q;zfLl}R(dfoY^Z$KuWi#ddF5ww0{cW#fY{7K{I^p#YDSptN`R0o$bux2!44NqYKrN)?9v$tL;=8h-7KhIEX7SzZjMkS} z#I6b?m;}hvfzd|nN#_-8%RXv3r>Qr)KQr!VY#$kn)6jJ14U8``5R!K(grjkti%ek`i9nft7|) zN1zO0)ZSR#27JL%*nDw?R^PJ+rMymZW!a)Z8S9xfCnec;6l7(4JEoM_KF~YRKIhn2 zy|9j(dlmUftLh6|dVhLfk_i``sXpEQilu4lin8k9kl;;cI)tF z*0lWZT9=V|)qi1^Z1a(W7K?M8ZT>$KJrzi6*5>R@$Ma&b%EVjQlO&S`-?g2mCr6wx zF6K*$iAVl5c$?{^x)PNfQ$MNJ1FU<6e`upNAmn=c@T)6hoeGb<%4F2s!<~*A%Qb6F zzh|xS3o6}&V9t=XhRv^m8E@v`JE=9lHnJ@J(DMO~{(qy*Z)c_IRP-D&Ql2TSKkM(` zzOMUn=;qFc)f3mlXYv8R&A*9>HOJ30JN9l^8~K^G3S+km{hg-gjw)_7$Icr&o&0F# z2t}<=$y7bFzv6)hn#0EfUn#C_A;wwZ=NR3v9QcCMlPhcYckB!j06<6k4K_9qxrVLn zZ4l_d&VLpLN{HhNh66)HfV_Cy>yU&Pqy$2o1>A$dyo9}DNJYLP4V1v*ZD}C)qmix> z$My<=66CG#UfB$K9ooy54@RUlR!P#EEO+*k5qI#8{##|Ns5{VjydyPQBpT&}sDZ#u z+Oc{tbLLdkL^|rwW&!>ahAu~jX7i*Aoa`6 z892BZm1!+r`ztn6S-e(G@5xUK_hZaZXoEb791y?EFbj$Kz>Dyf=9B9sYmnbYcr&@f zF+*!?bLfZ^7yRrrT^gg3RjXy*`fLnDpcWN-j8K+M0x8JGLtxP|4YrDcPL zGg|k*F&}@zaLZ2`_TGA;?z78bjbZNYM%Ai0nvZ?t>V*~sq9xtkA7OF~+)aBhT>Y?y zN9;gZUMNP$rgCWI*YgdOOb=DAA(QKAB_ zse8S#>HZs>ioxIDg(!i5$)`Su#rlzg!2@i5|KWe4gwy$6!|T7n`xNC$)WQas{_j=$ zpmL>+&VKKz{g$R_tOhZM#Sye%0n~8GPF)rlmIgYF;|tP(dr_=*4}hVS9oT1x{XnL` zJwV`|0H}qM+@rHyQG8bvL^!m=DYLy))f2O+{uehJaX1awDHT{H25Er9J%XKz@Btgi z4{v`ZcVbu(yZn$~W(Tphdtz;BVr^Pt`wD?6^d@b{v>iKs)$;4%X^|@B*CW$9OvF^` z(bpqT9}y2h@YkKX)G$G6=qFr(j}E+_VpYpL7R7@vfS}(RsEY~ZvNGG{GJzh)LbZV`6bpH4ZSDv1mQ*_8JGnXF7EuXrFLY5@MVh zuF$EQ@dn)mT-7p-MQtO-$>D(ld91CY@$=%NK)`v&T~)SKdUEn$Ha049wWFA5s1di#%P{G)!f%)oQ;tF@gdSH+QBytZSezV8szNQ!v2Q?Nim}GN5I?c68 zlFP)oz5l*h=2B<>bF)l`Bm43tM^W@35_N{CA%U}WU~j?9K~Q~luNvvQV(Iee@^Dld zqDF|i)hyAbJR+h_yb28X+1XCa16F@K+XdLBAfH$V?f@-uw!)C-$p1z?zm9(i0aq$g znKZC^5^t*tfrKNG62}V+fu3xwut*z-@8JSlIV3ji8ZjL(fn)kzc}#}e`_0Q(FGQd# zID!(|DjXG$@S=u`c4C=fjU1_{E0X_&&mX>sA7;dC^vkFcL@&?qb+f6bu;_oCd3Am3 zMviSXMiA}ULyd0!PoqUI&Tbq^>@;UO>ePf4NM-(!#cmJ#s2x`3Lzp`IS z$@QD7)11{$)s9j+?myux+wiS?^dsO~OLoaIX=CjVmD~Pb&l6q-5NwO^&0ov7?j&0s z&1>wpM!WH(H|xCUluod(<0XHH8Yw>9_Nn9S%gXc9Xw=_3bDCOO&%AwhKYFInJnWl$ zQR#uo*`>t3Rf!Gl+5NPcL_&p0bM>r@n_Nn>$yTA4m{D`)tp0?%=!s;VWnU}g>VSDl zxZ2dNvd0G5$`ZtN9H?>S$N8i26Z`s&VOSH=q_7qFv(S&h!43H0zCV9B>Cf?trGsBT zlF}3nw*0(S%I0jg$%2O&g*^+uj+2@!*nQ$H_lZm!7A^OQNULxzMm?4Kp(_Vl14ET@ z1yJ;1Bx)Wp4uqcr2n9K7t*n<^XiyYN4Iw%8=~}Z5-@BQ+w?KTDyON-S_PatLkf+_h zU|hS_O%jj9BgDzT_d0(tw_$8_KnI+y2qb~FPwjoOO@co{oDnR5!8j(jzKgWEuO(KP z$NHU%7>!NF?fA(}oICnO%rdt+`XOeS&(^vr;!yzzNglZ5zx|h`9jgw*#-PyQXp#M~ zcq<_E4DpZz8f|y@k*f7}Oav3#?dS+ew%f50G^_xY&UOje*1msQSaB3m2v!_}1uZ~7(5?~q$kGPF3DQ;OEpA9<`fnEsWjeaiA+YT+lC{z=jDU~=K#7J+-&-B^FbzB2j`2~@QMYk=67 zLjNIyegl6H2y#5Fr*jyrJM4@c{uh+b8kWZz*4eHqzAFa$10)Z!wXLKjzp%Ca_CUK~m*$Y0_-vMo{&rY2aH~jXLHd7-rOX^SGp0<^#txS8b%3n^=dU zwza(Ne#f(@Te=EY~{y$Qp&u&~EX; zpF+8CeB5w_4&9<~v=7UC&{#L-e~*BbLiL800Wmv{jQD>=+ntVf5;nHm>pS1oOyiMi z2yr$r6Yd5hI2Ct;9sCe?L*@ohBlyt182P_vAaJw$_MyFWpah_mZDTav^WS^d;(yZN zs5F0F(enE-X@coCpjuca4fH$CQ2{*|j`D$F!%>+CN#PsN+K@y0B;@~|fzDMemcVKf z087VRSrDPU{T5rFuiXuL!2XLsiOGdr5-<%umkRtEpGyJO!{>s){p4PT_J<@ z&05$7cdu{Xfexv9+YmF(*}33`%<0CRxz=W^W6qfq)J`QwY!ZJ}|`CQj@#mWleFRROODEp3G*K9Q-K zAJz`+&!?=0uN?)@uJO&?`SfemojN(j9OI;t^9zB+_Y3DH778bAk}u24m7ot)iy$^-EfA^0OXE+9s}%xs zM*hA5iL)nP08O{rOp|=JFCOY=|H6NIfP7*iM8!v$0Zo{@0w5oMyBoBCz|#ZnBBalN zngOgY25EyBDO^tFDq9j!xUFlElo!N2H@(Atb5c0-f0F|Ic5)+lPN0WH`1@ zNB*x0z-%wJ>>$R{-mcDOMnN8LXG;wd@wKyM2Z_*EvDV%J3gc|~A?1<(?|1*56eQiv z&2CmOSQdkEhD|XMY@T=9Jnyu5-fOdon2OJ;s-ZRU>+I(?o2C`Muriyb7Y3HMPCb>E zr-H`f2;yi+1S%il1%fAaVyS(y~#HUD&itKkI*wlYHYncIc$g zB0<3kZB?0o;(Y7rl`jc@P2>nHC8F$wPFowyDg7Q=u|tWuE zo$XxW2qP9Fg1~ga*4CWhgYTg13>#3p|b#_L2e29f^#^;~0}6N~Mv%<9i_x zB~qY4hni~!c>ni>WdDDrmieZZ{H9hwY-=&e|C86!3Xe2a?JJeH*lu+%5;I#ofgcvY z4!4Owy+-T{p<4jZ${<2P>Js0HfA+29);u2lw9rTX?+-1TzJK~XmL+Iy&iuUmHM07| zZj+qtV)RpW36(0%)pLb$NU~Fsz8&HQ0sK*9`u>tu`#oJX$LQL+p_v@IkQwrx> z|EF5;xwWqvoq$B`AtXuR0v%XBSSASi2E50zOu|J?s>8UX!;cZ^-)yQ*D<|KXaUlxntfrXSpl&I}Q+{T-c2 zF77Sf{yTp!G5v!E!kf)KseQ<(K^`F2i(jUgMIZJJl`tGHeL;SZLU^;d4^uXZtyGJ# zb`5F$H`-46A|`bHrKo29V-Ih?UD#%RZ5i>An4`}9%I}`rh7r(tF747BBC|b=52$3)*Um^~ z#3s*j`)hqw3icsc^kqt>E4)G@-_MHs4}4V$_sO!7%UTQ*^UnP(qgvPksP`Wdocab* zOmBZw{%BkXDLZ_r-s&&&Q?r!!-pXt5>IRmg9r=>&SG~38t7A;*X{FwA{jLhJrRa(r zqrC@GZ?5fC+)*$M&JYRlptA%0xZZR34zXkDxyxk-ilTP7OLYY(5C^Qk?%(i1^e^XT zi-Xr`7jq-T!5lP;xhdk{j%d$OGd3V&2Pc2W-7PF;55)dmgASWL8Fd6ck=A)RXH=>FiToH~GCf|%N8)Y@k7ps3zd-B|K zHU631l7d+yw~2dr8mHZo0IP|6Oq%8M5YNUT>}P}*CwdkP^>4>!A-q`8vvkmtmjr^% z2NX+s81zIQ7C-{$jzYy+DPVtW@UZj@@*?(cqm`V!Qwv5^lR^W?oU@}ci)@!&-vt1i zvwiKB<=+L&Yk!;d@ID}$ZJ~dX6T=J*AP#6|TWI7eF+&^NjRCxIA0vsm}bX z3vMB5$l-n+SW(zC9W)5%Sg8#^o<=|ZGc>vS>|&y>PJzcTAZr+CY*Tq)mnOF!{PDJP)!HweN3IE) zdJYAdpz_%F`rkE-#t#i?T?21hoNwo)SAD1Pv*?6#zI3G(+bRev+QJtj%hwBD5iee} zPb6v>F-{3@>iAz;tmHNRNa4g#%r&sMURwD&?*sa7-R~M91z~><)Zm_Tj9C~PCvN=R zw;e?WWofE(K<7Av8OLjG4uEMVUWidynk@9*OyKRGvdQ&l>(35kXxdV7&!mGBBPy$R zWx#Dcos$&F!Ti864MFfd0ZgAGTPBk&{R1uf2O9JbwCO)792#_9dvV>I)VWsV}|%owY8qi*FVhFW;rCF)}y9= zZE${Y`0vT_wj}CeNKV)6217AdUsx12|Md+2Qc9VhV8DNm6m9B&C?I(Rz)ibv&Tvbo zk+X!0-`}Awf2pF>FJX3q_%7Z|t@2IKPwMDB?CkxrTQBfnXJxB@eO6t?)FRumbb}&b zPH#)Iv2y~Rs;Iu@*vLBpPf^s{dfb>l;eN+IVaC;~xAeF6JTF+0Tai?eQIT4aU6E4J zc zeLzO;sOYz;Xm34l+$f#1*$#B`f77g@Qq-=eZMH@soMrckw%jK=&0VzICpL{6(*Yl+ z`|pt|p+@nGKIf z5f`Tc+-nvW2LO5$4()UCwh%}{ERy>F)B<4d$bgSRyu^nz#0o7TgHcFxgt%gt&7hjt z@<-N#(fG4;8W^)|^`pP~WR9jss#`LtTQ*re)itdA~G|t2Z~BJoTTX-l|9#-L7E$+t92QHD7;J z!=h+c<$Y~)c5@uAmgCOYWKd5tSM)1t`}k1TOt*86jGk51Zuw0?a0?F2J- z8H3`agVMKSk%)Z;v=RuK+^#DR6QqYS2YWpn!|1Bz2vN@!^{bz(8RcCZ!p;v1;#HKL zB#uD|%Crt6mj)q$+##i8`eN2odwD)lPD94j4$MaFHPNcPjj+Y0c!^KuY z%X?&7&=x;09iAT(gYu_?CgKVt(9#j8Lc}--{=QR}7IroTh2GIxy;7~KfxUkUN9n*` zd98J=T@^j`xdi~&+uZ;I7VK`20+_7XbRr`hQ^In<9dtlJ1aWizjK4t#o@rOJgz3a0 z{Z!=pc1Ppy$0MJ^p3(!k)Hk)X4?kWD9Aj@?wO`XRHCqD+&)IzfmLEo?*@%`C+Vwp0 zS_M2xJLDoDN*r`S06 zxV!t{HVpIK``-J`TK%ur>C;_jSM6O@on~2EPo<;NJElmgqtiELTSV%H#ca1_!STPs z#T!+D{!u2O<+GF&4jSLO`5g<m+@Yf(&f9N-SZBe(UEH;}sP_ZCZ%9#b`g`dk zjO{;CQH6&xI6D*J#P@&oxd;ipL1W(DN>#&A^*b6Oj|pvXcE-V(9EWlJFU5fAp5aCX zx`MYK)tiib=FfkCJOcg`*fc#0}fx{hhm5Dr+|AgFg#}y;t|;6Mnd}mCbNH9iRK!+$9jKaQ-kj3 z5Ql|q_4yTaV4U2toby3=^I*eUjrO=@RYKt!CmX8BS=*Msmn#5L+^}?G9{nNkkm0q^ zw1}`5>)(-Pb%4Tu;?6$FFJdmBPU(HG9C4EP)+ItAJ8YqIMA^A^h^xAr>*sA z-6P1B|19y{t>S;L?&U`UA0k(Z>+gF!BgZ4=NgxHBSL1Mh+WH<*nuoatUANJ`YLwRn zjXYude48I$P3aJHLi9m}>Thm>quLJf8D3Q53d<|nA17C|1&M3cF@~=+2fU%>HdKJ7 z*xk}*mlqidP!LZEq#!hi1$Oanmmz5%ByXg8LIxU*8g_qiO?Ju2v8Q78h}+#G+7*i8 zjZe{3@y^MyVucjvU3qHIs#5eSNaw3sDd13iST*<+*RWu1S_K}|&;QXRu`0Ad(YGor z(V2_M94DTW<2WWNgo`s75z6H3{D#U99Zh9>>zz=mkTOnI8x`x`Wl z0Fe&{P@R8aVO@R7LqnU;fWoSJE<;qdjDa!YT35zDhA3>h&{|jQKaC&va}7^iT{&_L z(U^IhUBz?O5SRt~75s#b@tBwe+j97@w9fXdhDJG@UD{Ax}*)|@LdBIHxsq24ncW*m>BZ%QVOX%p^r}A#?HauIx zIfaNxFhE+!`kBQMwRhrEtAa$l+kvA{D;f@JU!SSa=ipF!XYRR(P%~%lwE;FCdl){1~0s!JB`~WQ@)h+&cmBBqrs^+!jT9HCH_}a{HNuhmf%07v;I9(ZS=#xrO~1D&X>Ye{_3M{ zR@jr7Ty;SIA29PO*GYeDw$0u#k*`lA|JKj$B>wp0vH@BrGr@+c0==UN&ew!F_F;c1 z`P+M>|7z);@X=8xPUgPqGq^;y%F`9Z({Lb=E7`B%Oq;qbeQ&G7cDIFOH;?fr)cy%d zqWNqe9}BPFE%9EI8qI{yLSX0mV27_@|38PEf2`>j+yocga2FcTPum`Z7Ct`umz}mj z$WGhVoAN{rcM%u8OYQQadDNghYG{AlYK%WiLw}Y^|12H&S;}DM3Y_Ctn?Flq17gnA zSqJZ-XX}3c2W)wJ6&{H60U_W8t>=*`AzEkmSTv~V3jG*?jmExx1 zu>nhfLBa-v`O#mrB;o4GAFTvZc3Y>osdwDL8jv&NrTdIrqNeryz64TpJ4%1kwHUyn z2v9!OOp{PKo=uaGK4$&^dtZ|O=T#v zy!_T6O~T|DGqwB6aZGCW*JFPrvFHDG%$|L9u$%otq`F#FeNz>S9Z`Uc+|gHN09q)so97@v@^+seeyRiH>8og;_?2g)E7O(#I8ue?OhSMSDq#zC(-m*CF{{ zV8W(>FT@mQEib237~J--mXWuLC#&95ZiO)~k#&V0B>zSXb*mKNg*|`hL3m3Ql8f{L zMtVd+D1Gxn5M+XSX@)@i=8_E|5AhNMAs_LQFUSP#5-SLd@R&31qmTTeYxsQl2Cj|J zgSKUd(2cW27372{1ofs5h!j+f7+RF;}A6r_f1FG1 zUitleob<)HhHzKcR4RuC+8h936Say99L~UvSCFPB zb3c|8lfP>PAM5S6ejY|{VTfKP?w%|#++_oNuYcBge9vY38DEcnbYAMc)3pIH%Dg#+i=5xqQ+#$@4&*uHiJ$uD6Pn0WFphfx zoYtWxKj%cI(s6$vP7rAxr>ZpZU$+|Y zmqs=j8MemA?9sXEpx${PykbFYc^v5!nXlS|(N`NFuFS2?-Kba8Z43!SIA@+-NK8!v zTVyxRPW$o%OTCery_XiaaQbPgK8sB#Bx~%+>PS~0<PXX*<)IFugQhv7T;~_ z8~j`;H*}yN0@u#3FDoEs1c}m4gNLt`v`cxCtUZhePrPF+$+1LnHJnbmhf>ACTvByA zc`iLTw2*&?LU5xCyg>tho^xJ1Q?od_^UM3;oV2m}_a|s?0^6e5Q@47kBd2ImpF;PcJ5+6$Jgx7pT1m#Z{3WJQTs@YIy{dr?U))s9FjRm>e)UvjAxcC zBN`OfOcMtd{jy0GvIxu`U&}L^B!t9HVYK~9Cm4UQsev2tfm9COr!9Ib%!xV!{q2+U zS``yi;%CaQni_e!HL`_R402N4a>Q2VZ^Tp%-K*d_2r7k3s#}>Hg2mBASI@86-7*TJIc& zUiLI<)o5N_u->2ldKQF5e} zmPK_ibe?{7@Y60D?)=X0Fh2Mj6W6O-&*2w!XE65O36~3TTO88q2liJbWr<$LxkLv_ zzoztg&y!Z27Iyhrl|5g*D6rC0|AC+2?2sjyVd6N}T_-hR&)8*<$}cc|Rr8~%jZas7 zv!OHvFvjV0)nT#euO58S*3#T3AjW_90F`U$Tt~Xq72r&BmwkaR4&QlDdeo+AbM zvXPGXDdew`Y!a9>FRkl}|C={axID(;a(@TsHXbXtOQ)cV7{7~@Pp=O&1EQ@(W#eLV zZ{E@6aCEo53qKQk_UX8xk?#~FukO%g8r59t*5-+oX}zLZ6KV-h$_#gMvtxfzH%{R3 zLGi;rKbi3SC~hnW+?}UCOv?k2&!lMVT(h|RNEH%hRNW45=$s#2asC0G8THjr|j7eSlHzJVN0w}0Q zuNvM>)L6W$P*D{6;F##96W4#+cLP^~$${m+zTEntUk&&^xljL?yXCO%!a7ex;Cb8q2tq!54WXNYLuO7TOkoU)iK z6HP7j=o`{7Ib(E6ESz<~i$9gi3&gvw0^|QIpzt!@-tbjJq+K(KWu06QCwLpb-zNk< z?%s0E09z(~!2BDJg#drUX<>x-(?FTa4!XeGqBf@EYWbDZ1oye+Q0Ir=J{yN!4;Nh$hUf^~ z4gmVCM&U&PTSjdbBxeu}z+-d0HecbPgJlutE;9eVF9QAL4|Kz(N6^OqXK;Q!!+VF= zO~%U>mKVMspnGxaM{(sB&&_?Du}vh>P?#(RkbW$Gu|0nmoQew<>%)zF$m>Bq>g-Ml zGTc-s=#QRyj*p)KZq-I#l7=!r7v5a7BrtzEl^8w^yn37k zw~+P-9MeDv$*%rtT$%cjR+LU@jD5@YxzjOGFWmH)N-B@Cg`a-j!Hj(zg+=ThW^DtB zC}1t-rKEoav!Suv%00O!Lw0-qE|?XL)+>)U<4`eTwB{BwZQ*HLVr&v+i%+u}rt>!- z5i}d}^L-hgvN02!yMzC-_BTJP|@|k=SN>hWt&rwM8&gdj=IS@)N%rrKWVq% z9k*;#4p(AIaHRo%^@8QMv!Soon*v%8Z(GpiW#$v5;%K3K8p&B>+EoqvV(OSsAqHQ$g6oIWo$3+~_9@zWs+>I6GxOV_ zw*g@^erMHQX(KWA<;}_(iKf%>jhlZbZLMy3L=h0k6I8@#w(8y-rCGX$ca4A79wubk zFIQt=BX|<@dLcee;JwHp^u$H<9&AMvPASA}qS=Q+DN84_@zyj9#;16CHDgO=D7a2t;1=U;x-R8M(+J$d4LelQLzHi!fa>H5P zRp~%%D!!f;(HsDhSp~kRkt8um>dlYwYbijDy;dJ8_-DFx$3j2xcK#SNOb)0)Yz2sY zIQN_OsDm2sHbR;RB#s_R{WsG8^WxM+7(Ae+=f5QUC&YhlRgMfqTslhfJw|W5IfIob zCwBCx&b8sGuPiY6w*ku;P(n}ZT#YB&Lwju% zO{+e7@#MTi=$cx9yNV>$4nbD8nHyDu+j^m74vcTu7@9*(LV0f>1JaOYf*gx@*1XeHoGK-0Jh^~14rF4Iq=Il--2g3Z<-^=6i`3;$ zs0gH1eO-;EtxKt+L^X!JuDZR9?*>}`mVmzwKMM-I8VE^y(xgElIJ-R)kAzUr%e6z% zt@3~GZjT|>f*ZHg;puX!GS~`-$lulNnOQhZyh9SB`JVMGEJ9tz=eno7;~N?$<$y zkZq-(C^TOaLAJXVi{&D!=BaXYe<>!{p3FLywAKDiS zMTXA>F?RwkJTeEDbD~;Uf*v8|o6up~(^-G7Ii@FCI@-J-^uV%hS{4dsP+<8a+6Toi zu|0Ns`^UMv=!U(TWFhR{7=Cn=ocy>>AI~Mv%mA{I0F*%PZuF*J7LIM-95y_r0^^UCT(#&eVpL>6B z-T6@c=6)VCgx%vSh62Cj1Umx;&AI!j6)!E@lbhR1p7Y#pS)G4YtbCIv<*58?W=Erc z^F=#wI?Nwd#+JvqMn$s|fHtwOEa#CLRB~OG_sHEnh;I z^R@9hLGCrQ>7Z9c=*v{ji?WZ(Z5e+oifSaPivezqGr_9u z6CUD*8GlAR#Hyb~?pwHZSi*Gd2gG|!wkzPh?u7`m;&Gj_+$n`c{BdV*^N zs+S>3`+8^zS$sN1SM1vdm*>7c5KOm?2HnZqmjf}tV$&w*pA|dxCR23xIy-;nUKLD* zozkx)4m$Qv0ussv>mp#tC`I_uQ1Z7tb3-(pvARDFm6uU}7b1*mTK;u=?oF|`+fsbX z&8{+UG31)|F7W1U9$SsW5VSL(eKXTP62<~`zY+?u*-~jaN#E`eDB8@c1PpkES42hY ztOyyn%`Wz-!2cIm*Bw^{h<<HU8uptk2?6jE zPQu6lbobr)2o8#Jg9_ zIw)A2gUp0Ftf(M@q0A8J_Lj$!Uc@gvK%YcwWBPxAkPg+J7E2koQ`MHk zrN^ygg}HWSp@h&~GTLFNM@ImC?0jN|suGv{ro8wO1l!@pXvx zlE;6!ei#mDkDQrB1;?Mj$U~ry@lJXw+RRDGXhYX)q2tS}U$YWe_ zNU0gWadu05#V(e3F-F-isuMe5!m%gYc(W1hS%282B!7Pw@s;WKT#ClYD9ary%UuOs zHmu6!_9pff(R3ARtv8QxiZ7>gf3fo_8-8DZUlR|_*xEf5!l5;TtlJoxAmzlhCk&NB zxE#W0GU07=qPI7nuk*XDBjFZ+&X{SP-*xHLq9;~tzuoR$h5eZvGr?@#{u7Ek00IY!|Oxe@)nSt>*w!>S9cn#-QkNE zm&t!CZPbJjj}rkR)RyhW%S}qnKA`5!SPy(Egy$g56hOheS4q`z=XTSAe6rMOHfCOks=c?KhF(t{j7P+l9= zdMq6}qkY!lK7Yf!(E2K1S$xCE#_AQ(kl`xyr$cM}@<+VRkTNdMq;OMGNrn!F#JYc| zsvwTIbCzcQ;P|^f{R`!8w}4?Lr7AP;VF2x>s*-CQKa$n#331;Jkl}c?Z=I z_K`5ZS9wvbJoN~|)ekkuB&Mkw~BPJKUtd{>H|W*f4Z5D#LnbpBZG=ZWLK?x@*+J6X*V``Du^ZwBr=3|pg&M}Lw9x6?#&ZT0w1uLhhEwu8ay42O zWr@N3Utsq7(ef26yLyykhRiXBHsiP>h6F-+%bl{6-LQZ%ztpue)nDTTMsjCbku5cI zMCtMwi~%K#$85yaM^t}aCN^)KW^|u%p^7krJRkR%-{bYaGO)`RbSgCTbg;^e+2`KN z3XX;U(mmC0qq@emp5st3Vae;(C`rCeBY^Q%3r>c4LlqDEua7c{Yh)JJJ8I@k3{8%4 z|Cd;Ia!UC`W)1X^J2XD~0eL@NoSTG7cCJpzpwuEnm>ZWZ_fdbvtJi}uSn5M=Rn7BE z!j=*s+GG&2C7-x!TExuZFl3o&C>3A226+&}1yKX?sy|{eKtUD2H7vh19VtJ0&#h*X zS5?9#gi-IbUbJ*J{c3Y_(lC4Fxv>|J>+vsNTwQPF@$5kB3gP~i& z$1JY|znc-&6ZOpnbO*(e=M5>?Zphjg_gwx}y~V>FfkUQR!s|TmMhX|S;4oe%TDH3_ zS=YIHlSOnG!0KdAyCSYDZB!a(Sp1YaLjAq@{3QL3pkjXn%X_o*Qli+q4qICip`zHu z6;n${0f9o7*e4UIg30Dnl~&<8OXPwKULebdE6)3N&8ZT)dfF&}(lJIqYv4M-n_ym;9b`qqkG>d{TT^v zF2}rph2!$yg_a5V=i)b~2CuWRt^_{HEtg~)vMXfgT@8-iJpDrtAFQ*~nu( ziAR4ujZPiIq#e7GZlK$I{_*@z?1CZG4PRpR{gQW_aMs^PcRMHhkOcj79J^DhHo4UA z$)(>!J2*MYXbcd24P3kAAZ+SncL$4siJ$(`J=PFjP{ItA8%zKNFJ_`w45fhUB)7?$ z;>$x3PFW|}yZp~imPWc11KFo_r(bkWtTlghvt;vOr5=nXG)93&<@t+gu10dI^6qmy zDGo-*3~nCodd9l#?>tI|gKqT}(}ph(JW5XWbla8odKi4Liir>jnx;BlZ{ zv3J*ar*~oF`s#MJ#GIeAec5!-lDw(4%31E~_W(1#aXvI^s5&W0-g{Zh_EfzuTg35CG!C8`|Kht%>?PKQf3+C(NOc7)6SOh141rf~Lf(H_2UU|= z8|}3owSQ_xQuCt`gtgCn+C;*+@A=8?bld(3+(LGhr*V}SV1Z4AeObMZgtJAh9f6d= z_0!4)s;_Hy#HranB7rchyCtc@c%2=XPn2qN*x)4m+g2Ga@fqkED8H{(&5#NJruCFz zbu0*9_+UR6YPTt@+nm}EKp}q{WL?>>-E_G>A~z6A@4*p)fO@!&H7(jbX3x34h>(^_ z5Tx7lPcTdlH*dX3dG!QJNh&TA3uRycThFy7#XT@=#Cr>7S!qUWNFay5>YO7mbicYO z(k@%JwQDD}*B4~48A(>?S{5!O@k!2)@f*#{)Ny)A2Z(;`ehqU|UdVr^VW7<%Lt6&k zL?^HyeJ@BN3CXU?#hn;1-%0vrP6i3XuaOyw>60gpl~1cu2}wvM*F7f7@d=E5c}&iB zDi%wxg&Xbj@J}f!)(lMGCQOWJza0SV z#ER*bxiEArdWz3qtDJlher zhW@eHzOjz=zc2Ss6b}~-O3*h7(>Gr>4+TG_eTOyA`09n+VoYyHX59f zfuLy`wd)*I=bHf(ue+S#ynl@usTrYL?mZ$QrTtT0`zKfH(0PAqXtG#_LRKhQI}4hu z@X@zPq3>s}(yQR12=10X$u0~kchX4{WY#=xUYdYcg1)@3E&^pjltsISxjiyUHr@D> zCS$trjG92#-9^#*21EBQwpf4KFHi6MK*7df8I#^e5nL8(3qi26O>l)v$;Z=2;&5R4 zwaM<$>9v7|p*MfU;AchL`QP)%cgd5uu8&=ln1>+hP1^qf^*=RfP(uJqK(xP`4w^^> z)~&)dU1Q2WE^bDEtv1|7&|x9-bSmxH|}lC~vv?W%+d2><6nNo zy7$xBziz+22&n>pV$Sol*IrkDuYMH1;`NAF2S}dnW{cl;F1VzRAuU%HV4Oaa%zaws zRW@D55^{70)$@**5^|freK3`t3G#c$v~2wAQS#Aq zXi8ZctvwFa$aLeO%!i>vy)IW+x4<#9opE_;3VwY4cqIOR>o##h;aFcF1N{DmzdO-z zWL&Bq!PPZ+T!AV>6*Jke(hQbQ*mX+15o*!(G2mLS_*$~rB8x?#{7k=y3zL+O}{e)Djtq~Cm?o+qe^U>>nWxibv>8(39%$m5dXS%5tS`uL{6T*N9ttPJ^ zs^Yo&4pmAdJYH9P9C*gQG3GYVCLZg9nw)h#T1VZ}7UN7GR+|LGYrJ*|fqZ0nTae~v zf1dWK+(P*dzOt4rhn~ft&vtPoI`sJtScPxu)@y!$588jGz4dXt?Izo!+AP_jr_41? z_wHaP@cosr0q>8KzFB%OuUpT*TB2;BO}p`Tm!3R5=-eH>+7YYqDIzBXUAAeVur74i zPuksXi@hk1ip*Y)GOO)}p3&r#{_?pG?Nr+N)7jf1tVAcwRv=`s)hqYYqq=c8MirvBc!WgwgJH3~?8=4n( zYmxdgQU$#50K}NY!=I&)lqk zKbfY&L`q$Bm7dCH-1SjHj9f<<&W60vXo6c6+UM-DtH%onqb%B(@1MGN2PK|-d5L7# z?^bdaX;8$wU4sJ}R58+O^TL!dax_?$2_TH^tN8+NW z7Nh(q5)Ll$dA&K1IVHfLaS;Mbh^4-Y|&mu07j-)_U(vs9r=%6#C_mrc<`fcBZ{wJ2x&3gKNdI~ zlPHEZ{os{<2_|@5GQI=8W+lXWApR-7R7IqX)h&?AKfTOy7tf@BVZ#q(bp;H@`1Q~; z{c~RD1-ri~A2ZBfGSGqc5UE{%?Xpw>Rm32mIb&miude)5iZGFY*{S? z1}POQnXM?iG*Uge6rwx_K6m2JzGP00v9FN_&Cahj%3@qm-nHUVz)#d|*vQxc#i%}V zhgIN!y zeTxj^_fW@jtcXGNm@|2FyU*ctCUA3*_sycucy&}0ezjLz5FR}H4-~q zQ#im#ZdxmfRPpV=4PzX>wz?@oX*m{{|Epd)WmZMKS*MNBLE<5CmNlb(`fR&$1@1fZ z%`%Hq-pzlv*3!gzWB%8T;bG|g(+x&n#Q9riDs+**%u^RfLEWE6-3#-}76mv@ivj<` znwCp^_>!ZKukZ5(l}ogJhPEd5El`Afg0S{2{Qh7d^N$`UIsUj62AJsWYUxDP=@ zoCa;-dm|f%d2Qh@H7%AmcVPZ;|1sp|zgm>&GY!-tYYJ1e* zsind8h^|0l50pEq>G7d03kD&!y}+qximD!>qWq$l-um-@R%%nDMnFuUc;7#~6=-z? zsCgRDb#wo#)d+|hSBVs~pZ0bc@D;`HT20+>wQ|qB>}=Y)21y}543l-XK6J}H1@BXw zWy;^@EeCrn9!o8LG~*h~CL$fyqv|vGivXQlgf=@@x8N0##@Uh6*AP5OoM?lBItq|N zOVx}@Hv_DH65F&(XFcq{`*~};zkneFAnGpWZEp=pLtZJTPAPlcg4aKa&(n(|d}*{yaMa5Yo*n$qwD%=Vjqk&F&JFI1kdca5aRscdeTg>(^E z))3j%XnBQr#bVK>5{Dla7u+}rhPJ8_oN2L$&U=gcT@FeMytRm0HjT@?k+q5*u-x$e zxIhip&AwUeS!=tw;i&?sY!o~U75iru-PU!|7(PGo`QHbd zPGCZR7^eHYhyFeW&@|iZX5RawFPdfDVe`0*6E5>7tk6s^65MJACigO+rXM71j+S-d z3~%l;W3;jW$oHAYh;LGk+J~QfBBCkB&xbE#ZCj@hnGy00vBB?uTkkX0_PazQU=Paa z2N93krl9zj{8hv&%dwAqOH_gf00d{qxETt60ghh+rJh3fc{-6PelPMCTE^}(;rAy*MlskB zdmLil)Fv!3I6{54CfuNe87Zd#FjK|ZH37tdwwydd90@Pl#r`&VcR7iRRNa`vKJ#vW z!&|@ok9`;2cDyG(i-R`Pyw!|992#OcQ7CVzz+J@Arr&oPcFTyD$}N`&RarE0(UTVd8=M5FlxIaf9Uo!2(Y za50n*+eV~a@I*;HH3}#ZO52wKeHR!Jfb6DHZ$Ob(_}h z-Ft_#9)(Af(iiIwK>JM>;A;%QgM{c}6W&#~w*(oN(&{xqZq=kK0irH&DU$ zd%f++93?_`vzZn30AIsGXgiJmM%(-*s_K0GR@AEPZOqO_ z@epZ8PhFaI>6reOE5=}TFnMSmXHyh)lVGTYXe5J`KWjt|dw@PLd%{APp36B?41Dzx zKW@(Jz3?Hg$u!SlshK)nsN-%}7u@Cef(IQrxW&v=B9n7@cgmWP>zT%qdouajNy!!*5x)6HTF`IXr3ojy-oYD9hu zUHrMGJpDa-QbB!xkMH#S7bD5R?h4U6YADxU#{_v`(X96q3dw9rOwV){@R$l*oKLNr zPTiqb(`cl3Q0!&kQ9u!Rh|a@5duQO@u7}bs*YPi-;@d?-!_1>!-0t{W`;&X883WW_ zG}@#*&dlv)2Bg%nnVjvi`*G*HB4?>)3O2s9Hj~n%nE~#9)3T2eAH#6QT6sUD=rOtD zv2g|O;D`9UKt77=+xdG;x$#aLSyy(vhHMXv!e8Pz5lRqhJzYzgVI zP}!5NI#xRJshM}wY;W@p{FRh1(} zZ|!u!$Gw2i5z6EF>*|HXiEt}Oh8>>j!?rkXUx)M-eXhA10qC%;ajZhom(!rU7)A1@ z+GdK6Wa70yC+IC1{DWr*EyLv%%^MqfLn5U8Em_ZS|<7e3=clm0u=xsR%HkTc7c)5SWK{Cz}<%SvYQ& zo1|>x`gPe^83rf@477|(x#z%taNYlZ9SH0srjGI+t=~!5De##{y zU>*kfFu)#Ps+5Qea3dBSytX~OIbj|p6a=_xgQ2%LovQMBo(vv`gOyuR%}$+d4v{>9B-o3 z4uyVLYV%i4YJ11#pY;pAG+`$={TRFnibOl6enkDkXD}aB?Y>9Vz-P{9*E?fj_1oDI zBErr##SWSlgY42W1aj}7<(Kz=b$9p|a^e6UbvKQ0+W-D@LL+_xBbyxkv@=QvG_~K2 zR*Lwg-*AX{80J}%a95Lsi0;VKi-mual{cl49qmuzQ_|3kKk!q*K7K2;(Z)k-ydQVjWjOmVovC*?6u zqK_f`gdpbT+0nVdmBFS zIxrl(^pV*l7bDzkI43+_uTnt=Q}4Wfo+%exnnPxk0jkCo<*7NvF#hvLOwWjo17KWv z`K}c=tG-{ikibJVJwtGRQPE(DvF_WrQ^ZaN-3vipU{w7=qKcj-$1dp^;%Cc-po!m- ztatU_!Ahl%MCkb;EnpHcZjOY{daDtrUmgSKD&L7AOpCYC7w}LGlQ77h1y*bNAEKKO z)%1sVRyvM)d==oMrudCTS#5kxCH~NR7d~N75DSpmEBxxDL#%gy2>|RRCDd#l$3MO3 zzq>8HnN;+c4m*5sIa~9SALr`ARmGW!`Q~dLmgjdXlFxz*7yg^y zC*gJX9lSU%Bfk`d?W4<^>mQ#CP}wW;re^hx=~P5JJCo;&7bo#yU{kCokzRJc2Rze5JDUQho1 zA>3?QiDv32Fp0QdjtF0v6O=hzA+D;nW7Se|#}{yl=bdC5>{Msho>QEtjio3RStZI9 z4a12}@#kbg|Dn~%YVr0e_Dk6?scAjlVP%`G0PYVdCKI=Ry8-j{Q$pj}wNu;=yFQ;{ z(T0p3k)rGMQVQRBS|<9@{Sr8xO8oKp?{*ktG6OFM=}r}E$JqEL7ih1$lTLqS1o-D(O1qTn)#$^;zw?{w z?#e1B6dj>|h{ z_OmH}5v0_3uS11jy1#^F>c(z*Gpeatbmg3S8RZLY1Oh}kMw5P-K)JWtx3A$k)zJRO zaSxMBc<5;$(tm@t`hTuS9SYl~RSaU-&2t?K8YaafdE2uOsxgWc zKF>OYjC}HcuzvjY;ki~G7y|4yp^F6ctug6;In~%CH?99n#>~i0S-Z(~yO)h_CvBI;bXB~=;myD;9L%v$raom!+6kp_i3~DmQdmu<4hupD{QGlc}dz;WuBwm z22uKA`;VE>tb`CLcMf?6colYZu$r$HAIOnpPSj(C-jmpgIxqg61v_XcqNX(8iQ~ag?Cg{dWBKLc;0*W^{~yPf9a#V}?=J z1EF{q2CcYQH4EiaI~xOB*B!$#h~!Lv_OW+PbhtfisPk6~mQe#HLe^SW!v>;CD~7fy zi(f4&yRb%{3H<`nsOx&|$F9Jfg95Ta<&ZdD=0%Oq23o*LrXVmbdHyQ!^E*>7{ zPt&&4pKrz6iz2DVXPO$Jjm@2H?R7sU+N4WkRSi@*v=Y~I@j7C{)@4mPGP5>+bl7DV z?a_=c?c=Q)e6l#K{*Q{c42m<@x`l%T4Uz!Cnc(iO10lFufZ!eo8r*}sdyv6hgX=(W z9o*gBWq@J0Iq!S!SNE&xe@|8S?tW_3TD$k|WzE)Xa5V71(x)6*n{?e={}zX3MY>!& zQ6nYc{)pv`?d2Y)3Ghp~;!lF6W3nJE{ zv-9`)@c2^)4{r;$2dj;U8W?k3?8}l74qjs+bEdpTQ|Wgf#(i2!*p@0m+s=db1cQjH zbR-}qEqHUFqY#u^a!9Ebx7EU7SB{f06Ks+g{rg9WcT{yOdHDB0&OOqGJ{tfh0F7oPIcH=qObDDiXCSn2zCsBh7L|2bqv3*vV}!r@ zl0Ru%Uh8rWCJSP7=~G1FUWTlZnTrBnOPn+Q@3olHf0#O_K`Hk`GFuyiFnfF=mHwRD zsemS$wq2gAD$5XmB6^;StqO@ktX-?J9^WLjBeF6AV!)wPi{yV;+JvjmX{SvKw~5Eg zGsAPk+YACJsX>0DgY^wP7-G6BxnK|??S1n&e}6tuf5yl2RqLSpR%y_Zf}_UM(DL|C z9}mep2v`@@m@<3`{TuD~g&;n{trTj&4!fFXEjR>w%(vZt;y(UZknP$Bk9^ZFx|t7! z-A}e7YG9c0PPkhWVOuen}1qPe+nV^`y;%2iXPo<}V0) zbPhdy#%~}M-1dz%)jKa$bK-mf1C;x<=Z5C30A8W0HD(dF*oT{!IQVa+3cp zbm8s2s5AI~B`l7?u8PWNG2fJ7Z$sdmO3j7XXe2RNsiRoi19v$K< zrKYZ8blaqZ_oE95p}90}$bJ2HZAH5`bbckfo-;~iB@%N%FW^TxafPSikOQ44p}82s zm3CHt)1i^4PaB5vUGIFtdtGGB1tdN}RhK(xnBsVZR4~b(C1P#1-|MkLwR^z%_q2aU zFfW+XDd4VZ6h(!7gfQw5`YfH1?wn4Xs%x$W!aV?E%iC9?eLy4gK0sbRySdcU47}pD z0&TMiTOb%35sokB$7*H!lfSyP*v5ug$)XT{Zg*L`wA)`ybM(V0JIc%h)w8&NCr;zo z^UJ?zk=Fy>&0M4paeZhV6fL%S@E+p6JC=7bx+vO(l#YgzX&-XEWhd$y1PA!IW?UG1 zc}V1q2Jc88aoOaJ>Swdz-4MQ^&P-xU`lWZ7@2`@k<~(mfw-=^b+J&1maJJ5}M*hd!Qi&gwpveWH`bzdb}V&ZDD=IlLr!@7v` z$To_3!xD4Jim>*`)kjcI*kX$uJHZ^5u8sK2`Fo`r{o$64W~1wNRpKIr_;k&GtzC2> zAU2L)&GQGR)4Ij=fLn<*AMiw`)>`sl^5UK6y_p9Er^sS;DQiJ~BnErx-AAKTCOgBB zKi!g^lA6&rda5qm(ayZiJs=Zk{g`*pbDY_>XHQ>{UFQPxk)`vqot>4#$+)rxf2-AM zcVO{eGwb)veq%}BleG!Mpym62U}k|Jwp*5h+9o-ef8>>sDJ+fZCGFULvkYfc3_ zD`WSFMVbJKgU(N5{*pItfj%2ZW3?0k!w+m^GyB|j2H5^#*2fGl;QB~^7Sg5{>j^3B z=p0O2?|G9!)OrvzQi}Fr%mU!Pv+lt3x3>@ID(s9Tu7X3RoJ0GxMznKt#uS=LEM|N0 z`5EmgHBZB7+z%MJTzN6&)LCs0feTMUy%b@1u9)!+TOW>7lW@$jTt+)QG(>sI!<1`u zaQgRr=#^LmrT(EX|?p|r#N%j{{_Vm!RKzkNYx=xsv-Wy-T(WYNau zP$RyeL(%}UrKR&^Yk>@$bCktU!x;of9_BMjYjbV*D%>9|*M zQ|WGU`_6;}{lNq-Mab#}2(^M;CBO%sIAl@EY(53;PlXY)S6Ku0myfFc`xZz?&0&TE zSGm2416^9ed(n)4B7T{2y3snRK`~tM#8{StDjgXuZ=3I&gi$GAZ!0Oz{&WG)VH*?3CRHR zD+u?ZqXl<=;xn>C0Mfj0R@jn8=P8kB+e9VuHLJhwWe({rqy z#HeIuc#BpjXrZ(vVfBY#Rr4lplj3)BkIwfKm?#rU7^uSpWdznU9O5VD_*?>H` z_8taEzr8pYbL~XemR9JS*7h;yYjF$;G;}ul?l(A2(-@wM>h2YOi*ktcHu=aHMwn)& z9dp$%bTD+ScR;;KW1Suas@8e#CWxDq3X(eD8*|Sa58q$pu3bNNY(@cVXu=;-G69C& z;*S>^qqjODN*c4!t#9%ci!GmeqCKCYe}fgHvwLl$dQ z$at~?ZRIQYy2?TSk8k?LD(teV0f(F3H@y+ZL#Yi1FDUam_VK(o7;3Uw;O?m~=$jsZ zs_)>{l^69BDKL~p^R9_uRvhap=9^Nf_Gl!s6hnjn?~K@(96-8Sb6QMs1T+8Q3h~DK?m>izS-__Jf;627jpgrW36u<48SDUS(b7i4gGrR!R;n zVCl0<*S*RE{=cmV_i&6PW2R{~w+zfew{T5`wjy!@su@0_578J*!NICdAKaso>C}G5 zI`N}Zgz_T>gbt8iqAfbH=+|U7vq?&SMKOTp1&w1dN1~MqT4KH zu)Wg2;Df(JE%ndEW|4)7^)8OSoQ;|rq?5-N*#=PRB4i7#{{;dDuLSx^)Y4ync<~Y$ zANN(N`}6lXbs4vVi^w-eSNOtzYd;ifvyGzyjb#+gFx?f_IiQ;K-$FjmYDwB*Y1$uD?}jP2&A`QX0l zlh_Y$=R~|HzhUmlAnwjYn0%FmY~A)>k9}s^==J4xoMbzt5_+b=c-qo`pr2cN*JiRw z4WyG_ZBvrVdIzc!ZXI25%GB35+x?vnS(kM@#}N3^#Pgk6W=0dqjm32?w8@6JLUj%c zrYl8WF+Zh~)z1w@0nMbt^JsDgKZ|^!=;4pw86YS0oRFPxGGcsuVT;snZ&)2lCcK16 zE^s20k;qr2eu&Q^-0k>(b$ijWF@k%6noef;X|w>=snM4hCgk+d$27~=V&^t8f96pJ zw$|tCl;i9pb1Ac%3bhL8<)-xz1SDR5%*`C`_86V|A!L|}Bj@NW#xoQaOBanp5aOD& zPBq9O7}9A~$alpKo#d?o8$Z=|{S3KF(_rMS0q=@Ljgtr2p0ERddv-4?JK$WDcWLaP zqjc973uOBVe)!;%Lb}{be^dF7A0MZ+6h(0NNl$nQj$I3vhkoX2oprZa)(YG_VOD{O zz8U%td-iOK`XTcoKdNHq`Fy~0W`db^;KaB$Z-{t_fCmCi50vc>GUvc?JNBs7( zGh9mbq7W*Hh+IT}n&9ciPHPsyragh8&bv3^GFzM;@0CB{W_cjHof)(((Yea5F_jux z^HO*pWM+7{!z}iLJ;n-J!!5DL-%?!-;jP^TvNG*~oGuB} zb|HA*=d_!-n{Z$H5C!v{s&&j<{}rf5@~B62#G!64$S`Zqpmeh}yg~EKIBcG>_4v4o zVn77+CGzlnO^}-B>!`kHoy5ALqPy_=oaM>pAd>0OBX%0{3C%k$0D(OEh6&-|V_1;u zjE;dGcPbyAJ$4puWeX&?jcz&K&aPoG3DI zs;iooMO}G#xc_{#u@>=b?Jk%h6a%vPmsxzfMWVs)NDioT1BX@Qi z3=Nx813L&bWpusNdJUg16b1PBZ5*5pmLb95z$!5|$9o+xv61v$g4nZs?eyPgX~t7KM#$tG26Qf2{OB9M zaK9?9O%}SnEf06l#7DO-HcxL;ZyM1mu*=|?fHC?6Rav{dNPHH-Y4NBP3v>`4#a`ia zsZ7Y)iPdp@HXvHGG$~4DVmE#a%m0L!Uy)yb{2np!DlnRG^O1bKf^qu=w>XTDW=`$C zJxS&_(uxU*k7=T>MgBELP|{u4>l)OTb3(9d;<48YN!x_8`tKCzElN$!ue7T?8lDgZR5xkD&Hr`_L1o|G#X5#p)$}^e+zlzYzSNw%4vT zTi4Bj_z1CmiSNwCG}g=Jq^1LW*}3(9hZM*uY}WQG;(k-bTpLe?Vox|v00wL+(D<2B z+ls<;g8|uF=dGX4iQZk#6Lu5B3mR|U>;^_i_ki55_7(`Xm-zkHZx2F&ae==4uvUu0 zJ)~9+>h%Y4)U6b>4zdu!*h{~}7oXr4*1uw(&ci&&0^DQ%j=p{P+@WN|WwIiF>GdV5nwQM&I?Y3dJ>b@4F8 zqf#^7z3lfniNBhqwjIMcHWrUspTUNC6j|8npnT7I~LGA9vDPuoJEp7<&u|}v=?-L)Di{1u2(lN zrB=%)Rz}%iwMSpB>HB1(Ly{}G*O2{b{wc+ZYCW~PeRxz*?@s4In39$i1s7897m3us zu$a!YutEC1)a&!1b?d-R42zl%)-}_PPoY)j%loz6}}kykJ5~(eDxaA6g6;T8rv`k6z(m!4UuWM%Gmo zID6#v0p}i0q8Su*7OTciTqADp6Ha=*Xst2iJHaS|ihxor_zmDaGALg2B%0>E56uoL zF%XJAeKrb19PP#V)AerMJ@cP(P40PDKJc!3K(Wkd9f6o#zL6d8I&Eu3T)B+>pL)E? z-#Z`u(jP-5Z5>{JUmKUnwQ1uq<-eSEWsM7oa=x`d9*M=Zqdy(}lKOQuW!OV|p#2ht z^`A8mMtj@;bd4q6T7-hGe!Cgbq44hjl3)cc{V++nOXuuJ(qRcB%hkk;GWmGT1nYWEmFDTT=(@zOGR=m)q7O5Vx_-OFiJMx zPHO2S(IAZcOgd?^Hy$SMCwqf=?z2EHxCspDoeDG%-@!)3p##x=v)#Nh;9)rmVXitN}Xn{61{r_etyJ!}}JCcy_s3 zZg%;XK9c_jnT*aW;>R#s=TGJG{4dauVCZ*4)`9zfn-^jV5PcuvD#5lV$qW44>P9yl zg&2PD_77{(f_wL^=Uhk|5-V_>%-P<<@RNT|w{{@E7|Wov|qdf9rsN=oW&<09W5sCpAX0C#=xJ0O_V)I5<&11?^I3>BiVq9ro4>M z^N&nFBTqBwE1fl89`~%k_+Lt?vZxU!m_nU@b;)M|1wnu7qt}^z|9a`ziVjia1!*=6 zCXfsfh$S6Tkn9xTJ({*z^`?pHGk8z$3I>`zVBf+({Hi?Tgn@=GK1Ds{Vv-;y)ok2dy$O%a{DgwIu$XhoP;|uKM zCJ#Tqf_0yAM30ZZvHQM%*1|tlR@_DS_=#G*B(3T-DVN;U6AS=WaE5lYYWLGRf$r*k z%)8+@1I$5(-ZC=NK8g2MPogwOB|RIUe5<3<3%ar>#Pmu`TjAy5?zi;|T96<0E!2Nr z!h9WU4QN^iA2K`^?WgR={*9EFsuD91S`>%up5A+eX_bVEJL64%{rZi#KZz(ck3TvN zf0jmTj~KBDnP;aF_HSBtd`~1aU?XDx?S*s1%VXHfHti5hxTN9n-nXPjj5}N~ZtUM7 zz3-46l#~8R6^BN`ue-!Ycj{xd<{d>^b}qf%T#oIql`-A4ORo+**huXq&KK)TYZO>qE+&L85i zH$7)z&yEWma>+RKhMBC!5UZh>cQ9xf>}NuZ{Cuc>d}~vGM7AG@`ly!{(G?cWfMg#^ z_)^mr&G1u%op!;(gAN-&5q8XFQk4?URw-c7B}>uwRks}u zucI1WEGIpzbRH5fY*#v;XSP%4#25s+9yx`sApm`IT`v*SU)1BTY@-;^3 z^`rc0pV{?)fe5xfF=pNJLhvUk5IE_&kM>~aR%*Q zf4b+g%_a9mnlm2eIi765wH5GMJEjt%w)3J!oP0Qfp~5R6ic9ytK5WEH`bfO8HDX*b zmcCkljTZ)7Hm;IkZBq88$Cd|ktdJG`wZ7`q6FOU--*hY$stC^(g=qoS5_rTUo`_%E zXCxo6OB7DYRL#m0<)!|3x(X+b6yLm$4;Yr^OA3%@LN{gspY4+43qLS74GKP7c<$cB zkA^Mg8pa_ucHFwOwlqNtbx_K0#cilcseX`uN+@Bi@F#y>E+>o9+Lqx$&) zg9n}}17jcr9+LpSaghvt4voe0%uuE&Qsknws8^@DDtEj;SrlBoKZwVhh{GFNZ`m$b zZ$#KeuIU=_!+Bd*)MGb_({*TNz}T|(IqAv&{CXAYI;HUX&iN|b;7|LX+2fH9(?v;t z)hr=Or3jd3f4y%c4X*>zy7+eI4;{zdzYNY?Cx)HJr!9LPtq|WNE_8K_&MDbi88tQ0 zPOI=0)zbokFlHx0GsRrC=njbMeM^rMR8s$Kle|TaTFcFx?wx$6<1`te!vwD(DLw5@ za?*#ocW;XfJ!*&g8QTVzetCb4eSh44co&NCH+}{sUecw+Bsu}(#i!GzywU)=RK0Ivt*rqP@$Yb$0|+J z_wg!Usmk<)C=ib1**+-r=x`;KcO#DpJjob9mvw_|!4=-S+>kxVQ*58AZMm;8{9gQh z=YsY*QJL;Bqy~+~RRINHtn6-odQa+$(a~;OGiF+@2i@Pm z`)DUHb9pHde2P2%#&1AC8>j)9mS6lg>eop)?4Pjy*OTCXu0oahzor}GCD8>S2VR!A z;gv1(*exrCE3PfZ8*A2L;(j*x?NOojThm&osomf_QD*D?J<;l?D>M;*L?^Nz)hYA3 z+T|Gi>iao;8}1WM&dNYfYYAL?=mIZ7TY8WPonC` zbO(hh_e&mt_WOW<^+D=?ikLS4rky6&AGa?hSFXyiTkoK4LOCc9(qIgKA%Of1b7cGR zn#d2NG2%M(nG$ay$7t@}91>P`{JzEohyDoN?iBmQZnKe=ArRk*-gY^;9%QHLo{jA& ziq;nFpko+r)fDIOb@D9fjXR%nKxRbul;`;4SX5poQ*IkaPxU%~3iPPyl^;CNV z@$9K7bny}ym(A)y&zMUZZQurht5QXgp?Tr#EPFni3%+JI{&jm^7Y!fE``i%q@lc!- z(u-!dhf-SRlK`-PZ!DN>hn?_PX^YyEb;&|QE~g)C&rb#3VSeTGgzyZ-I&v_y}5qHB%4Isan-_Oe@v6diVMF+5y&wTM5)hJmZ~?tG4G%B zT~cF7@NmGHB6o41K8X{&>M-4wxPP;Tpm<0wZk&PCIOxo2_ORR?B5g@qEJh>|HuO`9 z1)o4oi;+Bk@i6EMK;-gum4teumvI`k!%wK{fWu1iKE{`Q`xasq4K#OXk;V*E)NZ(S zpgI~bO|_q99)284cS%&842(F;@C`qxIHtjN$WMB5osL64p)oWNGr5-Ls~)X3N-1QB z8N$nyJ1m}|Y&!yq)-aX^C??)W$gKYG-;C83-@^C3I5TE=YN zIu0+J&-InPeHbd~*4f1BMsB3g`lHVCgXqAN(nk9?4p7*E;xfI6kyf0O2cGDB&EPTK zycr3-@?Vu}Y|~1+oomb@?bVAb_W$bvs4^o?G^l5+k)POq`IrB9mv~bisoqjeEs^{H z@`nt6JP!%evBRdIoTKIGM&ykIB0QrfE9i6@jGL~5pA(LLKc8v<*CE*e9r87Tj@`)zF;%enARYZUfYvTAxtF+!2=gy%OgGkG1=r23az-lX*7m zHP`Jmf1C)y^h*eLr9WoC800! zZXqVxT#9^27CQGqWzL&P=-**}lC1xLysOxXg3r0Dly|CWrZd z_YK8Ydi%gB-ow@Y0+v+9YJerR8y~-G2$y<5tY=XB6;y*3>U?8_a>AqFBE>2u4`&{| z$B|9vcL(mFA9@n@o7ujJPyadwS3CM!3^`MuAl@B_+*+cGnlId!N7p3^i+n`&huhzY zC<&erkH7ZUvxC8i=4HVqoxfL9VRnNrncE}uM)5@K4n_1$dplye$)_D z9V(Q6o2o)=gwg85X2itf>;^wD`9ch=g*3CvGv_dkb;xU4E1C~k}6 z-A{8wp8NN!h;=7O@ODxK@5x%*e;2i6S2sx`@?&vu7VdwXAA&Wzv*NpGvn~n$pXy1| z44*1`K7|(pDh&Wv?!B_v;Ny=FS!*PzeA;|b&Cf%XXG&(fpiKcSCa1#$GeCgMA?6*q z2Xcoldm|w|ALSPW&!RK0>1+qfdEp(EBr~Go^YKdl3oqx49<%;5-Pepee}AJJ3mM=^ z+xqVtOKxfZlxdl31fGe!ii+-6QJKetm~Im!feQGA2mbE{zhr>!2o8;2lNsWU_VdhP zvl+~&7z)XHyojA>}O;Lb$v7|#^C0@Hz$bT*Rd)?y3g!H3z1=2 zH+%H!tM$Ad$co{w&m(oHoeRIg?hrojrnjtwb{Ku+J~e87Vujn%KehRKRNZoI^n4eH zORMemt`87u_1Auhom;;GCgCR0Kz2s|_;+5NRFk`%&CgW@YrU!Oc+QFWC-aKi$;nB+^=wS8`z{Cx zq1$?o>{SJzlN*dXoEtv_%uWdzpZjH>`as0^IifhaDRX06Z&DJryS+-AG-2@VN&Q7oyUQ~I>?*54^O8u=n`WL z+CfciEh2Zq z)OEW>T$N~?Z zFb%ENAjCnLf7eMIK*sS5kRqPD_SbhS^X3;PMR^Vjt>=cg9oEorI;}5CA&50-rYUL0 zRlWSji9^il25Pj8OuVxndQ_eT3dCYHtqXm#k^#Zs11+~E->hZCt04czIA_8CJqs}W z*PpOm!cr3F9-A?O*ygeEvp4qK|Mo4zDH3|Cix&5Ye{v~Q0Usw?O$LNKPR#{g6<{&h z)5KkKrpFHMmzr_o_|0Z^$HCM5#{X-7pWd!P!AdV06hqzkcBWA~=ECx(2r z6|N~Af66?|ei>g7R+1VA1ahPH57{537X7pv)%3PQ&G~$gwX;!0)Y@npb2PY8)Tc+a zZQ@PpvK8TphBbMp!*?iv>vH8(sZEr7(44zof9R(r4|fg*G@ThLgq`ia98kfQe!cn} zdimMK!!__9rjgaE@YDdso1}nz91xQosg^D z=HPlQ8rnsirE0RW6NcEh>N4f3RHf?Ze^w`B1nQJxNU0_Gyu2edDhX^H2fjupLNKWS zwno0n1u`x;hy+4|xQ9#^*^`SRi%Y%_%rJ1;7WqSv|0Xk9b8%&w&bxu8@FR;%21NycTJSuKxSse<#Ta z(pI+6r9qqskHz)d3eE#RxA=X|y!TMjOlv)|aqzL(=qfpKz z{Ygn`l0Qzqq7yD5wG4q~jI*a09yP;#YRP-0gt~@w=tky3w{r=o*5%DRm@h0iP|@>w zVBW+L;nY%tR~w^!$zNe#>GrCVf7@5PdfMuerjuTg&hwpS3gP#^JfpVRGCo{TyvJGb z7Ra(YibR4RA|C*4L{UKw9-=$X{*Ta;xaKq<{}AV1Gcq*hmFhue=~j9(HtCvFihr+} z1MEwhutDL$Hvt@TXbB;XHOUvSho~xdBZ#--lLRkGsRLT#aeFvbAj3|#t`zMb$lcIy z!qN~BNt99O>pR-<(8ce2^K?cd5Ubax{muxpn#OEt&b8MDDP~7`^Pv2>SxP%GA@>wV z<6Z%}y=HaZqfkVjqFvo_Aj?()lLHfvT$l{h@E`gNe{#!AUUM2?f7@F2a5Ge=D-h$677wtk?Qz|9nXX{u}k`Pu*l=XdmLaKT}diex?LT%6{k% zO->Pkjn)~#&7xlg>J81|hHrAPP;jOKtcwvU2`=>6wW{q>Y~EaJL#rcmZTPhcdy<9o zyzJUFm-31Ywv)V?V-`vhI%?1R{K;^E<9#a611j1vv5^Zpe}m!_mi<~{nQ0!n`%+g^ zPq!yaq<+sX`t3e%{J>)0-A;Zlhp(^KY)rW}^29^pDk^=`eaGgHO5si2i+C>$H_(vk z#}8fPQIi|eV|A2p_0>z?gP7XK;IoBwZ?qYsql+o7d7jyZ-dU+Y(n`#Hy<_{){ehYa z6#Mp}pQkv|f0d+qgeFf`kr6Vt`3u=0e(w9;YZ>%w84llaCA?5fH?UskE_+#o?c2#54U2)*$ORc4FfN4;l!7{r)}pV96Q2KoS-sm6 zZRH(Q)=^vwm4f&?$$Bz7c#EG^ncu{XZBjnrt`{bde}(;|Q%wGQSvacLG1_&7;xT<3 z*_+fCeTZAc;Zxh!$M`t7B;m~$oA7SME9qo4t7IHerQk$p>_GtS;ynucR7L3W5s?>- zN6MRL0W57ZXH zYp;D)e@72nVW53AWMEm?gO#Cw`!oDm>#K5~8L(50%v$KWw~3m5ZxF%n0Ok=7@XzJ~ zenoVou)3!6s+i}zRBo`j?}})-g5Y2}@=`0{Vle;2MpLiPA-H~QW9jx{!!&k#E4!qH zb1?W`WU)fD4U&Q2F;67&1@JeB(yw*WqdYGEfA33+#7VsQHl6QI@hG2-yW_2uTv{>> zC~RlNEK6Y@lh|;Kz(Y_WTLERyDK^4+0yyED>-wH@)sVzlOqA5e>!ZiiSC(aG$O!On z)Z)b+OSZT2&TA#BdGos#zJma@tRH@2s$SDO+WJc=c-KvDz|QM@Lo4?j-Jt*aY3e!5 zf5_syc_AUU?;_C9(CnfXCTo$C4L0+9Zm}7a`qq}0jDgG$EvjKUTo<$B`2O?gsJv{) zrL)H_{pAqmg{*8isFpjsMG=KwIU7F`Ut!|5&$;VjENdr&edetMZtS+Vbnb!=gpGs$ z#ZMVpZ}l2-G501PYf}35XpZ49bit(Nf5K)G8wv2pc{KYR3;hN)Jluj5U6NZtBSoK4 zBJ~hpq>Do3$@P*HXZUEopOF0e_O|pJZ;!tYG}dVI z(yG;y@?4Nx@fiq%* z7JroPh+Q|Y^4Wa(pWeW1WEG0QG<}x!7C%dA7-klruDANEbz=90P#v};Bs$NZel_uhY&ak`jlTO$(uKI=`DbN)S})vLVVS(kfb1|l57o8_vFx;K<%%IYs1d<(XckI$ zGE}yJ{g;?y59o&Lcf%yxGEaaVShz2ir;6&S(6651*BrKQo(qD&@a67Nf3Wf&xUJaq zHi+P9hyL#JeAVB`zU$d5!vWop8p$EH7cc1udO5Ic#|mn?;J0QzoR`?%uL8-JDP{UY+^m5z6)+TBE2Wc1%}qsaBAROWh@^VCaoN#T%s zJ}+R%n$qkeDt(4+>8~bFz+9AeN3qfSu8XW~rP8FQiYY&jvrYJizE*6>?}>V>4mPU4 z!oE6pot|08mqr!6I6;1GF+gQST!&}=DHT}Px4zUcw{5j!Q^Ug=e@s)E^MbD|yEV+H z4giKHCxg9%n3^cH+jY6vxW!E0_OWYCelB?H-QwWFynW_jo%VyZaP`D!clL3IU-pCB z{=u;bUyZd>&fb91Dg40!E6x{d6m$gLL_DO-PnpDG8KDq&olQ%>vc9MduP`j-Q_T>dgc^3Tkczcqgs zu7(f&TQbh?#c7}ZB<=-1Va>a;*71b+J93AijY+T#iMA2Lb-414-k%?lmWa6v<_2=x zOxRO|rzEMjRtdSRd{b4Z4-Z|Ta%ZZlH zNRH=E)QBoEJ$l8L@nFpHxJhmv@lBeVxWL~o0M?Zw1n$QN@d19*YkCOI2T6VREe_{%iHUVJzBTTxd!D>{cNps7ng7a3a46yc|re>h+xrf}U{?Qrv=0dRAH67n)hY##4m~mENZ0e7~L%8*=3~ z$@@3gN-pDTnDdJxeugZVD;+Q=vfaoNH$cBCt*X9>{}IR%3N>(piQ=6zdO}>xuFKRP zKLKu^rE>Y34ec*Z9nQ~q0wzTFQ9>h9zo8lOfAJZeodR$*=1(NM9yonO`UhpM2}r;D zW360A#EoLmGa;7D3aI($;mi{ZY7}}zPKlsi&fW-K`x{g}{u3%xKKaL@GkUKo4xMJ4 zU%z>b6Hn`D&nej``VAKUDwcF1eEi3-a ze@3vWip*`4GDPK#sCi>#^+qiXY9loh+=RTWl}EncEF@tS@2)EVg1z9SKs1;DyKz&* zs{9>I2ui+{^BzNcRT4Ntp{YhSCFQ8HYju?JSuC?HHoUkL85BdeZ%BSAHNQ^(rWB38 zGrH_(#|Ku%(Mf6-72wSUu6=zG&MyL+iC zHDJy}HIzK*d$*z_p}_-OA!3_Z>N@7|Q(3gDs&0HOZW~&h_!Zieh{-GMw$1ngcW25G zD~}7`8XPl=vNPq*$g=SD`i#5D`oU;m^Ix)m^}pUjx=IfJ0hOfQw?3H!rr^GQf7C*h zV1-i}SH#amjsIy0R>k=gtUkETg9%UE$^9wrxH(BZ2&h%eldb$*RagDG zY)f~S$={ws4s>W%0|45d7bU8?Z`5#2X9;E7<-I~~X{XcVjBs`IqHPmyF{fl#nCjj= z+~8`n#W)oaWesh8j5w%B@J+jAe}#PZ4h>o~0=-@D_P3W>u=k9;XdS{jlA3bBuPEvB zw5C$Fd|3AT_4Fd~Yrt>45Za0bQzdo9J?3dsTH<1g)YlMFS}L78{$rCN-)!TlZ@0tbf?uQ(mbpl$m}*jTvSTe{EYqW-#e> z?PcWvYCp|sIL9W#H+FuRkR0%j{|iQd@|!;Le=`JxEjr76x;VDcTCU`$RZ7yl^X;q8 z{9BLWQQDc!?I08Lz|UNr@Zt4Cx7rH8#n$#?oKa-Yjb|elCuk#%Qf$;O#B*c=%=`w7 zd^y`S+y&ouhR6HpvrQVQf0(D6h<+%(XjdB*0`(KYdH*R0Kft3xMFA$Fzds=|scSEb zXB~s${@X?*pGC|Nn5RYJbtGcw1KvE=zErAE2L|-JgOrvI(*=dlL^i4}tnv+Tc3tY8 z9^Z6kb9)%fKH{~0=iJ%Nc?vs$?CAZ=kUb@L(xkUu4^Mipc7;jrf0}La`R-hBd6nE8#l z&L16D{`}n4+m^|{e||vulg2{2Lx{TT-}pM_b;1b!&|QO3`vS+faV<(FlVN;HMWvqz zXa3CZkGmvR(S_*Gvyy;T;ZY^%|8~t|5cg~{C@imjZ?+zU zzmBn4)pxCY=v}3oR-U3HH^ro`M2+ZQ-TvBjE`|fS6KA>iseg?VS=hSS5y^JAel-d> zLAjwC73)HWf0n*{$PBRB?j~CtsFkfX6#*Wws4v{+tMM-ioCsP)ZafMe6jBHYnu+#p zEVKwX1bAwYo=Y}i4btaWC2>CA+#v73(J5-&a1sKnHE@ zCE&FQOX9;(Df^tA7NmnLrwQGIto@+`$Fp>2F=ss=8Us?E%nEV#8t~fUs=-Q+X$5V4 zh^;vZ3=>|U9`8vD+Tu3Nfmi|)1R8${aN)_^$JL_>H{nq?2Jwu}#uqi7e+;f*gf|cM_1>e{=1H32@EQ+uW&X#z%c(ktLmVRfy;JSw8sQPb;kRht#Ozuq zbphPj0TjRvo(7z+K0LGc!=Zydu#&Qi-u-sFUK9}V6i_%HERYYzAHVsE1lx)BPc(~* zayV^kg&caAUAol1g!{k|JX7LHp`ka^B)Z6*7)wN zKe!O_9(3MTe7op+M&27szlGtNgYCGSa$V^I;$2VA&94j45bNZjRoNeqQR&vjk@b@F^ zf23CyK<|$GI(`71CR{bb+H(C=ysb5O^Gz!Ft!R}sfha4Zs ztwY7jm|qt}iMLJi&a_X&1t0?#WCN0jNf#4!mWbj=ZLL7yDI3kNf6B(; z5t@DfgV%?q=uCRznqYHFh6f%K=l;7N9ej`_wPi2|z(-9~s-Q4H$vQ907m) zutwZyh<@%jDiRu9OeJ8VUSU)>gGDGSfehG*h++~2kYRU zcTRj^f;62M5+o*rO{MquBeuxZ@a3Cuc7(n&FC<4us?tBu&?L<=PgQ)Te@gIkglP=7 zbE^e0M?4Cr`$pMZyGdTb-VtYM*7H>?@0_Q2J>>D6?u3H79MOGp16wT-fw>O%eTG|K z1nIQ(?~|Uu9!~yi^8Z3inh;qk?}8Gg(inWg!Lg#$N0s8DiO7#^@7W8qf0XJ>;QpxW zA2z2^*L*5Q!I|@-sZ^$%e+5kh{?e@q4OOWSX&$q)wO4S{sp$OLkasyP@;cETPN}QHT#Dy zGE&`glGrGD0(QzWz-NGADO-agw`J}z&#*?&JAm^FIczOA*l<0QXB7L$ zXBl}yDQPY=3Wwts!etJ-Syo&2^6oSH-4Icm1nVfJeo7A4f##q!$yug4>rB2+E8>#g4YyCPT2A2$BOWLHSqi>cCGSgZXRuNn2&jM z7CBl|oEDXwN(b>$o4aBH;+L|;hyGW{Lar(m*U{^6@oM^he|IAHh4u=0b1@V5T%*sg z`Wt_HEDogJ_+&+*XxW7Q=qJJI#QVwSjVd3eBZ#T+$Ya0QDH0_Es*O~YI9{#gF+zw~ zNO|)|b~*!VJ=@(~)|47^E>}i?KrekFZ zNS=@DyCQj-Bf;2+1w+5YY1S@cq$fTMy!SV=d<@Xlw+h6lw+|@zl&J~fH5Di&F5hraC?6FP9V)7smo`J-NR(GvNV11 z!c2686bB4IzJ9NQpWR%rRh`$nc&Q$k83sVIlO&y?d8Cu9gj^FVv}nSZki~LA7l%~Z`2o`Yx=V_qfg7QZ5FW85~p9Yh^0nuZ=3$ar%qfI7Bss4 zdVe$WhcIN!&_}$z z?4RDV(#jgVuw~_e>oda!xOsuUxJ6xe=*|crFfMj{+pkO zOG=1Znvt+Fx_*5VV-9W|wbDwW(!?&cml&=Qp8cQn4+yEGLN;|o&)GWhlR`wAC+yUY z20>NY)(%}Pweakf%ju)?^{Johm-Z%fIzh6fmuU}QD!m2PP!B$pqf*gS6Z@N`S4NC_ zf9o%}|DCfoYN?YezO0R7JT(EHEq$sx_UT2l_1=QQfo+i?Q@g6` z30dY!MoF8`cCvN(1m7cs3d6FbMmtp>tt0Wq({x>z6)*faan~QFRY55jL;}qf6JYgL z@h|lC5=7oB>!rU@vM{|oi=gT>BBLCakd=Da%oZDC@f*g@uE?yiUMHlJa1YSFf76Y@ z?qNdj^}5ma8ijg*F0aFRg_h?e{Yu-)Q^lac^>={Icyq&N)9>jwXju=qn7bMV-EO?5 zzab=S2a@}0DsWr8AcDrbG%INDf!TKoK6sCVgcN&RKi);Tb5U3^I9AexYYn~7o;jnC zKRvPX)!rpxGcmQoouYG;%%u^Ne>EIpQ-57BJnok{CNNZ#w^0I*i;tc!_&d;E-luB5=`uQfAoG*QlfO? zmz0Y?W2I_YK)Dos35-6U@)#rNqlQ+<>aCY(3&z33BY$%x&Th7M)*Sjtf7_SNYHd21=H9@|joO>&M!;EhD{BQSIlLz5nv3jdZl; zwP{a6SQR-3E6&D*25knGf7d|T<;XbkLlr@6lpM+`EgSXEO(34knXVke*W(S!;jZ@& zSZ;{#af3r+&$xVDe*-2?T*k$le}$}Qw9n6PAagzZ5mI;FOtuVmBrMdv@2q22U;ZJV zui?>;$_#}Q1Ui$bFBC=GJ+P7?r+l3MTE%N6l`CIz?9&Ikor%G}#B0PPORhHE6|5cP z{U^e<^h3hk%m+S85_fNuH#bBHlM>m(j>klkyGagiyMGlgf64X<^I1xWSD<}!&*ep7 z&c3iO)}21bL0_7VhVhO@JBz6N9v&ubrHJU)l`e$%_^b;v{V9t>?@ndeGWNP@bFm@T zlSSbbop4i|zp_5GDk2GGm5_oj(@xrvh7`RXr4K6CVKPOhDg3GWq3~~Fnhz>ROML~V zQcJ#%mrmf=e+coV^Z)po1pU%@%1+yj{c?9$5zNW)AIaPOI9pEIri|dW_U5K@>z@@B zM|#bLhB{@Sz=pc|uI45M&rA#VyW_}flL8FigIjgl$@auNK~Ib_t)jtO_y@W1y0IOT znIyVxl`_m|Uy!%#e5kbbAXS6LiBs}QtIQ-a{#U70e=SoF!D6`iaXsr9;i5^EPUXSh zJ_zBWzWcpq%U`5VW;3G9eD<(Vk2$yGDCNFa!s}mn2#-Oe6n7_(dgkHQP$qJz1=>DU z4nc*S2&bvfNn_kT3n8THxq}f}dq-#~tcF}OC`$d9k0{`6&!x$Q7LC5PQ0ld|meAI=LISlCbyp1WAfL;*gIYCC<+wbGX!P z&+-`itmC}=ui6vedW#_XFo|uSW6a4#80LiHj}GP-L($}&IPywP(zT)NDBKyd%FnG? zS_KE?`?ILl((*NK$6v%D>~nzQ(1!yaruPPpf1-&FIqI8vbplm7wS&9q{IMgp&yv*b zsFGkNlKfxtNxlPEmy>2-VQ)R1Vtw<%KjgD-Eal&M{RLaF|3|;G+l+OCUbtKOxnskJ zmdm@i@Z-N!Xle`MExL~AdS1%2pcKsNx4ZLHsx@j02RQE;D?(+A6|_-ut}MR8`S;FR zf5YKm`iUkGtyxgQv+`(G)SOn(^hNr#dt6zWSoinwb7N!tCps5r_7bO$>&tHL#;_md z&LoSs~&nLQo4qMErrO?$&@~W|bpPYr^ zLM#l;-N=Gn$f*!$x^05=CIIa)SIugWfA%bPKt3pUu~5Ya(mFkCrKC9tOuU|zy`B}g zPi&6%o7k7ox|)cVcT)+h$faZ^&!mj}3r-qm+IM4aPGdEVxaVrKI%TWE2j05&jFkR6 zbHDI*6wDB?nC}3A<)n@zB<26HOoBiC%jOY;HN*&1ynH91Gfe(aEo%R3nfmJDf678l zP2|sbGs4vEZBEp4F*SD;_b0hU@5_*cabaOa+^OWz_*TzGAIMSt|4`JS{x|oyZggBt zb*S@e=;kJeQ@UgtRXYqR-JS8tL4&P-Np5LG8Gw|^@ z?Pj@tRY6ZCEL+y+K98ONIO(Jee~stjIgEtg={9@nf-sTU*B<;E7UkYBmK#bU??zXH zc><|gzkPbS8-FxfU{p$FO_&VuS z(SrlmdW;b>tb*db5EB7wQn=3VfuT86F^iOpA4L%2(f1O>~eeoh@G1(cUb$*B(p{OwfJtD zt9*!y~DxlGR@lrA2v~9&vFG61R^Su~j{`zP|bD zRMj}0XQ&0eyjYhIL@x3Lr@KA_!!HAw^Dh|d(Y8|QEhT?E^|bPR_hSAwDgHEDGRhVm zTGhOajfUn)|5)M*f8{%%QQ>-;tO(Yv)u>tGJVs;(j!*9Brs-^AUItvR0Iv)0K8UkS z+r0jzZNSbUROSdPY-CJ`7UIiWeExiH^@Hf)HNdgR@H%UEt>++R1}rb#2$ij+(rBp{ z=lL|nq5i{|!&VA^k*%qOOF812z2@xDbE5Efg&?DJ$sp`qfAfW>T>3G#wtdqqGZ)`; z0-DOCO7FDPmXw~icd-^-E3@4hdsvhTmV7x_4EE>#@}l~|_*L!1<`#J{F=eon)J~zv zA70`=;_ZKN|9DqMOJc4rw7XdRcP;)XIG-puDcIAn7|xf}ZMk-M>2$~PyGx9W1?FHjYoyS>r)5JTgg1j~W8emB6{Xt~~@{Nn+r zg4(t&%6yyjo7K4WoLZ1s*R$ot3tFUERh5=%HUdxlapmtl|5oNT;wv?$9yF&xt-N=h z4i!Es#3A-hIFoRsPpytfQ@y&mI^=aocY}lT1gp>u4 zH=#@jpl@c=@KoX&A47bP7d-DbFnAfty!p6J&#nhIx{t+;aGCTf^sbkZB7}-4oI56z z*i9q@e-9OA^ome3ghP}(t&c<$|9wH|Q(uPfa&(e-Ecl-{C0lXw2xh|R`*=6?PsM#{ zswa-Hzb+;d50F;-x0lcZL}c)Pr3th?)5y_6OWtIJ>6RJ*<=?yUR&W>>YKLV%Uwl}d zW~@Y|#x*ANBzLl=qrsY>mIZ@n9=}0{ecJgLe?#W~h%&G9hB{~8Wo~6<#VNZ?-+|?w zuogsne!u^zdv^hf&)JORWUacV1cW2cil*>xA;PT<$qi~scxun{XmUs zEpT0cPejOP1S>wrF8~8bh@zRe}Dsp-M&V2KC z3AHa{8p<@l#_8`G)n%d}MZ?h7nc!4YCI$u?ef&US@rltKI+RK`q< z9p_SxfbTh(8U~%^m`>~YXrl3Sf5X)a3h4yga@-0x2$mxQSBbTvvloXwGZ%FDPThx< zGT4fQS!>G!wNhYeeowF)@oU;iSBcl|S_Ey1Urc*WJPpLc6)Gf3MX|0Vwmv6{W9CTq(%GfoAH6}u^P0vM&R(Qb2Pgo{_f1o=c+LvEB zNcAiHQfH+AVE7mAatJv_3_3r$1g*xJY8@UL2vlBL1O;541*qQuz8!gVKVV*Xrd~nd zcTlL2vJ~%go*U$x4WH7f8k*58pL(km=kk?Jzk5w3lYt2D*cvn<2eXHBnApGKiML+$s!XUg2UuT3%y&91-jZTuy zPakjSq_3pWOgusCf8_Ae@%4*XKc4yY4%9wIGw|oIq0&(cNnj}Ol%TuUg6TdxB7f<0 z!rE1B4$!+unpD+y-fDxr+s=xT^xh?esWaZ^WdMh=nQ(7H7;2Qi+%!^0sw}U&b33sg z`1>YB>?Hd}R_sy|P}K73D1o661)dIDhsd%jhmekYj#|u$A>9 zMfMJvYYNTLe|X1yE6mD?DWyW)@{sfXf-@LZcy zXmxu>h*OBHW#HnDC&O+Mk2z|+wY-mO{B6tPe-CEX)wjO<7w)S$+>Fco48%YNF(88j zkRcPuFa~6}0W$EsVlaBe5c`Uu?G*zLFT)c71~mZ&KLG}@R}2oX7&2cmjJ+b;9RKNf(_5GI&2~d>Cnh+ ze{3=KmnQcAF9B%;sPbIC#gWiODiqR_Q1*u66S~}~5ydL9UQmKwoD7#dWNSTF#ytM#D;08XFrWzQTO%q?2H|O+7l}IBqJy z3|s@XhLV8>?%FlZc8522-=N_-EME~MQ$37^>jY;ae|Nz^ z^G~9@AEm@=UfOHsHOz1G`l!I{A6*Z*Vbp^f8N?LvM1J&6e*6&hRssKabGQ#N7kZGj zsAa1e^tNs3d!9)K^-l7~M#Sc)q(9&dlLi9Nk7khEgWZ6zPc`~cwx{hH;Y4bG%{_R- zmg>Uw@=|nBYs$>)T)Gbr6Joosf0+}F$cY~uj^3|X)o4NVmq13)h7;XFa`c>RApS3k zLQ}mO5GBN#X3PSc>M7e)t(P z8!8<(F4#7agtrmewBG< zI?-#LzTXyD{SY(pH5Me&Sl4R|DspTZRqA$RL@hy@Xg$lZU`R=&(9Ge0|CRoi*bF^H zijoTx?#B`1?PhYmNG4Ute{4HivXNZ2gD;$|*4x+H*C#vB*E`rJJKWbh(kDCC*E`-P zJK5Je_0PG8m?}E%^Ot6YQX?p1VhAWNYZ(rPcE>m_EjKSM3$83JQ3~L=O)U?Wn*O1D zQn(m^K>AU-m+Q_D-Q~MJn)0pK3GIc~N_pm3Nidm`lm`ur4qIh<5eo#62EuGE1e?r4TJHc&6 zuB&~bUGv0@2z35DY@EW{5&cQEEksD(!81fWG^Zzu`B2|ko-O5Icj#mrvhN)& zG_0d(^euzv-8%n*Kg$!eyGO5o<-WhJ*pr7MQYAeQ#unGjvWJ@s*NYyQ_oP8M83?Jo z2T__sYjsE#?_gd=!{L>k!4(?q;Y>d4=bUwd;`oMge@jo0-7X>y-|&r_NBffTcPSBVHP`ts@;_0MY4&K$w*C-ai@@}5dh&1XT61dY8*asqv;3w~(?fKs zI^T-|;r!`KyIyFOWNMwyf*Nn0Qq#t6v?g1JvZ^&aT7{|_Q>zo{+<^_$3n)Y~CDx$_ zS+XE{`wJgEQ!wG2a9lREehE_o@#>%{vIH#nfBOW1jFCQA7|FUN(gPSC6sv*Bek47; zJS&oZyD$=U8>0;%JSdg{PnIWLT%6@fSI&>P-x6uATX2c4E*4s@I&cWC6DgQ%K%O54 z=e|oA={gofeX#-!AkpPABggl4aM)MC-dM?RJ`ZG2lXm03P{G_B`Bjkx90X5mENTCIt(5v%R0ASX+%vn9eoL!{my@Hq(j ze*XAdN!QyR!!wzqXcKL>W-FE#E@1%%D6xL%eo~7N=F9is^V&ie=B{j zV`h$k(Vs2EA0h`YXNAjJBc&!O7`u73+x?efbA)t43Zp5lCiK9-=nKmqQ*~M)#!vgT zsUpmx^mdzY&O%Q&1=DIayt3lH(e1E?dlhM#xb}B7niZwJR;BY2H=!lqP44@2-iRA6 z_3qQSf2_AowzI7COnPg0=8@MYe;PoM_=ZZ2Bi|B)^#Q@5^pLw(i9eqWkJma^^?!Ow z<{hQ!*lbVi9(+tFeQ=H7%fH=O$Ab&Y zjJ%9fE10*py(>M$23ZCMpUPWAci`{p?fqOh<8J*$4O>rd1rykl_wJ+ee_6_tW52DH zk2KGr7V+4V0v0Y4{EGegv(G*7DsEQ3L8H0FRgsciW`4KFjK~XNDc7|fcy>-cmMJJ` zWhP~D44FGmS%M+7`QbXql@Pc*8kJzWJQ|T8xjY({@N{`JBmuKD8Z@)nEry+_KnA?Y zT(VuO`q!bQ!}pV04=3jVe_~iP5SAN_HM^GDcmwmPM&=qe=sw2gYd}%P_xHkc8)}OR zGqAUnJ;$Fd!z8TApLll!^(HexzWARQjHkXOwYjM#wpcio4>Hfn2BxZ~ww=%4M7p2- zR^B-UfvOJOqx7rEUe|=}8jh~bti4`lTCyjQvF$~0`Ha$TambDCmo`5roEW1o=T+$z&C=cUB{12EDv5lzU3&q)1Y+7Zxj3@vmZoy8<3_$S*5chqok$Jtz@ z9hlBu43Ey7JXkTO`o53*Y|Q!o1iwDqKaE$7gdE(b6bxJ6?p;`7;;6M8(=2S^4Qw@PxOkM+)8=;;5&6B@eSa$0C7jMOX zrLri=eXp9NG|A~zz9@ADoKJSbwNQP*b|Wopv=Y`TxnWw5HBRmj^>Z_gTji&%zzZFW z>i1Mt!8ffm;Vg`8kZmu0XGBC0|A%+4FM?@P)h{{00000 R2>=NIg#rKo>;wS-000xxW2*oF From 258285f0a25e9ea35366cac6dc82be05191e64fa Mon Sep 17 00:00:00 2001 From: Sampsa Pursiainen Date: Wed, 6 Dec 2023 12:28:45 +0200 Subject: [PATCH 7/7] Sampsa: Changes in NSE tool (Dynamic solver). --- m/zef_nse_interpolate.m | 39 ------ m/zef_nse_plot_sphere.m | 28 ----- m/zef_nse_tool_init.m | 235 ------------------------------------ m/zef_nse_tool_start.m | 13 -- m/zef_nse_tool_update.m | 79 ------------ m/zef_nse_tool_window.m | 258 ---------------------------------------- 6 files changed, 652 deletions(-) delete mode 100644 m/zef_nse_interpolate.m delete mode 100644 m/zef_nse_plot_sphere.m delete mode 100644 m/zef_nse_tool_init.m delete mode 100644 m/zef_nse_tool_start.m delete mode 100644 m/zef_nse_tool_update.m delete mode 100644 m/zef_nse_tool_window.m diff --git a/m/zef_nse_interpolate.m b/m/zef_nse_interpolate.m deleted file mode 100644 index 0c057fe8e..000000000 --- a/m/zef_nse_interpolate.m +++ /dev/null @@ -1,39 +0,0 @@ -function zef = zef_nse_interpolate(zef,type) - -if ismember(type,[1 2 3]) - - for i = 1 : length(zef.compartment_tags) - eval(['zef.' zef.compartment_tags{i} '_sources = 0;']) - end - - - for i = 1 : length(zef.nse_field.artery_domain_ind) - eval(['zef.' zef.compartment_tags{zef.nse_field.artery_domain_ind(i)} '_sources = 1;']) - end - - zef = zef_build_compartment_table(zef); - - zef.active_compartment_ind = find(ismember(zef.domain_labels,zef.nse_field.artery_domain_ind)); - zef.source_positions = zef.nodes(zef.nse_field.bp_vessel_node_ind,:); - -elseif ismember(type,4) - - for i = 1 : length(zef.compartment_tags) - eval(['zef.' zef.compartment_tags{i} '_sources = 0;']) - end - - - for i = 1 : length(zef.nse_field.capillary_domain_ind) - eval(['zef.' zef.compartment_tags{zef.nse_field.capillary_domain_ind(i)} '_sources = 1;']) - end - - zef = zef_build_compartment_table(zef); - - zef.active_compartment_ind = find(ismember(zef.domain_labels,zef.nse_field.capillary_domain_ind)); - zef.source_positions = zef.nodes(zef.nse_field.bf_capillary_node_ind,:); - -end - -zef = zef_source_interpolation(zef); - -end diff --git a/m/zef_nse_plot_sphere.m b/m/zef_nse_plot_sphere.m deleted file mode 100644 index 4f15df495..000000000 --- a/m/zef_nse_plot_sphere.m +++ /dev/null @@ -1,28 +0,0 @@ -function zef_nse_plot_sphere(h_axes,nse_field) - -axes(h_axes); -hold_val = ishold(h_axes); -if not(hold_val) - hold(h_axes,'on'); -end - -h_sphere = findobj(h_axes.Children,'Tag','nse_sphere'); -delete(h_sphere); - -[X,Y,Z] = sphere(100); - -for i = 1 : length(nse_field.sphere_radius) - h_surf = surf(nse_field.sphere_radius(i)*X + nse_field.sphere_x(i), nse_field.sphere_radius(i)*Y + nse_field.sphere_y(i), nse_field.sphere_radius(i)*Z + nse_field.sphere_z(i)); - - set(h_surf,'FaceColor',[0.5 0.5 0.5]); - set(h_surf,'EdgeColor','none'); - set(h_surf,'FaceAlpha',0.5); - set(h_surf,'Tag','nse_sphere'); - -end - -if not(hold_val) - hold(h_axes,'off'); -end - -end diff --git a/m/zef_nse_tool_init.m b/m/zef_nse_tool_init.m deleted file mode 100644 index 7e7fbd5a5..000000000 --- a/m/zef_nse_tool_init.m +++ /dev/null @@ -1,235 +0,0 @@ -function zef = zef_nse_tool_init(zef) - -if not(isfield(zef,'nse_field')) - zef.nse_field = struct; -end - -if not(isfield(zef,'inv_time_1')) - zef.nse_field.inv_time_1 = 0; -end - -if not(isfield(zef,'inv_time_2')) - zef.nse_field.inv_time_2 = 0; -end - -if not(isfield(zef,'inv_time_3')) - zef.nse_field.inv_time_3 = 0; -end - -if not(isfield(zef.nse_field,'viscosity_model')) - zef.nse_field.viscosity_model = 1; -end - -if not(isfield(zef.nse_field,'velocity_smoothing')) - zef.nse_field.velocity_smoothing = 0.15; -end - -if not(isfield(zef.nse_field,'viscosity_smoothing')) - zef.nse_field.viscosity_smoothing = 0.001; -end - -if not(isfield(zef.nse_field,'start_time')) - zef.nse_field.start_time = 0; -end - -if not(isfield(zef.nse_field,'time_integration')) - zef.nse_field.time_integration = 2; -end - -if not(isfield(zef.nse_field,'viscosity_exponent')) - zef.nse_field.viscosity_exponent = 0.6; -end - -if not(isfield(zef.nse_field,'viscosity_delta')) - zef.nse_field.viscosity_delta = 0.001; -end - -if not(isfield(zef.nse_field,'use_gpu')) - zef.nse_field.use_gpu = 1; -end - -if not(isfield(zef.nse_field,'n_frames')) - zef.nse_field.n_frames = 1; -end - - -if not(isfield(zef.nse_field,'gravity_amplitude')) - zef.nse_field.gravity_amplitude = -9.81; -end - -if not(isfield(zef.nse_field,'time_length')) - zef.nse_field.time_length = 1; -end - -if not(isfield(zef.nse_field,'time_step_length')) - zef.nse_field.time_step_length = 0.1; -end - -if not(isfield(zef.nse_field,'pulse_amplitude')) - zef.nse_field.pulse_amplitude = 50; -end - - -if not(isfield(zef.nse_field,'sphere_radius')) - zef.nse_field.sphere_radius = 30; -end - -if not(isfield(zef.nse_field,'sphere_x')) - zef.nse_field.sphere_x = 0; -end - -if not(isfield(zef.nse_field,'sphere_y')) - zef.nse_field.sphere_y = 0; -end - -if not(isfield(zef.nse_field,'sphere_z')) - zef.nse_field.sphere_z = 0; -end - -if not(isfield(zef.nse_field,'cycle_length')) - zef.nse_field.cycle_length = 1; -end - -if not(isfield(zef.nse_field,'p_wave_start')) - zef.nse_field.p_wave_start = 0.05; -end - -if not(isfield(zef.nse_field,'t_wave_start')) - zef.nse_field.t_wave_start = 0.2; -end - -if not(isfield(zef.nse_field,'d_wave_start')) - zef.nse_field.d_wave_start = 0.35; -end - -if not(isfield(zef.nse_field,'p_wave_length')) - zef.nse_field.p_wave_length = 0.5; -end - -if not(isfield(zef.nse_field,'t_wave_length')) - zef.nse_field.t_wave_length = 0.5; -end - -if not(isfield(zef.nse_field,'d_wave_length')) - zef.nse_field.d_wave_length = 0.5; -end - -if not(isfield(zef.nse_field,'p_wave_weight')) - zef.nse_field.p_wave_weight = 0.5; -end - -if not(isfield(zef.nse_field,'t_wave_weight')) - zef.nse_field.t_wave_weight = 0.2; -end - -if not(isfield(zef.nse_field,'d_wave_weight')) - zef.nse_field.d_wave_weight = 0.05; -end - - -if not(isfield(zef.nse_field,'arteriole_diameter')) - zef.nse_field.arteriole_diameter = 1e-5; -end - -if not(isfield(zef.nse_field,'capillary_diameter')) - zef.nse_field.capillary_diameter = 7e-6; -end - -if not(isfield(zef.nse_field,'venule_diameter')) - zef.nse_field.venule_diameter = 2e-5; -end - -if not(isfield(zef.nse_field,'pressure_decay_in_arterioles')) - zef.nse_field.pressure_decay_in_arterioles = 0.70; -end - -if not(isfield(zef.nse_field,'max_reconstruction_quantile')) - zef.nse_field.max_reconstruction_quantile = 1; -end - -if not(isfield(zef.nse_field,'min_reconstruction_quantile')) - zef.nse_field.min_reconstruction_quantile = 0; -end - -if not(isfield(zef.nse_field,'blood_conductivity')) - zef.nse_field.blood_conductivity = 1.59; -end - -if not(isfield(zef.nse_field,'viscosity_relaxation_time')) - zef.nse_field.viscosity_relaxation_time = 1.902; -end - -if not(isfield(zef.nse_field,'viscosity_transition')) - zef.nse_field.viscosity_transition = 1.25; -end - -if not(isfield(zef.nse_field,'artery_diameter_change')) - zef.nse_field.artery_diameter_change = 0.1; -end - -if not(isfield(zef.nse_field,'capillary_arteriole_total_area_ratio')) - zef.nse_field.capillary_arteriole_total_area_ratio = 2; -end - -if not(isfield(zef.nse_field,'total_flow')) - zef.nse_field.total_flow = 1; -end - -if not(isfield(zef.nse_field,'conductivity_model')) - zef.nse_field.conductivity_model = 1; -end - -if not(isfield(zef.nse_field,'conductivity_exponent')) - zef.nse_field.conductivity_exponent = 2; -end - -if not(isfield(zef.nse_field,'pressure')) - zef.nse_field.pressure = 110; -end - -if not(isfield(zef.nse_field,'rho')) - zef.nse_field.rho = 1043; -end - -if not(isfield(zef.nse_field,'capillary_domain_ind')) - zef.nse_field.capillary_domain_ind = 1; -end - -if not(isfield(zef.nse_field,'artery_domain_ind')) - zef.nse_field.artery_domain_ind = 1; -end - -if not(isfield(zef.nse_field,'mu')) - zef.nse_field.mu = 3E-3; -end - -if not(isfield(zef.nse_field,'pcg_tol')) - zef.nse_field.pcg_tol = 1e-05; -end - -if not(isfield(zef.nse_field,'pcg_maxit')) - zef.nse_field.pcg_maxit = 10000; -end - -if not(isfield(zef.nse_field,'reconstruction_type')) - zef.nse_field.reconstruction_type = 1; -end - -if not(isfield(zef.nse_field,'solver_type')) - zef.nse_field.solver_type = 1; -end - -if not(isfield(zef.nse_field,'gravity_x')) - zef.nse_field.gravity_x = 0; -end - -if not(isfield(zef.nse_field,'gravity_y')) - zef.nse_field.gravity_y = 0; -end - -if not(isfield(zef.nse_field,'gravity_z')) - zef.nse_field.gravity_z = 9.81; -end - - -end diff --git a/m/zef_nse_tool_start.m b/m/zef_nse_tool_start.m deleted file mode 100644 index 6986d0166..000000000 --- a/m/zef_nse_tool_start.m +++ /dev/null @@ -1,13 +0,0 @@ -function zef = zef_nse_tool_start(zef) - -if nargin == 0 - zef = evalin('base','zef'); -end - -zef = zef_tool_start(zef,'zef_nse_tool_window',2/3,1); - -if nargout == 0 - assignin('base','zef',zef) -end - -end diff --git a/m/zef_nse_tool_update.m b/m/zef_nse_tool_update.m deleted file mode 100644 index b8269db4b..000000000 --- a/m/zef_nse_tool_update.m +++ /dev/null @@ -1,79 +0,0 @@ -function zef = zef_nse_tool_update(zef) - -zef.nse_field.use_gpu = zef.nse_field.h_use_gpu.Value; -zef.nse_field.pcg_tol = zef.nse_field.h_pcg_tol.Value; -zef.nse_field.pcg_maxit = zef.nse_field.h_pcg_maxit.Value; -zef.nse_field.rho = zef.nse_field.h_rho.Value; -zef.nse_field.mu = zef.nse_field.h_mu.Value; - -zef.nse_field.viscosity_model = zef.nse_field.h_viscosity_model.Value; -zef.nse_field.viscosity_exponent = zef.nse_field.h_viscosity_exponent.Value; -zef.nse_field.viscosity_delta = zef.nse_field.h_viscosity_delta.Value; - -zef.nse_field.pressure_decay_in_arterioles = zef.nse_field.h_pressure_decay_in_arterioles.Value; - -zef.nse_field.velocity_smoothing = zef.nse_field.h_velocity_smoothing.Value; - -zef.nse_field.viscosity_smoothing = zef.nse_field.h_viscosity_smoothing.Value; - -zef.nse_field.time_integration = zef.nse_field.h_time_integration.Value; - -zef.nse_field.capillary_diameter = zef.nse_field.h_capillary_diameter.Value; - -zef.nse_field.pressure = zef.nse_field.h_pressure.Value; - -zef.nse_field.start_time = zef.nse_field.h_start_time.Value; - -zef.nse_field.blood_conductivity = zef.nse_field.h_blood_conductivity.Value; - -zef.nse_field.gravity_x = zef.nse_field.h_gravity_x.Value; -zef.nse_field.gravity_y = zef.nse_field.h_gravity_y.Value; -zef.nse_field.gravity_z = zef.nse_field.h_gravity_z.Value; - -zef.nse_field.conductivity_model = zef.nse_field.h_conductivity_model.Value; -zef.nse_field.conductivity_exponent = zef.nse_field.h_conductivity_exponent.Value; - -zef.nse_field.arteriole_diameter = zef.nse_field.h_arteriole_diameter.Value; -zef.nse_field.venule_diameter = zef.nse_field.h_venule_diameter.Value; - -zef.nse_field.total_flow = zef.nse_field.h_total_flow.Value; -zef.nse_field.capillary_arteriole_total_area_ratio = zef.nse_field.h_capillary_arteriole_total_area_ratio.Value; - -zef.nse_field.capillary_domain_ind = zef.nse_field.h_capillary_domain_ind.Value; -zef.nse_field.artery_domain_ind = zef.nse_field.h_artery_domain_ind.Value; - -zef.nse_field.viscosity_relaxation_time = zef.nse_field.h_viscosity_relaxation_time.Value; -zef.nse_field.viscosity_transition = zef.nse_field.h_viscosity_transition.Value; - -zef.nse_field.reconstruction_type = zef.nse_field.h_reconstruction_type.Value; -zef.nse_field.solver_type = zef.nse_field.h_solver_type.Value; - -zef.nse_field.max_reconstruction_quantile = zef.nse_field.h_max_reconstruction_quantile.Value; -zef.nse_field.min_reconstruction_quantile = zef.nse_field.h_min_reconstruction_quantile.Value; - -zef.nse_field.artery_diameter_change = zef.nse_field.h_artery_diameter_change.Value; - -zef.nse_field.gravity_amplitude = zef.nse_field.h_gravity_amplitude.Value; -zef.nse_field.time_length = zef.nse_field.h_time_length.Value; -zef.nse_field.time_step_length = zef.nse_field.h_time_step_length.Value; -zef.nse_field.pulse_amplitude = zef.nse_field.h_pulse_amplitude.Value; -zef.nse_field.cycle_length = zef.nse_field.h_cycle_length.Value; -zef.nse_field.p_wave_start = zef.nse_field.h_p_wave_start.Value; -zef.nse_field.t_wave_start = zef.nse_field.h_t_wave_start.Value; -zef.nse_field.d_wave_start = zef.nse_field.h_d_wave_start.Value; -zef.nse_field.p_wave_length = zef.nse_field.h_p_wave_length.Value ; -zef.nse_field.t_wave_length = zef.nse_field.h_t_wave_length.Value; -zef.nse_field.d_wave_length = zef.nse_field.h_d_wave_length.Value; -zef.nse_field.p_wave_weight = zef.nse_field.h_p_wave_weight.Value; -zef.nse_field.t_wave_weight = zef.nse_field.h_t_wave_weight.Value; -zef.nse_field.d_wave_weight = zef.nse_field.h_d_wave_weight.Value; - -zef.nse_field.sphere_radius = str2num(zef.nse_field.h_sphere_radius.Value); -zef.nse_field.sphere_x = str2num(zef.nse_field.h_sphere_x.Value); -zef.nse_field.sphere_y = str2num(zef.nse_field.h_sphere_y.Value); -zef.nse_field.sphere_z = str2num(zef.nse_field.h_sphere_z.Value); - -zef.nse_field.n_frames = zef.nse_field.h_n_frames.Value; - -end - diff --git a/m/zef_nse_tool_window.m b/m/zef_nse_tool_window.m deleted file mode 100644 index 668b3453f..000000000 --- a/m/zef_nse_tool_window.m +++ /dev/null @@ -1,258 +0,0 @@ -function zef = zef_nse_tool_window(zef) - -zef_data = zef_nse_app; - -zef = zef_nse_tool_init(zef); - -zef.nse_field.h_plot_sphere = zef_data.h_plot_sphere; -zef.nse_field.h_plot_pulse = zef_data.h_plot_pulse; - -zef.nse_field.h_nse_tool = zef_data.h_nse_tool; -zef.nse_field.h_nse_tool.Name = 'ZEFFIRO Interface: NSE tool'; -zef.nse_field.h_solve_system = zef_data.h_solve_system; -zef.nse_field.h_parse_reconstruction = zef_data.h_parse_reconstruction; -zef.nse_field.h_nse_sigma = zef_data.h_nse_sigma; -zef.nse_field.h_interpolate = zef_data.h_interpolate; -zef.nse_field.h_use_gpu = zef_data.h_use_gpu; -zef.nse_field.h_use_gpu.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_pcg_tol = zef_data.h_pcg_tol; -zef.nse_field.h_pcg_tol.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_pcg_maxit = zef_data.h_pcg_maxit; -zef.nse_field.h_pcg_maxit.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_gravity_x = zef_data.h_gravity_x; -zef.nse_field.h_gravity_x.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_gravity_y = zef_data.h_gravity_y; -zef.nse_field.h_gravity_y.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_gravity_z = zef_data.h_gravity_z; -zef.nse_field.h_gravity_z.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_total_flow = zef_data.h_total_flow; -zef.nse_field.h_total_flow.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_total_flow = zef_data.h_total_flow; -zef.nse_field.h_total_flow.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_start_time = zef_data.h_start_time; -zef.nse_field.h_start_time.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_velocity_smoothing = zef_data.h_velocity_smoothing; -zef.nse_field.h_velocity_smoothing.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_n_frames = zef_data.h_n_frames; -zef.nse_field.h_n_frames.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_sphere_radius = zef_data.h_sphere_radius; -zef.nse_field.h_sphere_radius.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_sphere_x = zef_data.h_sphere_x; -zef.nse_field.h_sphere_x.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_sphere_y = zef_data.h_sphere_y; -zef.nse_field.h_sphere_y.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_sphere_z = zef_data.h_sphere_z; -zef.nse_field.h_sphere_z.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_gravity_amplitude = zef_data.h_gravity_amplitude; -zef.nse_field.h_gravity_amplitude.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_time_length = zef_data.h_time_length; -zef.nse_field.h_time_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_time_step_length = zef_data.h_time_step_length; -zef.nse_field.h_time_step_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_pulse_amplitude = zef_data.h_pulse_amplitude; -zef.nse_field.h_pulse_amplitude.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_cycle_length = zef_data.h_cycle_length; -zef.nse_field.h_cycle_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_p_wave_start = zef_data.h_p_wave_start; -zef.nse_field.h_p_wave_start.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_t_wave_start = zef_data.h_t_wave_start; -zef.nse_field.h_t_wave_start.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_d_wave_start = zef_data.h_d_wave_start; -zef.nse_field.h_d_wave_start.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_p_wave_length = zef_data.h_p_wave_length; -zef.nse_field.h_p_wave_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_t_wave_length = zef_data.h_t_wave_length; -zef.nse_field.h_t_wave_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_d_wave_length = zef_data.h_d_wave_length; -zef.nse_field.h_d_wave_length.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_p_wave_weight = zef_data.h_p_wave_weight; -zef.nse_field.h_p_wave_weight.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_t_wave_weight = zef_data.h_t_wave_weight; -zef.nse_field.h_t_wave_weight.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_d_wave_weight = zef_data.h_d_wave_weight; -zef.nse_field.h_d_wave_weight.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_conductivity_model = zef_data.h_conductivity_model; -zef.nse_field.h_conductivity_model.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_conductivity_exponent = zef_data.h_conductivity_exponent; -zef.nse_field.h_conductivity_exponent.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; -zef.nse_field.h_pressure_decay_in_arterioles = zef_data.h_pressure_decay_in_arterioles; -zef.nse_field.h_pressure_decay_in_arterioles.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_capillary_diameter = zef_data.h_capillary_diameter; -zef.nse_field.h_capillary_diameter.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_capillary_arteriole_total_area_ratio= zef_data.h_capillary_arteriole_total_area_ratio; -zef.nse_field.h_capillary_arteriole_total_area_ratio.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_pressure = zef_data.h_pressure; -zef.nse_field.h_pressure.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_rho = zef_data.h_rho; -zef.nse_field.h_rho.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_relaxation_time = zef_data.h_viscosity_relaxation_time; -zef.nse_field.h_viscosity_relaxation_time.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_smoothing = zef_data.h_viscosity_smoothing; -zef.nse_field.h_viscosity_smoothing.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_transition = zef_data.h_viscosity_transition; -zef.nse_field.h_viscosity_transition.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_arteriole_diameter = zef_data.h_arteriole_diameter; -zef.nse_field.h_arteriole_diameter.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_artery_diameter_change = zef_data.h_artery_diameter_change; -zef.nse_field.h_artery_diameter_change.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_venule_diameter = zef_data.h_venule_diameter; -zef.nse_field.h_venule_diameter.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_mu = zef_data.h_mu; -zef.nse_field.h_mu.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_artery_domain_ind = zef_data.h_artery_domain_ind; -zef.nse_field.h_artery_domain_ind.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_capillary_domain_ind = zef_data.h_capillary_domain_ind; -zef.nse_field.h_capillary_domain_ind.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_reconstruction_type = zef_data.h_reconstruction_type; -zef.nse_field.h_reconstruction_type.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_model = zef_data.h_viscosity_model; -zef.nse_field.h_viscosity_model.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_exponent = zef_data.h_viscosity_exponent; -zef.nse_field.h_viscosity_exponent.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_max_reconstruction_quantile = zef_data.h_max_reconstruction_quantile; -zef.nse_field.h_max_reconstruction_quantile.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_min_reconstruction_quantile = zef_data.h_min_reconstruction_quantile; -zef.nse_field.h_min_reconstruction_quantile.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_viscosity_delta = zef_data.h_viscosity_delta; -zef.nse_field.h_viscosity_delta.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_blood_conductivity = zef_data.h_blood_conductivity; -zef.nse_field.h_blood_conductivity.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_solver_type = zef_data.h_solver_type; -zef.nse_field.h_solver_type.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_time_integration = zef_data.h_time_integration; -zef.nse_field.h_time_integration.ValueChangedFcn = 'zef = zef_nse_tool_update(zef);'; - -zef.nse_field.h_use_gpu.Value = zef.nse_field.use_gpu; - -zef.nse_field.h_pcg_tol.Value = zef.nse_field.pcg_tol; -zef.nse_field.h_pcg_maxit.Value = zef.nse_field.pcg_maxit; - -zef.nse_field.h_capillary_arteriole_total_area_ratio.Value = zef.nse_field.capillary_arteriole_total_area_ratio; -zef.nse_field.h_total_flow.Value = zef.nse_field.total_flow; - -zef.nse_field.h_rho.Value = zef.nse_field.rho; -zef.nse_field.h_mu.Value = zef.nse_field.mu; -zef.nse_field.h_start_time.Value = zef.nse_field.start_time; - -zef.nse_field.h_arteriole_diameter.Value = zef.nse_field.arteriole_diameter; -zef.nse_field.h_venule_diameter.Value = zef.nse_field.venule_diameter; - -zef.nse_field.h_max_reconstruction_quantile.Value = zef.nse_field.max_reconstruction_quantile; -zef.nse_field.h_min_reconstruction_quantile.Value = zef.nse_field.min_reconstruction_quantile; - -zef.nse_field.h_artery_diameter_change.Value = zef.nse_field.artery_diameter_change; - -zef.nse_field.h_gravity_x.Value = zef.nse_field.gravity_x; -zef.nse_field.h_gravity_y.Value = zef.nse_field.gravity_y; -zef.nse_field.h_gravity_z.Value = zef.nse_field.gravity_z; - -zef.nse_field.h_sphere_radius.Value = num2str(zef.nse_field.sphere_radius); -zef.nse_field.h_sphere_x.Value = num2str(zef.nse_field.sphere_x); -zef.nse_field.h_sphere_y.Value = num2str(zef.nse_field.sphere_y); -zef.nse_field.h_sphere_z.Value = num2str(zef.nse_field.sphere_z); - -zef.nse_field.h_viscosity_smoothing.Value = zef.nse_field.viscosity_smoothing; - -zef.nse_field.h_gravity_amplitude.Value = zef.nse_field.gravity_amplitude; -zef.nse_field.h_time_length.Value = zef.nse_field.time_length; -zef.nse_field.h_time_step_length.Value = zef.nse_field.time_step_length; -zef.nse_field.h_pulse_amplitude.Value = zef.nse_field.pulse_amplitude; -zef.nse_field.h_cycle_length.Value = zef.nse_field.cycle_length; -zef.nse_field.h_p_wave_start.Value = zef.nse_field.p_wave_start; -zef.nse_field.h_t_wave_start.Value = zef.nse_field.t_wave_start; -zef.nse_field.h_d_wave_start.Value = zef.nse_field.d_wave_start; -zef.nse_field.h_p_wave_length.Value = zef.nse_field.p_wave_length; -zef.nse_field.h_t_wave_length.Value = zef.nse_field.t_wave_length; -zef.nse_field.h_d_wave_length.Value = zef.nse_field.d_wave_length; -zef.nse_field.h_p_wave_weight.Value = zef.nse_field.p_wave_weight; -zef.nse_field.h_t_wave_weight.Value = zef.nse_field.t_wave_weight; -zef.nse_field.h_d_wave_weight.Value = zef.nse_field.d_wave_weight; - -zef.nse_field.h_n_frames.Value = zef.nse_field.n_frames; - -zef.nse_field.h_viscosity_relaxation_time.Value = zef.nse_field.viscosity_relaxation_time; -zef.nse_field.h_viscosity_transition.Value = zef.nse_field.viscosity_transition; - -zef.nse_field.h_viscosity_exponent.Value = zef.nse_field.viscosity_exponent; -zef.nse_field.h_viscosity_delta.Value = zef.nse_field.viscosity_delta; - -zef.nse_field.h_velocity_smoothing.Value = zef.nse_field.velocity_smoothing; - -zef.nse_field.h_blood_conductivity.Value = zef.nse_field.blood_conductivity; -zef.nse_field.h_conductivity_exponent.Value = zef.nse_field.conductivity_exponent; -zef.nse_field.h_pressure_decay_in_arterioles.Value = zef.nse_field.pressure_decay_in_arterioles; -zef.nse_field.h_capillary_diameter.Value = zef.nse_field.capillary_diameter; -zef.nse_field.h_pressure.Value = zef.nse_field.pressure; - -zef.nse_field.h_viscosity_model.Items = {'Constant','Power law','Carreau-Yasuda'}; -zef.nse_field.h_viscosity_model.ItemsData = [1 : length(zef.nse_field.h_viscosity_model.Items)]; -zef.nse_field.h_viscosity_model.Value = zef.nse_field.viscosity_model; - -zef.nse_field.h_conductivity_model.Items = {'Archie''s law','Hashin-Shtrikman upper bound','Hashin-Shtrikman lower bound'}; -zef.nse_field.h_conductivity_model.ItemsData = [1 : length(zef.nse_field.h_conductivity_model.Items)]; -zef.nse_field.h_conductivity_model.Value = zef.nse_field.conductivity_model; - -zef.nse_field.h_reconstruction_type.Items = {'Pressure (Arteries)','Velocity (Arteries)','Viscosity (Arteries)','Concentration (Microcirculation)'}; -zef.nse_field.h_reconstruction_type.ItemsData = [1 : length(zef.nse_field.h_reconstruction_type.Items)]; -zef.nse_field.h_reconstruction_type.Value = zef.nse_field.reconstruction_type; - -zef.nse_field.h_solver_type.Items = {'Poisson','Poisson & microcirculation','Dynamic Stokes','Dynamic Stokes & microcirculation', 'Dynamic Navier-Stokes','Dynamic Navier-Stokes & microcirculation'}; -zef.nse_field.h_solver_type.ItemsData = [1 : length(zef.nse_field.h_solver_type.Items)]; -zef.nse_field.h_solver_type.Value = zef.nse_field.solver_type; - -zef.nse_field.h_time_integration.Items = {'Euler','Trapezoid','Runge-Kutta'}; -zef.nse_field.h_time_integration.ItemsData = [1 : length(zef.nse_field.h_time_integration.Items)]; -zef.nse_field.h_time_integration.Value = zef.nse_field.time_integration; - -zef.nse_field.h_solve_system.ButtonPushedFcn = 'zef_nse_run_solver'; -zef.nse_field.h_parse_reconstruction.ButtonPushedFcn = 'zef.inv_time_1 = zef.nse_field.inv_time_1; zef.inv_time_2 = zef.nse_field.inv_time_2; zef.inv_time_3 = zef.nse_field.inv_time_3; [zef.reconstruction, zef.reconstruction_information] = zef_nse_reconstruction(zef.nse_field,zef.nse_field.h_reconstruction_type.Value);'; -zef.nse_field.h_interpolate.ButtonPushedFcn = 'zef = zef_nse_interpolate(zef,zef.nse_field.h_reconstruction_type.Value);'; -zef.nse_field.h_nse_sigma.ButtonPushedFcn = 'zef.nse_sigma = zef_nse_sigma(zef.nse_field,zef.nodes,zef.tetra,zef.domain_labels,zef.sigma,zef.source_interpolation_ind);'; -zef.nse_field.h_plot_sphere.ButtonPushedFcn = 'zef_nse_plot_sphere(zef.h_axes1, zef.nse_field);'; -zef.nse_field.h_plot_pulse.ButtonPushedFcn = ''; - -zef.nse_field.h_artery_domain_ind.Items = cell(0); -for i = 1 : length(zef.compartment_tags) - zef.nse_field.h_artery_domain_ind.Items{i} = eval(['zef.' zef.compartment_tags{i} '_name']); -end -zef.nse_field.h_artery_domain_ind.ItemsData = [1:length(zef.nse_field.h_artery_domain_ind.Items)]; -zef.nse_field.h_artery_domain_ind.Multiselect = 'on'; -zef.nse_field.h_artery_domain_ind.Value = zef.nse_field.artery_domain_ind; - -zef.nse_field.h_capillary_domain_ind.Items = cell(0); -for i = 1 : length(zef.compartment_tags) - zef.nse_field.h_capillary_domain_ind.Items{i} = eval(['zef.' zef.compartment_tags{i} '_name']); -end -zef.nse_field.h_capillary_domain_ind.ItemsData = [1:length(zef.nse_field.h_capillary_domain_ind.Items)]; -zef.nse_field.h_capillary_domain_ind.Multiselect = 'on'; -zef.nse_field.h_capillary_domain_ind.Value = zef.nse_field.capillary_domain_ind; - -end