function proj2d = compute_one_projection_method_2(xs,ys,zs,data3d,psrc,pcdet,su,sv,nu,nv)
%
%	proj2d = compute_one_projection_method_2(xs,ys,zs,data3d,psrc,pcdet,su,sv,nu,nv)
%
%	Method 2: compute the project based on the stack of planes perpendicular to the src-detector line
%	This method should be faster than the line-integral method
%
%   Deshan Yang, PhD
%	Department of radiation oncology
%	Washington University in Saint Louis
%   01/16/2011, Saint Louis, MO, USA
%

corner_points = [...
	xs(1) ys(1) zs(1);...
	xs(1) ys(1) zs(end);...
	xs(1) ys(end) zs(1);...
	xs(1) ys(end) zs(end);...
	xs(end) ys(1) zs(1);...
	xs(end) ys(1) zs(end);...
	xs(end) ys(end) zs(1);...
	xs(end) ys(end) zs(end)...
	];

corner_points_t = zeros(8,1);
for k =1:8
	p = corner_points(k,:);
	[q,corner_points_t(k)] = project_1_point_to_a_line(psrc,pcdet,p);
end

t_min = min(corner_points_t);
t_max = max(corner_points_t);

dist = norm(psrc-pcdet);

N = ceil(dist*(t_max-t_min));	% N planes
dt = (t_max-t_min)/N;
ts = t_min:dt:t_max;

proj2d = zeros(nv,nu,'single');
vecu = [0 0 1];

vecn = psrc-pcdet;
vecv = cross(vecn,vecu);
vecv = vecv/norm(vecv);

us = ((-nu/2+0.5):1:(nu/2-0.5))*su/nu;
vs = ((-nv/2+0.5):1:(nv/2-0.5))*sv/nv;
[uu,vv] = meshgrid(us,vs);

for T = 1:N
	vecu_t = vecu*ts(T);
	vecv_t = vecv*ts(T);
	pcdet_t = psrc+ts(T)*(pcdet-psrc);

	vdet_t_xs = pcdet_t(1) + vecu_t(1)*uu + vecv_t(1)*vv;
	vdet_t_ys = pcdet_t(2) + vecu_t(2)*uu + vecv_t(2)*vv;
	vdet_t_zs = pcdet_t(3) + vecu_t(3)*uu + vecv_t(3)*vv;

	proj2d = proj2d + interp3(xs,ys,zs,data3d,vdet_t_xs,vdet_t_ys,vdet_t_zs,'linear',0)*dt*dist;
end

% adjust the value according to the projection path length
vdet_t_xs = pcdet(1) + vecu(1)*uu + vecv(1)*vv;
vdet_t_ys = pcdet(2) + vecu(2)*uu + vecv(2)*vv;
vdet_t_zs = pcdet(3) + vecu(3)*uu + vecv(3)*vv;

dists = sqrt((vdet_t_xs-psrc(1)).^2+(vdet_t_ys-psrc(2)).^2+(vdet_t_zs-psrc(3)).^2);
dists = dists / min(dists(:));
proj2d = proj2d .* dists;


function deg = rad2deg(rad)

% RAD2DEG  Radians to degrees conversion.

%   Copyright 2008-2009 Joan Sola @ LAAS-CNRS.

deg = rad/pi*180;

% ========== End of function - Start GPL license ==========

%   # START GPL LICENSE

%---------------------------------------------------------------------
%
%   This file is part of SLAMTB, a SLAM toolbox for Matlab.
%
%   SLAMTB is free software: you can redistribute it and/or modify
%   it under the terms of the GNU General Public License as published by
%   the Free Software Foundation, either version 3 of the License, or
%   (at your option) any later version.
%
%   SLAMTB is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU General Public License for more details.
%
%   You should have received a copy of the GNU General Public License
%   along with SLAMTB.  If not, see <http://www.gnu.org/licenses/>.
%
%---------------------------------------------------------------------

%   SLAMTB is Copyright:
%   Copyright (c) 2008-2010, Joan Sola @ LAAS-CNRS,
%   Copyright (c) 2010-2013, Joan Sola,
%   Copyright (c) 2014-2015, Joan Sola @ IRI-UPC-CSIC,
%   SLAMTB is Copyright 2009
%   by Joan Sola, Teresa Vidal-Calleja, David Marquez and Jean Marie Codol
%   @ LAAS-CNRS.
%   See on top of this file for its particular copyright.

%   # END GPL LICENSE


 function pgd_step_test
%function pgd_step_test
% test the PGD algorithm using 2D LS cost function

% cost function terms
kap = 4;
A = [1 0; 0 sqrt(kap)];
W = eye(2);
M = eye(2);
yy = 0;

f.niter = 10;
x = [-kap; 1];

% run PSD
xpsd = qpwls_psd(x, A, W, yy, 0, 'precon', 1, 'niter', f.niter, 'isave', 'all');

