// // Solves a linear system iteratively via conjugate-gradient // // A: complex matrix // y: right-hand side // x0: initial guess // nmax: max number of iterations // tol: tolerance // [[Rcpp::export]] arma::cx_mat cpp_cg_solve(const arma::cx_mat& A, const arma::cx_mat& y, arma::cx_mat& x0, const double nmax, const double tol) { int n = 0, ii = 0; // counter const int nr = y.n_cols; // number of right-hand side cols double rel_error = 1e4; // large value const int N = y.n_rows; // temporary variables double alpha_i, beta_i; const arma::cx_mat B = A.t(); // Hermitian transpose. // Note: diag blocks not symmetric, so no easier way arma::cx_colvec y_i(N), z_i(N), g_i(N), p_i(N), w_i(N), v_i(N), x_i(N); arma::cx_colvec g_ip1(N), p_ip1(N), w_ip1(N), v_ip1(N), x_ip1(N); // loop over RHS cols for (ii=0; ii < nr; ii++){ // initial step y_i = y.col(ii); z_i = B * y_i; x_i = x0.col(ii); g_i = z_i - B * A * x_i; p_i = g_i; w_i = A * x_i; v_i = A * p_i; n = 0; rel_error = 1e4; while ((n < nmax) && (rel_error > tol)){ alpha_i = real(cdot(g_i, g_i) / cdot(v_i, v_i)); x_ip1 = x_i + alpha_i * p_i; w_ip1 = w_i + alpha_i * v_i; g_ip1 = z_i - B * w_ip1; beta_i = real(cdot(g_ip1,g_ip1) / cdot(g_i,g_i)); // updating p_i = g_ip1 + beta_i * p_i; v_i = A * p_i; rel_error = norm(x_ip1 - x_i) / norm(x_ip1) ; x_i = x_ip1; if(rel_error < tol) break; // skip cost of next line w_i = A * x_i; g_i = g_ip1; n++; }; // end while x0.col(ii) = x_i; }; //end loop return x0; }
// // Angle-resolved spectra for linear or circular polarisations // // kn: vector of incident wavenumbers // medium: surrounding refractive index // R: Nx3 matrix of positions // Alpha: 3NxNl matrix of principal polarisabilities // Angles: Nx3 matrix of particle rotation angles // Incidence: Ni vector of incident beam directions // Axes: Ni vector of incident beam axes // ScatteringNodes: 2xNs matrix of scattered field directions // ScatteringWeights: Ns vector of scattered field quadrature weights // polarisation: integer flag to switch between linear and circular polarisation // inversion: integer flag to use different inversion methods // maxiter: max number of iterations // tol: tolerance // progress: logical flag to display progress bars // [[Rcpp::export]] arma::cube cpp_dispersion_spectrum(const arma::colvec kn, const double medium, const arma::mat& R, const arma::cx_mat& Alpha, const arma::mat& Angles, const arma::vec& Incidence, const arma::ivec& Axes, const arma::mat& ScatteringNodes, const arma::vec& ScatteringWeights, const int polarisation, const int inversion, const int maxiter, const double tol, const bool progress) { const int Ni = Incidence.n_elem; int Nl = kn.n_elem, Nr = R.n_cols, ll; arma::cube res(Ni, 6, Nl); arma::mat tmp(Ni, 6); // global, will update at each wavelength arma::cx_cube AlphaBlocks = arma::zeros<arma::cx_cube>(3, 3, Nr); // global, will update at each wavelength arma::cx_mat A(3*Nr, 3*Nr ); if(inversion < 2) { // full interaction matrix A.eye(); } else if (inversion == 2){ // only propagator G = I - A A.zeros(); } for(ll=0; ll<Nl; ll++){ // loop over kn if(progress) progress_bar(ll+1,Nl); // update in place cpp_alpha_blocks_update(Alpha.col(ll), Angles, AlphaBlocks); // if solve or cg, need full A, otherwise just G if(inversion < 2) { // full interaction matrix // update in place cpp_interaction_matrix_update(R, kn(ll), AlphaBlocks, A); } else if (inversion == 2){ // only propagator G = I - A // update in place cpp_propagator_update(R, kn(ll), AlphaBlocks, A); } tmp = cpp_dispersion(R, A, AlphaBlocks, kn(ll), medium, Incidence, Axes, ScatteringNodes, ScatteringWeights, polarisation, inversion, maxiter, tol); // Rcpp::Rcout << tmp << "\n"; res.slice(ll) = 1.0/Nr * tmp; } if(progress) Rcpp::Rcout << "\n"; return res ; }
arma::cx_mat cI::operator*(arma::cx_mat input) { arma::cx_mat outputMAT(prod(_S),input.n_cols); if(input.n_rows==prod(_S)) { for(unsigned int i=0;i<input.n_cols;i++) { //func_fftn(arma::cx_vec vec_Inp,arma::Col<int> S,const string forward_or_backward) //check(_Faktor,input.col(i),"*"); // check if _Faktor has as many cols as input rows outputMAT.col(i)=func_fftn(input.col(i),this->_S,"backward"); } } else { // verbosity(*_Pa,"CI: do the transform",2,__FILE__,__LINE__); for(unsigned int i=0;i<input.n_cols;i++) { //verbosity(*_Pa,"CI: do it for column"+std::to_string(i),2,__FILE__,__LINE__); //func_fftn(arma::cx_vec vec_Inp,arma::Col<int> S,const string forward_or_backward) //check(_Faktor,input.col(i),"*"); // check if _Faktor has as many cols as input rows // cout << size(full(_Pa->activeIndices)) << endl; // cout << size(input) << endl; // cout << size(input.col(i)) << endl; // cout << size(test) << endl; // for(int j=0;j<_Pa->numberOfActiveIndices;j++) // { // cout << uv(j) << " " << j << endl; // full(uv(j),0)=input(j,i); // } _full=arma::zeros<arma::cx_mat>(arma::prod(_S),1); _full(_uv)=input.col(i); outputMAT.col(i)=func_fftn(_full,this->_S,"backward"); } } return outputMAT; }