% run PGD
data = {yy, A, W};
f.step = 3.3; % best step is 0.4, so illustrate suboptimal step
[xpgd1 steps] = pgd_step(x, data, @costgrad, 'precon', M, ...
		'step_method', 'user', 'step', f.step, ...
		'niter', f.niter, 'isave', 'all', 'chat', 0);

%pr steps
[xpgd2 steps] = pgd_step(x, data, @costgrad, 'precon', M, ...
		'step_method', 'der2', ...
		'niter', f.niter, 'isave', 'all', 'chat', 0);
%pr steps

if im
	clf, subplot(211)
	plot(	xpsd(1,:), xpsd(2,:), 'y-o', ...
		xpgd1(1,:), xpgd1(2,:), 'b--+', ...
		xpgd2(1,:), xpgd2(2,:), 'm:.')
	xlabel x1, ylabel x2
	title 'QPWLS example'
	leg = {'PSD', sprintf('PGD:%g', f.step), 'PGD:Newton'};
	legend(leg{:}, 3)
end

% cost function map
if ~isvar('qq')
	x1 = linspace(-4.5,0.5,41)';
	x2 = linspace(-1,1.5,43)';
	[xx1 xx2] = ndgrid(x1,x2);
	qq = 0 * xx1;
	for i1=1:length(x1)
		for i2=1:length(x2)
			x = [x1(i1) x2(i2)]';
			qq(i1,i2) = norm(sqrtm(W) * (yy - A * x)).^2;
		end
	end
end

if im
	hold on
	contour(x1, x2, qq', 8)
	plot(0,0, 'rx')
	hold off
	axis equal
	axis([-4.5 0.5 -1 1.5])
	xtick(-4:0)
	ytick(-1:1)
	colormap(0.3+0.7*gray)
end

if im
	subplot(212)
	plot(	0:f.niter, sum(abs(xpsd), 1), 'y-o', ...
		0:f.niter, sum(abs(xpgd1)), 'b--x', ...
		0:f.niter, sum(abs(xpgd2)), 'm:.')
	xlabel 'iteration', ylabel '||x||_1'
	legend(leg{:}, 1)
end

% cost function and gradient for basic WLS
function [cost, grad] = costgrad(x, data)
y = data{1};
A = data{2};
W = data{3};

p = A * x;
cost = 0.5 * norm(sqrtm(W) * (y - p)).^2;
if nargout > 1
	grad = -A' * (W * (y - p));
end


function mean = f_mean ( m, n )

%*****************************************************************************80
%
%% F_MEAN returns the mean of the F central PDF.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    10 September 2004
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer M, N, the parameters of the PDF.
%    1 <= M,
%    1 <= N.
%    Note, however, that the mean is not defined unless 3 <= N.
%
%    Output, real MEAN, the mean of the PDF.
%
  if ( n < 3 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'F_MEAN - Fatal error!\n' );
    fprintf ( 1, '  The mean is not defined for N < 3.\n' );
    error ( 'F_MEAN - Fatal error!' );
  end

  mean = n / ( n - 2 );

  return
end


% Written by Ali A. Eftekhari
% Last checked: June 2021
clc % clean the command prompt
L = 0.1; % 10 cm length
W = 0.01; % 1 cm thickness
Nx = 50; % number of cell in x direction
Ny = 20; % number of cells in the y direction
m = createMesh2D(Nx, Ny, L, W); % creates a 2D Cartesian grid
% m = createMesh3D(Nx, Ny,Ny, L, W,W); % creates a 3D Cartesian grid, activate this line if you are curious
T_inf = 25+273.15; % [K] ambient temperature
T_base = 100+273.15; % [K] temperature at the base of the fin
k_val = 237; % W/(m.K) thermal conductivity
h_val = 10; % W/(m^2.K) heat transfer coefficient
k = createCellVariable(m, k_val); % assign thermal cond. value to all cells
k_face = geometricMean(k); % geometric average of the thermal conductivity values on the cell faces
BC = createBC(m); % creates a BC structure for the domain m; all Neumann boundaries
BC.left.a(:)=0; BC.left.b(:)=1; BC.left.c(:)=T_base; % convert the left boundary to constant temperature
BC.right.a(:)=k_val/h_val; BC.right.b(:)=1; BC.right.c(:)=T_inf; % right boundary to Robin
BC.top.a(:)=k_val/h_val; BC.top.b(:)=1; BC.top.c(:)=T_inf; % top boundary to Robin
BC.bottom.a(:)=-k_val/h_val; BC.bottom.b(:)=1; BC.bottom.c(:)=T_inf; % bottom boundary to Robin (don't forget the normal vector sign)
M_cond = diffusionTerm(k_face); % matrix of coefficients for the heat diffusion
[M_bc, RHS_bc] = boundaryCondition(BC); % matrix of coefficients and RHS vector for the boundary conditions
T = solvePDE(m, M_cond+M_bc, RHS_bc); % solve the linear system of discretized PDE
visualizeCells(T); % visualize the results