reconstructor.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033  *
00034  * */
00035 
00036 #include "reconstructor.h"
00037 #include "ctf.h"
00038 #include "emassert.h"
00039 #include "symmetry.h"
00040 #include <cstring>
00041 #include <fstream>
00042 #include <iomanip>
00043 #include <boost/bind.hpp>
00044 #include <boost/format.hpp>
00045 
00046 #include <gsl/gsl_statistics_double.h>
00047 #include <gsl/gsl_fit.h>
00048 
00049 using namespace EMAN;
00050 using std::complex;
00051 
00052 
00053 #include <iostream>
00054 using std::cerr;
00055 using std::endl;
00056 using std::cout; // for debug
00057 
00058 #include <algorithm>
00059 // find, for_each
00060 
00061 #include <iomanip>
00062 using std::setprecision;
00063 
00064 template < typename T > void checked_delete( T*& x )
00065 {
00066     typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
00067     (void) sizeof(type_must_be_complete);
00068     delete x;
00069     x = NULL;
00070 }
00071 
00072 
00073 template <> Factory < Reconstructor >::Factory()
00074 {
00075         force_add(&FourierReconstructor::NEW);
00076         force_add(&FourierReconstructorSimple2D::NEW);
00077         force_add(&BaldwinWoolfordReconstructor::NEW);
00078         force_add(&WienerFourierReconstructor::NEW);
00079         force_add(&BackProjectionReconstructor::NEW);
00080         force_add(&nn4Reconstructor::NEW);
00081         force_add(&nnSSNR_Reconstructor::NEW);
00082         force_add(&nn4_ctfReconstructor::NEW);
00083         force_add(&nnSSNR_ctfReconstructor::NEW);
00084 }
00085 
00086 void FourierReconstructorSimple2D::setup()
00087 {
00088         nx = params.set_default("nx",0);
00089 
00090         if ( nx < 0 ) throw InvalidValueException(nx, "nx must be positive");
00091 
00092         bool is_fftodd = (nx % 2 == 1);
00093 
00094         ny = nx;
00095         nx += 2-is_fftodd;
00096 
00097         image = new EMData();
00098         image->set_size(nx, ny);
00099         image->set_complex(true);
00100         image->set_fftodd(is_fftodd);
00101         image->set_ri(true);
00102 
00103         tmp_data = new EMData();
00104         tmp_data->set_size(nx/2, nx);
00105 }
00106 
00107 int FourierReconstructorSimple2D::insert_slice(const EMData* const slice, const Transform & euler)
00108 {
00109 
00110         // Are these exceptions really necessary? (d.woolford)
00111         if (!slice) throw NullPointerException("EMData pointer (input image) is NULL");
00112 
00113         if ( slice->get_ndim() != 1 ) throw ImageDimensionException("Image dimension must be 1");
00114 
00115         // I could also test to make sure the image is the right dimensions...
00116         if (slice->is_complex()) throw ImageFormatException("The image is complex, expecting real");
00117 
00118         EMData* working_slice = slice->process("xform.phaseorigin.tocorner");
00119 
00120         // Fourier transform the slice
00121         working_slice->do_fft_inplace();
00122 
00123         float* rdata = image->get_data();
00124         float* norm = tmp_data->get_data();
00125         float* dat = working_slice->get_data();
00126 
00127         float g[4];
00128         int offset[4];
00129         float dt[2];
00130         offset[0] = 0; offset[1] = 2; offset[2] = nx; offset[3] = nx+2;
00131 
00132         float alt = -((float)(euler.get_rotation("2d"))["alpha"])*M_PI/180.0f;
00133         for (int x = 0; x < working_slice->get_xsize() / 2; x++) {
00134 
00135                 float rx = (float) x;
00136 
00137                 float xx = rx*cos(alt);
00138                 float yy = rx*sin(alt);
00139                 float cc = 1.0;
00140 
00141                 if (xx < 0) {
00142                         xx = -xx;
00143                         yy = -yy;
00144                         cc = -1.0;
00145                 }
00146 
00147                 yy += ny / 2;
00148 
00149 
00150                 dt[0] = dat[2*x];
00151                 dt[1] = cc * dat[2*x+1];
00152 
00153                 // PHIL IS INTERESTED FROM HERE DOWN
00154                 int x0 = (int) floor(xx);
00155                 int y0 = (int) floor(yy);
00156 
00157                 int i = 2*x0 + y0*nx;
00158 
00159                 float dx = xx - x0;
00160                 float dy = yy - y0;
00161 
00162                 g[0] = Util::agauss(1, dx, dy, 0, EMConsts::I2G);
00163                 g[1] = Util::agauss(1, 1 - dx, dy, 0, EMConsts::I2G);
00164                 g[2] = Util::agauss(1, dx, 1 - dy, 0, EMConsts::I2G);
00165                 g[3] = Util::agauss(1, 1 - dx, 1 - dy, 0, EMConsts::I2G);
00166 
00167                 // At the extreme we can only do some much...
00168                 if ( x0 == nx-2 ) {
00169                         int k = i + offset[0];
00170                         rdata[k] += g[0] * dt[0];
00171                         rdata[k + 1] += g[0] * dt[1];
00172                         norm[k/2] += g[0];
00173 
00174                         k = i + offset[2];
00175                         rdata[k] += g[2] * dt[0];
00176                         rdata[k + 1] += g[2] * dt[1];
00177                         norm[k/2] += g[2];
00178                         continue;
00179 
00180                 }
00181                 // capture and accommodate for periodic boundary conditions in the x direction
00182                 if ( x0 > nx-2 ) {
00183                         int dif = x0 - (nx-2);
00184                         x0 -= dif;
00185                 }
00186                 // At the extreme we can only do some much...
00187                 if ( y0 == ny -1 ) {
00188                         int k = i + offset[0];
00189                         rdata[k] += g[0] * dt[0];
00190                         rdata[k + 1] += g[0] * dt[1];
00191                         norm[k/2] += g[0];
00192 
00193                         k = i + offset[1];
00194                         rdata[k] += g[1] * dt[0];
00195                         rdata[k + 1] += g[1] * dt[1];
00196                         norm[k/2] += g[1];
00197                         continue;
00198                 }
00199                 // capture and accommodate for periodic boundary conditions in the y direction
00200                 if ( y0 > ny-1) {
00201                         int dif = y0 - (ny-1);
00202                         y0 -= dif;
00203                 }
00204 
00205                 if (x0 >= nx - 2 || y0 >= ny - 1) continue;
00206 
00207 
00208 
00209 
00210                 for (int j = 0; j < 4; j++)
00211                 {
00212                         int k = i + offset[j];
00213                         rdata[k] += g[j] * dt[0];
00214                         rdata[k + 1] += g[j] * dt[1];
00215                         norm[k/2] += g[j];
00216 
00217                 }
00218         }
00219 
00220         return 0;
00221 
00222 }
00223 
00224 EMData *FourierReconstructorSimple2D::finish()
00225 {
00226         normalize_threed();
00227 
00228         image->process_inplace("xform.fourierorigin.tocorner");
00229         image->do_ift_inplace();
00230         image->depad();
00231         image->process_inplace("xform.phaseorigin.tocenter");
00232 
00233         return          image;
00234 }
00235 
00236 void ReconstructorVolumeData::normalize_threed()
00237 {
00238         float* norm = tmp_data->get_data();
00239         float* rdata = image->get_data();
00240 
00241         // FIXME should throw a sensible error
00242         if ( 0 == norm ) throw NullPointerException("The normalization volume was null!");
00243         if ( 0 == rdata ) throw NullPointerException("The complex reconstruction volume was null!");
00244 
00245         for (int i = 0; i < nx * ny * nz; i += 2) {
00246                 float d = norm[i/2];
00247                 if (d == 0) {
00248                         rdata[i] = 0;
00249                         rdata[i + 1] = 0;
00250                 }
00251                 else {
00252                         rdata[i] /= d;
00253                         rdata[i + 1] /= d;
00254                 }
00255         }
00256 }
00257 
00258 void FourierReconstructor::free_memory()
00259 {
00260         if ( inserter != 0 )
00261         {
00262                 delete inserter;
00263                 inserter = 0;
00264         }
00265         if ( interp_FRC_calculator != 0 )
00266         {
00267                 delete interp_FRC_calculator;
00268                 interp_FRC_calculator = 0;
00269         }
00270 }
00271 
00272 #include <sstream>
00273 
00274 void FourierReconstructor::load_inserter()
00275 {
00276         // ints get converted to strings byt the Dict object here
00277 
00278         stringstream ss;
00279         ss << (int)params["mode"];
00280         string mode;
00281         ss >> mode;
00282 //      ss
00283 //      string mode = (string)params["mode"];
00284         Dict parms;
00285         parms["rdata"] = image->get_data();
00286         parms["norm"] = tmp_data->get_data();
00287         parms["nx"] = nx;
00288         parms["ny"] = ny;
00289         parms["nz"] = nz;
00290 
00291         if ( inserter != 0 )
00292         {
00293                 delete inserter;
00294         }
00295 
00296         inserter = Factory<FourierPixelInserter3D>::get(mode, parms);
00297         inserter->init();
00298 }
00299 
00300 
00301 
00302 void FourierReconstructor::load_interp_FRC_calculator()
00303 {
00304         Dict init_parms;
00305         init_parms["rdata"] = image->get_data();
00306         init_parms["norm"] = tmp_data->get_data();
00307         init_parms["nx"] = nx;
00308         init_parms["ny"] = ny;
00309         init_parms["nz"] = nz;
00310 
00311         if ( x_scale_factor != 0 ) init_parms["x_scale"] = 1.0/x_scale_factor;
00312         if ( y_scale_factor != 0 ) init_parms["y_scale"] = 1.0/y_scale_factor;
00313         if ( z_scale_factor != 0 ) init_parms["z_scale"] = 1.0/z_scale_factor;
00314 
00315         if ( interp_FRC_calculator != 0 )
00316         {
00317                 delete interp_FRC_calculator;
00318         }
00319 
00320         stringstream ss;
00321         ss << (int)params["mode"];
00322         string mode;
00323         ss >> mode;
00324 
00325         interp_FRC_calculator = Factory<InterpolatedFRC>::get(mode, init_parms);
00326 }
00327 
00328 void FourierReconstructor::setup()
00329 {
00330         // default setting behavior - does not override if the parameter is already set
00331         params.set_default("mode",2);
00332 
00333         int x_size = params["x_in"];
00334         if ( x_size < 0 ) throw InvalidValueException(x_size, "x size of images must be greater than 0");
00335         int y_size = params["y_in"];
00336         if ( y_size < 0 ) throw InvalidValueException(y_size, "y size of images must be greater than 0");
00337 
00338         if ( x_size > y_size ) max_input_dim = x_size;
00339         else max_input_dim = y_size;
00340 
00341         // This is a helical adaptation - FIXME explain
00342         bool helical_special_behavior = false;
00343         if ( helical_special_behavior )
00344         {
00345                 if ( x_size > y_size )
00346                 {
00347                         if ( (int) params["xsample"] == 0 ) params["xsample"] = y_size;
00348                         if ( (int) params["zsample"] == 0 ) params["zsample"] = x_size;
00349                 }
00350                 if ( y_size > x_size )
00351                 {
00352                         if ( (int) params["ysample"] == 0 ) params["ysample"] = x_size;
00353                         if ( (int) params["zsample"] == 0 ) params["zsample"] = y_size;
00354                 }
00355         }
00356 
00357         if ( (int) params["xsample"] != 0  ) output_x = (int) params["xsample"];
00358         else output_x = x_size;
00359 
00360         if ( (int) params["ysample"] != 0  ) output_y = (int) params["ysample"];
00361         else output_y = y_size;
00362 
00363         if ( (int) params["zsample"] != 0  ) output_z = (int) params["zsample"];
00364         else
00365         {
00366                 if ( x_size == y_size ) output_z = x_size;
00367                 else if ( x_size > y_size ) output_z = x_size;
00368                 else output_z = y_size;
00369         }
00370 
00371         nx = output_x;
00372         ny = output_y;
00373         nz = output_z;
00374 
00375         // Adjust nx if for Fourier transform even odd issues
00376         bool is_fftodd = (nx % 2 == 1);
00377         // The Fourier transform requires one extra pixel in the x direction,
00378         // which is two spaces in memory, one each for the complex and the
00379         // real components
00380         nx += 2-is_fftodd;
00381 
00382         if ( (int) params["zsample"] == 0  ) nz = max_input_dim;
00383 
00384         if ( nz < max_input_dim ) z_scale_factor = (float) nz / (float) max_input_dim;
00385         if ( ny < max_input_dim ) y_scale_factor = (float) ny / (float) max_input_dim;
00386         if ( nx < max_input_dim ) x_scale_factor = (float) nx / (float) max_input_dim;
00387 
00388         // Odd dimension support is here atm, but not above.
00389         image = new EMData();
00390         image->set_size(nx, ny, nz);
00391         image->set_complex(true);
00392         image->set_fftodd(is_fftodd);
00393         image->set_ri(true);
00394 
00395         tmp_data = new EMData();
00396         tmp_data->set_size(nx/2, ny, nz);
00397         tmp_data->to_zero();
00398         tmp_data->update();
00399 
00400         load_inserter();
00401         load_interp_FRC_calculator();
00402 
00403         if ( (bool) params["quiet"] == false )
00404         {
00405                 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
00406                 cout << "You will require approximately " << setprecision(3) << (nx*ny*nz*sizeof(float)*1.5)/1000000000.0 << "GB of memory to reconstruct this volume" << endl;
00407                 cout << "Scale factors are " << x_scale_factor << " " << y_scale_factor << " " << z_scale_factor << endl;
00408                 cout << "Max input dim is " << max_input_dim << endl;
00409         }
00410 }
00411 
00412 EMData* FourierReconstructor::preprocess_slice( const EMData* const slice,  const Transform& t )
00413 {
00414         // Shift the image pixels so the real space origin is now located at the phase origin (at the bottom left of the image)
00415         EMData* return_slice = 0;
00416         Transform tmp(t);
00417         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly
00418 
00419         Vec2f trans = tmp.get_trans_2d();
00420         float scale = tmp.get_scale();
00421         bool mirror = tmp.get_mirror();
00422         if (trans[0] != 0 || trans[1] != 0 || scale != 1.0 ) {
00423                 return_slice = slice->process("math.transform",Dict("transform",&tmp));
00424         } else if ( mirror == true ) {
00425                 return_slice = slice->process("xform.flip",Dict("axis","x"));
00426         }
00427 
00428         if (return_slice == 0) {
00429                 return_slice = slice->process("xform.phaseorigin.tocorner");
00430         } else {
00431                 return_slice->process_inplace("xform.phaseorigin.tocorner");
00432         }
00433 
00434 //      EMData* return_slice = slice->process("normalize.edgemean");
00435 //      return_slice->process_inplace("xform.phaseorigin.tocorner");
00436 
00437         // Fourier transform the slice
00438         return_slice->do_fft_inplace();
00439 
00440         return_slice->mult((float)sqrt(1.0f/(return_slice->get_ysize())*return_slice->get_xsize()));
00441 
00442         // Shift the Fourier transform so that it's origin is in the center (bottom) of the image.
00443         return_slice->process_inplace("xform.fourierorigin.tocenter");
00444 
00445         return return_slice;
00446 }
00447 
00448 void FourierReconstructor::zero_memory()
00449 {
00450         if (tmp_data != 0 ) tmp_data->to_zero();
00451         if (image != 0 ) image->to_zero();
00452 
00453         EMData* start_model = params.set_default("start_model",(EMData*)0);
00454 
00455         if (start_model != 0) {
00456                 if (!start_model->is_complex()) {
00457                         start_model->do_fft_inplace();
00458                         start_model->process_inplace("xform.phaseorigin.tocenter");
00459                 }
00460 
00461                 if (start_model->get_xsize() != nx || start_model->get_ysize() != ny || start_model->get_zsize() != nz ) {
00462                         throw ImageDimensionException("The dimensions of the start_model are incorrect");
00463                 }
00464 
00465                 if (!start_model->is_shuffled()) {
00466                         start_model->process_inplace("xform.fourierorigin.tocenter");
00467                 }
00468 
00469                 memcpy(image->get_data(),start_model->get_data(),nx*ny*nz*sizeof(float));
00470 
00471                 float start_model_weight =  params.set_default("start_model_weight",1.0f);
00472 
00473                 if (start_model_weight != 1.0) {
00474                         image->mult(start_model_weight);
00475                 }
00476 
00477                 tmp_data->add(start_model_weight);
00478         }
00479 }
00480 
00481 int FourierReconstructor::insert_slice(const EMData* const input_slice, const Transform & arg)
00482 {
00483         // Are these exceptions really necessary? (d.woolford)
00484         if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
00485 
00486         // I could also test to make sure the image is the right dimensions...
00487         if (input_slice->is_complex()) throw ImageFormatException("The image is complex, expecting real");
00488 
00489         // Get the proprecessed slice - there are some things that always happen to a slice,
00490         // such as as Fourier conversion and optional padding etc.
00491         //
00492         // We must use only the rotational component of the transform, scaling, translation and mirroring
00493         // are not implemented in Fourier space
00494         Transform * rotation;
00495         if ( input_slice->has_attr("xform.projection") ) {
00496                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
00497         } else {
00498                 rotation = new Transform(arg); // assignment operator
00499         }
00500 
00501         EMData* slice = preprocess_slice( input_slice, *rotation);
00502 
00503         // Catch the first time a slice is inserted to do some things....
00504         if ( slice_insertion_flag == true )
00505         {
00506                 // Zero the memory in the associated EMData objects
00507                 zero_memory();
00508                 // Reset the image_idx to zero
00509                 image_idx = 0;
00510                 // Set flags appropriately
00511                 slice_agreement_flag = true;
00512                 slice_insertion_flag = false;
00513 
00514                 // should be a if verbose here
00515                 //if ( prev_quality_scores.size() != 0 ) print_stats( prev_quality_scores );
00516         }
00517 
00518         // quality_scores.size() is zero on the first run, so this enforcement of slice quality does not take
00519         // place until after the first round of slice insertion
00520         if ( quality_scores.size() != 0 )
00521         {
00522                 if ( quality_scores[image_idx].get_snr_normed_frc_integral() < (float) params["hard"] )
00523                 {
00524                         image_idx++;
00525                         return 1;
00526                 }
00527                 slice->mult(1.f/quality_scores[image_idx].get_norm());
00528 //              cout << "Norm multiplied by " << 1.f/quality_scores[image_idx].get_norm() << endl;
00529                 image_idx++;
00530         }
00531 
00532         // Finally to the pixel wise slice insertion
00533         rotation->set_scale(1.0);
00534         rotation->set_mirror(false);
00535         rotation->set_trans(0,0,0);
00536         do_insert_slice_work(slice, *rotation);
00537 
00538         if(rotation) {delete rotation; rotation=0;}
00539         delete slice;
00540 
00541 //      image->update();
00542         return 0;
00543 }
00544 
00545 void FourierReconstructor::do_insert_slice_work(const EMData* const input_slice, const Transform & arg)
00546 {
00547         // Reload the inserter if the mode has changed
00548         string mode = (string) params["mode"];
00549         if ( mode != inserter->get_name() )     load_inserter();
00550 
00551         int rl = Util::square( max_input_dim / 2);
00552 
00553         float dt[2];
00554 
00555         float y_scale = 0, x_scale = 0;
00556 
00557         int y_in = input_slice->get_ysize();
00558         int x_in = input_slice->get_xsize();
00559         // Adjust the dimensions to account for odd and even ffts
00560         if (input_slice->is_fftodd()) x_in -= 1;
00561         else x_in -= 2;
00562 
00563         if ( y_in != x_in )
00564         {
00565                 if ( x_in > y_in ) y_scale = (float) x_in / (float) y_in;
00566                 else x_scale = (float) y_in / (float) x_in;
00567         }
00568 
00569         float *dat = input_slice->get_data();
00570         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
00571         float weight = params.set_default("weight",1.0f);
00572 
00573         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
00574                 Transform t3d = arg*(*it);
00575                 for (int y = 0; y < input_slice->get_ysize(); y++) {
00576                         for (int x = 0; x < input_slice->get_xsize() / 2; x++) {
00577 
00578                                 float rx = (float) x;
00579                                 float ry = (float) y;
00580 
00581                                 if ( y_in != x_in )
00582                                 {
00583                                         if ( x_in > y_in ) ry *= y_scale;
00584                                         else rx *= x_scale;
00585                                 }
00586 
00587                                 if ((rx * rx + Util::square(ry - max_input_dim / 2)) > rl)
00588                                         continue;
00589 
00590                                 Vec3f coord(rx,(ry - max_input_dim / 2),0);
00591                                 coord = coord*t3d; // transpose multiplication
00592                                 float xx = coord[0];
00593                                 float yy = coord[1];
00594                                 float zz = coord[2];
00595 
00596                                 float cc = 1;
00597 
00598                                 if (xx < 0) {
00599                                         xx = -xx;
00600                                         yy = -yy;
00601                                         zz = -zz;
00602                                         cc = -1.0;
00603                                 }
00604 
00605                                 if ( z_scale_factor != 0 ) zz *= z_scale_factor;
00606                                 if ( y_scale_factor != 0 ) yy *= y_scale_factor;
00607                                 if ( x_scale_factor != 0 ) xx *= x_scale_factor;
00608 
00609                                 yy += ny / 2;
00610                                 zz += nz / 2;
00611 
00612                                 int idx = x * 2 + y * (input_slice->get_xsize());
00613                                 dt[0] = dat[idx];
00614                                 dt[1] = cc * dat[idx+1];
00615 
00616                                 inserter->insert_pixel(xx,yy,zz,dt,weight);
00617                         }
00618                 }
00619         }
00620 }
00621 
00622 int FourierReconstructor::determine_slice_agreement(const EMData* const input_slice, const Transform & t3d, const unsigned int num_particles_in_slice)
00623 {
00624         // Are these exceptions really necessary? (d.woolford)
00625         if (!input_slice) {
00626                 LOGERR("Insertion of NULL slice in FourierReconstructor::insert_slice");
00627                 throw NullPointerException("EMData pointer (input image) is NULL");
00628         }
00629 
00630         // I could also test to make sure the image is the right dimensions...
00631         if (input_slice->is_complex()) {
00632                 LOGERR("Do not Fourier transform the image before it is passed to determine_slice_agreement in FourierReconstructor, this is performed internally");
00633                 throw ImageFormatException("The image is complex, expecting real");
00634         }
00635 
00636         // The first time determine_slice_agreement is called (in each iteration) some things need to happen...
00637         if ( slice_agreement_flag == true )
00638         {
00639                 // Normalize the real data using the normalization values in the normalization volume
00640                 // This is important because the InterpolatedFRC objects assumes this behaviour
00641                 normalize_threed();
00642                 // Reset the image_idx to index into prev_quality_scores correctly
00643                 image_idx = 0;
00644                 // Make a copy of the previous quality scores - the first time around this will be like copying nothing
00645                 prev_quality_scores = quality_scores;
00646                 // Now clear the old scores so they can be redetermined
00647                 quality_scores.clear();
00648                 // Reset the flags
00649                 slice_insertion_flag = true;
00650                 slice_agreement_flag = false;
00651         }
00652 
00653         // Get the proprecessed slice - there are some things that always happen to a slice,
00654         // such as as Fourier conversion and optional padding etc.
00655         Transform * rotation;
00656         if ( input_slice->has_attr("xform.projection") ) {
00657                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
00658 
00659         } else {
00660                 rotation = new Transform(t3d); // assignment operator
00661         }
00662         EMData* slice = preprocess_slice( input_slice, *rotation );
00663 
00664         // quality_scores.size() is zero on the first run, so this enforcement of slice quality does not take
00665         // place until after the first round of slice insertion
00666         if (  prev_quality_scores.size() != 0 )
00667         {
00668                 // The slice must be multiplied by the normalization value used in insert or else the calculations will
00669                 // be inconsistent
00670                 slice->mult(1.f/prev_quality_scores[image_idx].get_norm());
00671         }
00672 
00673         // Reset zeros the associated memory in the ifrc
00674         interp_FRC_calculator->reset();
00675 
00676         int rl = Util::square( max_input_dim / 2);
00677 
00678         float dt[2];
00679 
00680         float y_scale = 0, x_scale = 0;
00681 
00682         int y_in = slice->get_ysize();
00683         int x_in = slice->get_xsize();
00684         if (input_slice->is_fftodd()) x_in -= 1;
00685         else x_in -= 2;
00686 
00687         if ( y_in != x_in )
00688         {
00689                 if ( x_in > y_in ) y_scale = (float) x_in / (float) y_in;
00690                 else x_scale = (float) y_in / (float) x_in;
00691         }
00692         float *dat = slice->get_data();
00693 
00694         float weight = params.set_default("weight",1.0f);
00695 
00696 
00697         rotation->set_scale(1.0);
00698         rotation->set_mirror(false);
00699         rotation->set_trans(0,0,0);
00700 
00701         for (int y = 0; y < slice->get_ysize(); y++) {
00702                 for (int x = 0; x < slice->get_xsize() / 2; x++) {
00703 
00704                         float rx = (float) x;
00705                         float ry = (float) y;
00706 
00707                         if ( y_in != x_in )
00708                         {
00709                                 if ( x_in > y_in ) ry *= y_scale;
00710                                 else rx *= x_scale;
00711                         }
00712 
00713                         if ((rx * rx + Util::square(ry - max_input_dim / 2)) > rl)
00714                                 continue;
00715 
00716 //                      float xx = (float) (rx * t3d[0][0] + (ry - max_input_dim / 2) * t3d[1][0]);
00717 //                      float yy = (float) (rx * t3d[0][1] + (ry - max_input_dim / 2) * t3d[1][1]);
00718 //                      float zz = (float) (rx * t3d[0][2] + (ry - max_input_dim / 2) * t3d[1][2]);
00719 
00720                         Vec3f coord(rx,(ry - max_input_dim / 2),0);
00721                         coord = coord*(*rotation); // transpose multiplication
00722                         float xx = coord[0];
00723                         float yy = coord[1];
00724                         float zz = coord[2];
00725 
00726                         float cc = 1;
00727 
00728                         if (xx < 0) {
00729                                 xx = -xx;
00730                                 yy = -yy;
00731                                 zz = -zz;
00732                                 cc = -1.0;
00733                         }
00734 
00735                         if ( z_scale_factor != 0 ) zz *= z_scale_factor;
00736                         if ( y_scale_factor != 0 ) yy *= y_scale_factor;
00737                         if ( x_scale_factor != 0 ) xx *= x_scale_factor;
00738 
00739                         yy += ny / 2;
00740                         zz += nz / 2;
00741 
00742                         int idx = x * 2 + y * (slice->get_xsize());
00743                         dt[0] = dat[idx];
00744                         dt[1] = cc * dat[idx+1];
00745 
00746 
00747                         if ( prev_quality_scores.size() != 0 )
00748                         {
00749                                 // If the slice was not inserted into the 3D volume in the previous round of slice insertion
00750                                 // then the weight must be set to zero, or else the result produced by the InterpolatedFRC will be wrong.
00751                                 // This is because the InterpolatedFRC subtracts the incoming pixels from the 3D volume in order
00752                                 // to estimate quality using only data from the other slices in the volume. If the slice was not previously inserted
00753                                 // then it should not be subtracted prior to quality estimation....
00754                                 if ( prev_quality_scores[image_idx].get_snr_normed_frc_integral() < (float) params["hard"] )
00755                                 {
00756                                         weight = 0;
00757                                 }
00758                         }
00759                         // FIXME: this could be replaced in favor of a class implementation with no switch statement, similar to the
00760                         // inserter in the Fourier reconstructor do_insert_slice_work method
00761 
00762                         interp_FRC_calculator->continue_frc_calc(xx, yy, zz, dt, weight);
00763                 }
00764         }
00765 
00766         InterpolatedFRC::QualityScores q_scores = interp_FRC_calculator->finish( num_particles_in_slice );
00767         // Print the quality scores here for debug information
00768         //q_scores.debug_print();
00769 
00770         if (prev_quality_scores.size() != 0 )
00771         {
00772                 // If a previous normalization value has been calculated then average it with the one that
00773                 // was just calculated, this will cause the normalization values to converge more rapidly.
00774                 q_scores.set_norm((q_scores.get_norm() + prev_quality_scores[image_idx].get_norm())/2.0f);
00775                 image_idx++;
00776         }
00777 
00778         quality_scores.push_back(q_scores);
00779 
00780         if(rotation) {delete rotation; rotation=0;}
00781         delete slice;
00782         return 0;
00783 }
00784 
00785 void FourierReconstructor::print_stats( const vector<InterpolatedFRC::QualityScores>& scores )
00786 {
00787         if ( prev_quality_scores.size() == 0 )
00788         {
00789                 //cout << "No quality scores present in FourierReconstructor::print_stats, nothing to print" << endl;
00790                 return;
00791         }
00792 
00793         unsigned int size = scores.size();
00794 
00795         unsigned int contributing_images = 0;
00796         for( unsigned int i = 0; i < size; ++ i )
00797         {
00798                 if (scores[i].get_snr_normed_frc_integral() < (float) params["hard"])
00799                         continue;
00800                 else contributing_images++;
00801         }
00802 
00803         double* norm_frc = new double[contributing_images];
00804         double* frc = new double[contributing_images];
00805         double* norm_snr = new double[contributing_images];
00806 
00807         unsigned int idx = 0;
00808         for( unsigned int i = 0; i < size; ++ i )
00809         {
00810                 if (scores[i].get_snr_normed_frc_integral() < (float) params["hard"])
00811                         continue;
00812 
00813                 norm_frc[idx] = scores[i].get_snr_normed_frc_integral();
00814                 frc[idx] = scores[i].get_frc_integral();
00815                 norm_snr[idx] = scores[i].get_normed_snr_integral();
00816 
00817                 ++idx;
00818         }
00819 
00820         double mean = gsl_stats_mean(norm_frc, 1, contributing_images);
00821         double variance = gsl_stats_variance_m(norm_frc, 1, contributing_images, mean);
00822 
00823         cout << "Normalized FRC mean " << mean << " std dev " << sqrt(variance) << endl;
00824 
00825         mean = gsl_stats_mean(frc, 1, contributing_images);
00826         variance = gsl_stats_variance_m(frc, 1, contributing_images, mean);
00827 
00828         cout << "FRC mean " << mean << " std dev " << sqrt(variance) << endl;
00829 
00830         mean = gsl_stats_mean(norm_snr, 1, contributing_images);
00831         variance = gsl_stats_variance_m(norm_snr, 1, contributing_images, mean);
00832         cout << "SNR mean " << mean << " std dev " << sqrt(variance) << endl;
00833 
00834         double c0, c1, cov00, cov01, cov11, sumsq;
00835         gsl_fit_linear (norm_frc, 1, frc, 1, contributing_images, &c0, &c1, &cov00, &cov01, &cov11, &sumsq);
00836         cout << "The correlation between frc and norm_frc is " << c0 << " + " << c1 << "x" << endl;
00837 
00838         gsl_fit_linear (norm_frc, 1, norm_snr, 1, contributing_images, &c0, &c1, &cov00, &cov01, &cov11, &sumsq);
00839         cout << "The correlation between norm_snr and norm_frc is " << c0 << " + " << c1 << "x" << endl;
00840 
00841         gsl_fit_linear (norm_snr, 1, frc, 1, contributing_images, &c0, &c1, &cov00, &cov01, &cov11, &sumsq);
00842         cout << "The correlation between frc and norm_snr is " << c0 << " + " << c1 << "x" << endl;
00843 
00844         delete [] norm_frc;
00845         delete [] frc;
00846         delete [] norm_snr;
00847 }
00848 
00849 EMData *FourierReconstructor::finish()
00850 {
00851         float *norm = tmp_data->get_data();
00852         float *rdata = image->get_data();
00853 
00854         if (params["dlog"]) {
00855                 size_t size = nx*ny*nz;
00856                 for (size_t i = 0; i < size; i += 2) {
00857                         float d = norm[i];
00858                         if (d == 0) {
00859                                 rdata[i] = 0;
00860                                 rdata[i + 1] = 0;
00861                         }
00862                         else {
00863                                 float in = norm[i + 1] / norm[i];
00864                                 float cin = Util::square_sum(rdata[i], rdata[i + 1]);
00865                                 rdata[i] *= sqrt(in / cin);
00866                                 rdata[i + 1] *= sqrt(in / cin);
00867                         }
00868                 }
00869         }
00870         else {
00871                 normalize_threed();
00872         }
00873 
00874 //      tmp_data->write_image("density.mrc");
00875 
00876         // we may as well delete the tmp data now... it saves memory and the calling program might
00877         // need memory after it gets the return volume.
00878         // If this delete didn't happen now, it would happen when the deconstructor was called,
00879         if ( tmp_data != 0 )
00880         {
00881                 delete tmp_data;
00882                 tmp_data = 0;
00883         }
00884 
00885 
00886         if ( params["3damp"]) {
00887                 EMData* fftimage = image->get_fft_amplitude ();
00888                 fftimage->write_image("threed_fft_amp.mrc");
00889                 delete fftimage;
00890         }
00891 
00892         //
00893         image->process_inplace("xform.fourierorigin.tocorner");
00894         image->do_ift_inplace();
00895         image->depad();
00896         image->process_inplace("xform.phaseorigin.tocenter");
00897 
00898         // If the image was padded it should be the original size, as the client would expect
00899         //  I blocked the rest, it is almost certainly incorrect  PAP 07/31/08
00900         // No, it's not incorrect. You are wrong. You have the meaning of nx mixed up. DSAW 09/23/cd
00901         bool is_fftodd = (nx % 2 == 1);
00902         if ( (nx-2*(!is_fftodd)) != output_x || ny != output_y || nz != output_z )
00903         {
00904                 FloatPoint origin( (nx-output_x)/2, (ny-output_y)/2, (nz-output_z)/2 );
00905                 FloatSize region_size( output_x, output_y, output_z);
00906                 Region clip_region( origin, region_size );
00907                 image->clip_inplace( clip_region );
00908         }
00909 
00910         // Should be an "if (verbose)" here or something
00911         //print_stats(quality_scores);
00912 
00913         image->update();
00914 
00915         return image;
00916 }
00917 
00918 
00919 void BaldwinWoolfordReconstructor::setup()
00920 {
00921         //This is a bit of a hack - but for now it suffices
00922         params.set_default("mode",1);
00923         FourierReconstructor::setup();
00924         // Set up the Baldwin Kernel
00925         int P = (int)((1.0+0.25)*max_input_dim+1);
00926         float r = (float)(max_input_dim+1)/(float)P;
00927         dfreq = 0.2f;
00928         if (W != 0) delete [] W;
00929         int maskwidth = params.set_default("maskwidth",2);
00930         W = Util::getBaldwinGridWeights(maskwidth, (float)P, r,dfreq,0.5f,0.2f);
00931 }
00932 
00933 EMData* BaldwinWoolfordReconstructor::finish()
00934 {
00935         tmp_data->write_image("density.mrc");
00936         image->process_inplace("xform.fourierorigin.tocorner");
00937         image->do_ift_inplace();
00938         image->depad();
00939         image->process_inplace("xform.phaseorigin.tocenter");
00940 
00941         if ( (bool) params.set_default("postmultiply", false) )
00942         {
00943                 cout << "POST MULTIPLYING" << endl;
00944         // now undo the Fourier convolution with real space division
00945                 float* d = image->get_data();
00946                 float N = (float) image->get_xsize()/2.0f;
00947                 N *= N;
00948                 size_t rnx = image->get_xsize();
00949                 size_t rny = image->get_ysize();
00950                 size_t rnxy = rnx*rny;
00951                 int cx = image->get_xsize()/2;
00952                 int cy = image->get_ysize()/2;
00953                 int cz = image->get_zsize()/2;
00954                 size_t idx;
00955                 for (int k = 0; k < image->get_zsize(); ++k ){
00956                         for (int j = 0; j < image->get_ysize(); ++j ) {
00957                                 for (int i =0; i < image->get_xsize(); ++i ) {
00958                                         float xd = (float)(i-cx); xd *= xd;
00959                                         float yd = (float)(j-cy); yd *= yd;
00960                                         float zd = (float)(k-cz); zd *= zd;
00961                                         float weight = exp((xd+yd+zd)/N);
00962                                         idx = k*rnxy + j*rnx + i;
00963                                         d[idx] *=  weight;
00964                                 }
00965                         }
00966                 }
00967         }
00968         image->update();
00969         return  image;
00970 }
00971 
00972 #include <iomanip>
00973 
00974 int BaldwinWoolfordReconstructor::insert_slice_weights(const Transform& t3d)
00975 {
00976         bool fftodd = image->is_fftodd();
00977         int rnx = nx-2*!fftodd;
00978 
00979         float y_scale = 1.0, x_scale = 1.0;
00980 
00981         if ( ny != rnx  )
00982         {
00983                 if ( rnx > ny ) y_scale = (float) rnx / (float) ny;
00984                 else x_scale = (float) ny / (float) rnx;
00985         }
00986 
00987         int tnx = tmp_data->get_xsize();
00988         int tny = tmp_data->get_ysize();
00989         int tnz = tmp_data->get_zsize();
00990 
00991         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
00992         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
00993                 Transform n3d = t3d*(*it);
00994 
00995                 for (int y = 0; y < tny; y++) {
00996                         for (int x = 0; x < tnx; x++) {
00997 
00998                                 float rx = (float) x;
00999                                 float ry = (float) y;
01000 
01001                                 if ( ny != rnx )
01002                                 {
01003                                         if ( rnx > ny ) ry *= y_scale;
01004                                         else rx *= x_scale;
01005                                 }
01006 //                              float xx = rx * n3d[0][0] + (ry - tny/2) * n3d[1][0];
01007 //                              float yy = rx * n3d[0][1] + (ry - tny/2) * n3d[1][1];
01008 //                              float zz = rx * n3d[0][2] + (ry - tny/2) * n3d[1][2];
01009 
01010                                 Vec3f coord(rx,(ry - tny/2),0);
01011                                 coord = coord*n3d; // transpose multiplication
01012                                 float xx = coord[0];
01013                                 float yy = coord[1];
01014                                 float zz = coord[2];
01015 
01016                                 if (xx < 0 ){
01017                                         xx = -xx;
01018                                         yy = -yy;
01019                                         zz = -zz;
01020                                 }
01021 
01022                                 yy += tny/2;
01023                                 zz += tnz/2;
01024                                 insert_density_at(xx,yy,zz);
01025                         }
01026                 }
01027         }
01028 
01029         return 0;
01030 }
01031 
01032 void BaldwinWoolfordReconstructor::insert_density_at(const float& x, const float& y, const float& z)
01033 {
01034         int xl = Util::fast_floor(x);
01035         int yl = Util::fast_floor(y);
01036         int zl = Util::fast_floor(z);
01037 
01038         // w is the windowing width
01039         int w = params.set_default("maskwidth",2);
01040         float wsquared = (float) w*w;
01041         float dw = 1.0f/w;
01042         dw *= dw;
01043 
01044         // w minus one - this control the number of
01045         // pixels/voxels to the left of the main pixel
01046         // that will have density
01047         int wmox = w-1;
01048         int wmoy = w-1;
01049         int wmoz = w-1;
01050 
01051         // If any coordinate is incedental with a vertex, then
01052         // make sure there is symmetry in density accruing.
01053         // i.e. the window width must be equal in both directions
01054         if ( ((float) xl) == x ) wmox = w;
01055         if ( ((float) yl) == y ) wmoy = w;
01056         if ( ((float) zl) == z ) wmoz = w;
01057 
01058         float* d = tmp_data->get_data();
01059         int tnx = tmp_data->get_xsize();
01060         int tny = tmp_data->get_ysize();
01061         int tnz = tmp_data->get_zsize();
01062         size_t tnxy = tnx*tny;
01063 
01064         int mode = params.set_default("mode",1);
01065 
01066         for(int k = zl-wmoz; k <= zl+w; ++k ) {
01067                 for(int j = yl-wmoy; j <= yl+w; ++j) {
01068                         for( int i = xl-wmox; i <= xl+w; ++i) {
01069                                 float fac = 1.0;
01070                                 int ic = i, jc = j, kc = k;
01071 
01072                                 // Fourier space is periodic, which is enforced
01073                                 // by the next 6 if statements. These if statements
01074                                 // assume that the Fourier DC components is at
01075                                 // (0,ny/2,nz/2).
01076                                 if ( i <= 0 ) {
01077 
01078                                         if ( x != 0 && i == 0 ) fac = 1.0;
01079                                         else if ( x == 0 && i < 0) continue;
01080 //                                      if (i < 0 ) ic = -i;
01081                                         if (i < 0 ) {
01082                                                 continue;
01083                                                 ic = -i;
01084                                                 jc = tny-jc;
01085                                                 kc = tnz-kc;
01086                                         }
01087                                 }
01088                                 if ( ic >= tnx ) ic = 2*tnx-ic-1;
01089                                 if ( jc < 0 ) jc = tny+jc;
01090                                 if ( jc >= tny ) jc = jc-tny;
01091                                 if ( kc < 0 ) kc = tnz+kc;
01092                                 if ( kc >= tnz ) kc = kc-tnz;
01093 //                              if ( ic >= tnx ) continue;
01094 //                              if ( jc < 0 ) continue;
01095 //                              if ( jc >= tny ) continue;
01096 //                              if ( kc < 0 ) continue;
01097 //                              if ( kc >= tnz ) continue;
01098                                 // This shouldn't happen
01099                                 // Debug remove later
01100                                 if ( ic < 0 ) { cout << "wo 1" << endl; }
01101                                 if ( ic >= tnx  ){ cout << "wo 2" << endl; }
01102                                 if ( jc < 0 ) { cout << "wo 3" << endl; }
01103                                 if ( jc >= tny ) { cout << "wo 4" << endl; }
01104                                 if ( kc < 0 ) { cout << "wo 5" << endl; }
01105                                 if ( kc >= tnz ) { cout << "wo 6" << endl; }
01106 
01107 
01108                                 float zd = (z-(float)k);
01109                                 float yd = (y-(float)j);
01110                                 float xd = (x-(float)i);
01111                                 zd *= zd; yd *= yd; xd *= xd;
01112                                 float distsquared = xd+yd+zd;
01113                                 // We enforce a spherical kernel
01114                                 if ( mode == 1 && distsquared > wsquared ) continue;
01115 
01116 //                              float f = fac*exp(-dw*(distsquared));
01117                                 float f = fac*exp(-2.467f*(distsquared));
01118                                 // Debug - this error should never occur.
01119                                 if ( (kc*tnxy+jc*tnx+ic) >= tnxy*tnz ) throw OutofRangeException(0,tnxy*tnz,kc*tnxy+jc*tnx+ic, "in density insertion" );
01120                                 d[kc*tnxy+jc*tnx+ic] += f;
01121                         }
01122                 }
01123         }
01124 }
01125 
01126 int BaldwinWoolfordReconstructor::insert_slice(const EMData* const input_slice, const Transform & t)
01127 {
01128         Transform * rotation;
01129         if ( input_slice->has_attr("xform.projection") ) {
01130                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
01131         } else {
01132                 rotation = new Transform(t); // assignment operator
01133         }
01134         Transform tmp(*rotation);
01135         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly
01136 
01137         Vec2f trans = tmp.get_trans_2d();
01138         float scale = tmp.get_scale();
01139         bool mirror = tmp.get_mirror();
01140         EMData* slice = 0;
01141         if (trans[0] != 0 || trans[1] != 0 || scale != 1.0 ) {
01142                 slice = input_slice->process("math.transform",Dict("transform",&tmp));
01143         } else if ( mirror == true ) {
01144                 slice = input_slice->process("xform.flip",Dict("axis","x"));
01145         }
01146         if ( slice == 0 ) {
01147                 slice = input_slice->process("xform.phaseorigin.tocorner");
01148         } else {
01149                 slice->process_inplace("xform.phaseorigin.tocorner");
01150         }
01151 
01152         slice->do_fft_inplace();
01153         slice->process_inplace("xform.fourierorigin.tocenter");
01154         float *dat = slice->get_data();
01155         float dt[2];
01156 
01157         bool fftodd = image->is_fftodd();
01158         int rnx = nx-2*!fftodd;
01159 
01160         float y_scale = 1.0, x_scale = 1.0;
01161 
01162         if ( ny != rnx  )
01163         {
01164                 if ( rnx > ny ) y_scale = (float) rnx / (float) ny;
01165                 else x_scale = (float) ny / (float) rnx;
01166         }
01167 
01168         int tnx = tmp_data->get_xsize();
01169         int tny = tmp_data->get_ysize();
01170         int tnz = tmp_data->get_zsize();
01171 
01172         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
01173 //      float weight = params.set_default("weight",1.0f);
01174 
01175         rotation->set_scale(1.0); rotation->set_mirror(false); rotation->set_trans(0,0,0);
01176         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
01177                 Transform t3d = (*rotation)*(*it);
01178 
01179                 for (int y = 0; y < tny; y++) {
01180                         for (int x = 0; x < tnx; x++) {
01181                                 float rx = (float) x;
01182                                 float ry = (float) y;
01183 
01184                                 if ( ny != rnx )
01185                                 {
01186                                         if ( rnx > ny ) ry *= y_scale;
01187                                         else rx *= x_scale;
01188                                 }
01189 
01190 //                              float xx = rx * n3d[0][0] + (ry - tny/2) * n3d[1][0];
01191 //                              float yy = rx * n3d[0][1] + (ry - tny/2) * n3d[1][1];
01192 //                              float zz = rx * n3d[0][2] + (ry - tny/2) * n3d[1][2];
01193 
01194                                 Vec3f coord(rx,(ry - tny/2),0);
01195                                 coord = coord*t3d; // transpose multiplication
01196                                 float xx = coord[0];
01197                                 float yy = coord[1];
01198                                 float zz = coord[2];
01199 
01200 
01201                                 float cc = 1;
01202                                 if (xx < 0 ){
01203                                         xx = -xx;
01204                                         yy = -yy;
01205                                         zz = -zz;
01206                                         cc = -1;
01207                                 }
01208 
01209                                 yy += tny/2;
01210                                 zz += tnz/2;
01211 
01212                                 int idx = x * 2 + y * (slice->get_xsize());
01213                                 dt[0] = dat[idx];
01214                                 dt[1] = cc * dat[idx+1];
01215 
01216                                 insert_pixel(xx,yy,zz,dt);
01217                         }
01218                 }
01219         }
01220 
01221         if(rotation) {delete rotation; rotation=0;}
01222         delete slice;
01223 
01224         return 0;
01225 }
01226 
01227 void BaldwinWoolfordReconstructor::insert_pixel(const float& x, const float& y, const float& z, const float dt[2])
01228 {
01229         int xl = Util::fast_floor(x);
01230         int yl = Util::fast_floor(y);
01231         int zl = Util::fast_floor(z);
01232 
01233         // w is the windowing width
01234         int w = params.set_default("maskwidth",2);
01235         float wsquared = (float) w*w;
01236         float dw = 1.0f/w;
01237         dw *= dw;
01238 
01239         int wmox = w-1;
01240         int wmoy = w-1;
01241         int wmoz = w-1;
01242 
01243         // If any coordinate is incedental with a vertex, then
01244         // make sure there is symmetry in density accruing.
01245         // i.e. the window width must be equal in both directions
01246         if ( ((float) xl) == x ) wmox = w;
01247         if ( ((float) yl) == y ) wmoy = w;
01248         if ( ((float) zl) == z ) wmoz = w;
01249 
01250         float* we = tmp_data->get_data();
01251         int tnx = tmp_data->get_xsize();
01252         int tny = tmp_data->get_ysize();
01253         int tnz = tmp_data->get_zsize();
01254         int tnxy = tnx*tny;
01255 
01256         int rnx = 2*tnx;
01257         int rnxy = 2*tnxy;
01258 
01259         int mode = params.set_default("mode",1);
01260 
01261         float* d = image->get_data();
01262         for(int k = zl-wmoz; k <= zl+w; ++k ) {
01263                 for(int j = yl-wmoy; j <= yl+w; ++j) {
01264                         for( int i = xl-wmox; i <= xl+w; ++i) {
01265                                 float fac = 1.0;
01266                                 int ic = i, jc = j, kc = k;
01267 
01268                                 // Fourier space is periodic, which is enforced
01269                                 // by the next 6 if statements. These if statements
01270                                 // assume that the Fourier DC component is at
01271                                 // (0,ny/2,nz/2).
01272                                 float negfac=1.0;
01273                                 if ( i <= 0 ) {
01274                                         if ( x != 0 && i == 0 ) fac = 1.0;
01275                                         else if ( x == 0 && i < 0) continue;
01276                                         if (i < 0 ) {
01277                                                 continue;
01278                                                 ic = -i;
01279                                                 jc = tny-jc;
01280                                                 kc = tnz-kc;
01281                                                 negfac=-1.0;
01282                                         }
01283                                 }
01284                                 if ( ic >= tnx ) ic = 2*tnx-ic-1;
01285                                 if ( jc < 0 ) jc = tny+jc;
01286                                 if ( jc >= tny ) jc = jc-tny;
01287                                 if ( kc < 0 ) kc = tnz+kc;
01288                                 if ( kc >= tnz ) kc = kc-tnz;
01289 //                              if ( ic >= tnx ) continue;
01290 //                              if ( jc < 0 ) continue;
01291 //                              if ( jc >= tny ) continue;
01292 //                              if ( kc < 0 ) continue;
01293 //                              if ( kc >= tnz ) continue;
01294 
01295                                 float zd = (z-(float)k);
01296                                 float yd = (y-(float)j);
01297                                 float xd = (x-(float)i);
01298                                 zd *= zd; yd *= yd; xd *= xd;
01299                                 float distsquared = xd+yd+zd;
01300 //                              float f = fac*exp(-dw*(distsquared));
01301                                 float f = fac*exp(-2.467f*(distsquared));
01302                                 float weight = f/we[kc*tnxy+jc*tnx+ic];
01303                                 // debug - this error should never occur
01304                                 if ( (kc*rnxy+jc*rnx+2*ic+1) >= rnxy*tnz ) throw OutofRangeException(0,rnxy*tnz,kc*rnxy+jc*rnx+2*ic+1, "in pixel insertion" );
01305                                 size_t k = kc*rnxy+jc*rnx+2*ic;
01306 
01307                                 float factor, dist,residual;
01308                                 int sizeW,sizeWmid,idx;
01309                                 switch (mode) {
01310                                         case 0:
01311                                                 d[k] += weight*f*dt[0];
01312                                                 d[k+1] += negfac*weight*f*dt[1];
01313                                                 cout << "hello" << endl;
01314                                         break;
01315 
01316                                         case 1:
01317                                                 // We enforce a spherical kernel
01318                                                 if ( distsquared > wsquared ) continue;
01319 
01320                                                 sizeW = (int)(1+2*w/dfreq);
01321                                                 sizeWmid = sizeW/2;
01322 
01323                                                 dist = sqrtf(distsquared);
01324                                                 idx = (int)(sizeWmid + dist/dfreq);
01325                                                 if (idx >= sizeW) throw InvalidValueException(idx, "idx was greater than or equal to sizeW");
01326                                                 residual = dist/dfreq - (int)(dist/dfreq);
01327                                                 if ( fabs(residual) > 1) throw InvalidValueException(residual, "Residual was too big");
01328 
01329                                                 factor = (W[idx]*(1.0f-residual)+W[idx+1]*residual)*weight;
01330 
01331                                                 d[k] += dt[0]*factor;
01332                                                 d[k+1] += dt[1]*factor;
01333                                         break;
01334 
01335                                         default:
01336                                                 throw InvalidValueException(mode, "The mode was unsupported in BaldwinWoolfordReconstructor::insert_pixel");
01337                                         break;
01338                                 }
01339                         }
01340                 }
01341         }
01342 }
01343 
01344 // void BaldwinWoolfordReconstructor::insert_pixel(const float& x, const float& y, const float& z, const float dt[2])
01345 // {
01346 //      int xl = Util::fast_floor(x);
01347 //      int yl = Util::fast_floor(y);
01348 //      int zl = Util::fast_floor(z);
01349 //
01350 //      // w is the windowing width
01351 //      int w = params.set_default("maskwidth",2);
01352 //      float dw = 1.0/w;
01353 //      dw *= dw;
01354 // //   dw = 2;
01355 // //   cout << w << endl;
01356 //      //      int w = 3;
01357 //      // w minus one - this control the number of
01358 //      // pixels/voxels to the left of the main pixel
01359 //      // that will have density
01360 //      int wmox = w-1;
01361 //      int wmoy = w-1;
01362 //      int wmoz = w-1;
01363 //
01364 //      // If any coordinate is incedental with a vertex, then
01365 //      // make sure there is symmetry in density accruing.
01366 //      // i.e. the window width must be equal in both directions
01367 //      if ( ((float) xl) == x ) wmox = w;
01368 //      if ( ((float) yl) == y ) wmoy = w;
01369 //      if ( ((float) zl) == z ) wmoz = w;
01370 //
01371 //      float* d = tmp_data->get_data();
01372 //      int tnx = tmp_data->get_xsize();
01373 //      int tny = tmp_data->get_ysize();
01374 //      int tnz = tmp_data->get_zsize();
01375 //      int tnxy = tnx*tny;
01376 //
01377 //      float weight = 1.0;
01378 // //
01379 //      for(int k = zl-wmoz; k <= zl+w; ++k ) {
01380 //              for(int j = yl-wmoy; j <= yl+w; ++j) {
01381 //                      for( int i = xl-wmox; i <= xl+w; ++i) {
01382 //                              float fac = 1.0;
01383 //                              int ic = i, jc = j, kc = k;
01384 //
01385 //                              // Fourier space is periodic, which is enforced
01386 //                              // by the next 6 if statements. These if statements
01387 //                              // assume that the Fourier DC components is at
01388 //                              // (0,ny/2,nz/2).
01389 //                              if ( i <= 0 ) {
01390 //                                      if ( x != 0 && i == 0 ) fac = 1.0;
01391 //                                      else if ( x == 0 && i < 0) continue;
01392 // //                                   if (i < 0 ) ic = -i;
01393 //                                      if (i < 0 ) {
01394 //                                              ic = -i;
01395 //                                              jc = tny-jc;
01396 //                                              kc = tnz-kc;
01397 //                                      }
01398 //                              }
01399 //                              if ( ic >= tnx ) ic = 2*tnx-ic-1;
01400 //                              if ( jc < 0 ) jc = tny+jc;
01401 //                              if ( jc >= tny ) jc = jc-tny;
01402 //                              if ( kc < 0 ) kc = tnz+kc;
01403 //                              if ( kc >= tnz ) kc = kc-tnz;
01404 //                              // This shouldn't happen
01405 //                              // Debug remove later
01406 //                              if ( ic < 0 ) { cout << "wo 1" << endl; }
01407 //                              if ( ic >= tnx  ){ cout << "wo 2" << endl; }
01408 //                              if ( jc < 0 ) { cout << "wo 3" << endl; }
01409 //                              if ( jc >= tny ) { cout << "wo 4" << endl; }
01410 //                              if ( kc < 0 ) { cout << "wo 5" << endl; }
01411 //                              if ( kc >= tnz ) { cout << "wo 6" << endl; }
01412 //
01413 //
01414 //                              float zd = (z-(float)k);
01415 //                              float yd = (y-(float)j);
01416 //                              float xd = (x-(float)i);
01417 //                              zd *= zd; yd *= yd; xd *= xd;
01418 //                              // Debug - this error should never occur.
01419 //                              if ( (kc*tnxy+jc*tnx+ic) >= tnxy*tnz ) throw OutofRangeException(0,tnxy*tnz,kc*tnxy+jc*tnx+ic, "in weight determination insertion" );
01420 // //                           float f = fac*exp(-dw*(xd+yd+zd)*0.5);
01421 //                              float f = exp(-2.467*(xd+yd+zd));
01422 //                              weight += f*(d[kc*tnxy+jc*tnx+ic] - f);
01423 //                      }
01424 //              }
01425 //      }
01426 //      weight = 1.0/weight;
01427 //      int rnx = 2*tnx;
01428 //      int rnxy = 2*tnxy;
01429 //      d = image->get_data();
01430 //      for(int k = zl-wmoz; k <= zl+w; ++k ) {
01431 //              for(int j = yl-wmoy; j <= yl+w; ++j) {
01432 //                      for( int i = xl-wmox; i <= xl+w; ++i) {
01433 //                              float fac = 1.0;
01434 //                              int ic = i, jc = j, kc = k;
01435 //
01436 //                              // Fourier space is periodic, which is enforced
01437 //                              // by the next 6 if statements. These if statements
01438 //                              // assume that the Fourier DC components is at
01439 //                              // (0,ny/2,nz/2).
01440 //                              float negfac=1.0;
01441 //                              if ( i <= 0 ) {
01442 //                                      if ( x != 0 && i == 0 ) fac = 1.0;
01443 //                                      else if ( x == 0 && i < 0) continue;
01444 //                                      if (i < 0 ) {
01445 //                                              continue;
01446 //                                              ic = -i;
01447 //                                              jc = tny-jc;
01448 //                                              kc = tnz-kc;
01449 //                                              negfac=-1.0;
01450 //                                      }
01451 //                              }
01452 //                              if ( ic >= tnx ) ic = 2*tnx-ic-1;
01453 //                              if ( jc < 0 ) jc = tny+jc;
01454 //                              if ( jc >= tny ) jc = jc-tny;
01455 //                              if ( kc < 0 ) kc = tnz+kc;
01456 //                              if ( kc >= tnz ) kc = kc-tnz;
01457 //                              // This shouldn't happen
01458 //                              // Debug remove later
01459 //
01460 //
01461 //                              float zd = (z-(float)k);
01462 //                              float yd = (y-(float)j);
01463 //                              float xd = (x-(float)i);
01464 //                              zd *= zd; yd *= yd; xd *= xd;
01465 // //                           float f = fac*exp(-dw*(xd+yd+zd));
01466 //                              float f = exp(-4.934*(xd+yd+zd));
01467 //                              // Debug - this error should never occur.
01468 //                              if ( (kc*rnxy+jc*rnx+2*ic+1) >= rnxy*tnz ) throw OutofRangeException(0,rnxy*tnz,kc*rnxy+jc*rnx+2*ic+1, "in pixel insertion" );
01469 //
01470 //                              d[kc*rnxy+jc*rnx+2*ic] += weight*f*dt[0];
01471 //                              d[kc*rnxy+jc*rnx+2*ic+1] += negfac*weight*f*dt[1];
01472 //                      }
01473 //              }
01474 //      }
01475 // }
01476 
01477 
01478 void WienerFourierReconstructor::setup()
01479 {
01480         int size = params["size"];
01481         image = new EMData();
01482         image->set_size(size + 2, size, size);
01483         image->set_complex(true);
01484         image->set_ri(true);
01485 
01486         nx = image->get_xsize();
01487         ny = image->get_ysize();
01488         nz = image->get_zsize();
01489 
01490         int n = nx * ny * nz;
01491         float *rdata = image->get_data();
01492 
01493         for (int i = 0; i < n; i += 2) {
01494                 float f = Util::get_frand(0.0, 2.0 * M_PI);
01495                 rdata[i] = 1.0e-10f * sin(f);
01496                 rdata[i + 1] = 1.0e-10f * cos(f);
01497         }
01498         image->update();
01499 
01500         tmp_data = new EMData();
01501         tmp_data->set_size(size + 1, size, size);
01502 }
01503 
01504 
01505 EMData *WienerFourierReconstructor::finish()
01506 {
01507         float *norm = tmp_data->get_data();
01508         float *rdata = image->get_data();
01509 
01510         size_t size = nx * ny * nz;
01511         for (size_t i = 0; i < size; i += 2) {
01512                 float d = norm[i];
01513                 if (d == 0) {
01514                         rdata[i] = 0;
01515                         rdata[i + 1] = 0;
01516                 }
01517                 else {
01518                         float w = 1 + 1 / d;
01519                         rdata[i] /= d * w;
01520                         rdata[i + 1] /= d * w;
01521                 }
01522         }
01523 
01524         if( tmp_data ) {
01525                 delete tmp_data;
01526                 tmp_data = 0;
01527         }
01528         image->update();
01529         return image;
01530 }
01531 
01532 
01533 int WienerFourierReconstructor::insert_slice(const EMData* const slice, const Transform3D & euler)
01534 {
01535         if (!slice) {
01536                 LOGERR("try to insert NULL slice");
01537                 return 1;
01538         }
01539 
01540         int mode = params["mode"];
01541         float padratio = params["padratio"];
01542         vector < float >snr = params["snr"];
01543 
01544         if (!slice->is_complex()) {
01545                 LOGERR("Only complex slice can be inserted.");
01546                 return 1;
01547         }
01548         float *gimx = 0;
01549         if (mode == 5) {
01550                 gimx = Interp::get_gimx();
01551         }
01552 
01553         int nxy = nx * ny;
01554         int off[8] = {0,0,0,0,0,0,0,0};
01555         if (mode == 2) {
01556                 off[0] = 0;
01557                 off[1] = 2;
01558                 off[2] = nx;
01559                 off[3] = nx + 2;
01560                 off[4] = nxy;
01561                 off[5] = nxy + 2;
01562                 off[6] = nxy + nx;
01563                 off[7] = nxy + nx + 2;
01564         }
01565 
01566         float *norm = tmp_data->get_data();
01567         float *dat = slice->get_data();
01568         float *rdata = image->get_data();
01569 
01570         int rl = Util::square(ny / 2 - 1);
01571         float dt[2];
01572         float g[8];
01573 
01574         for (int y = 0; y < ny; y++) {
01575                 for (int x = 0; x < nx / 2; x++) {
01576                         if ((x * x + Util::square(y - ny / 2)) >= rl)
01577                         {
01578                                 continue;
01579                         }
01580 
01581 #ifdef _WIN32
01582                         int r = Util::round((float)_hypot(x, (float) y - ny / 2) * Ctf::CTFOS / padratio);
01583 #else
01584                         int r = Util::round((float)hypot(x, (float) y - ny / 2) * Ctf::CTFOS / padratio);
01585 #endif
01586                         if (r >= Ctf::CTFOS * ny / 2) {
01587                                 r = Ctf::CTFOS * ny / 2 - 1;
01588                         }
01589 
01590                         float weight = snr[r];
01591 
01592                         float xx = (x * euler[0][0] + (y - ny / 2) * euler[0][1]);
01593                         float yy = (x * euler[1][0] + (y - ny / 2) * euler[1][1]);
01594                         float zz = (x * euler[2][0] + (y - ny / 2) * euler[2][1]);
01595                         float cc = 1;
01596 
01597                         if (xx < 0) {
01598                                 xx = -xx;
01599                                 yy = -yy;
01600                                 zz = -zz;
01601                                 cc = -1.0;
01602                         }
01603 
01604                         yy += ny / 2;
01605                         zz += nz / 2;
01606 
01607                         dt[0] = dat[x * 2 + y * nx] * (1 + 1.0f / weight);
01608                         dt[1] = cc * dat[x * 2 + 1 + y * nx] * (1 + 1.0f / weight);
01609 
01610                         int x0 = 0;
01611                         int y0 = 0;
01612                         int z0 = 0;
01613                         int i = 0;
01614                         int l = 0;
01615                         float dx = 0;
01616                         float dy = 0;
01617                         float dz = 0;
01618 
01619                         int mx0 = 0;
01620                         int my0 = 0;
01621                         int mz0 = 0;
01622 
01623                         size_t idx;
01624                         switch (mode) {
01625                         case 1:
01626                                 x0 = 2 * (int) floor(xx + 0.5f);
01627                                 y0 = (int) floor(yy + 0.5f);
01628                                 z0 = (int) floor(zz + 0.5f);
01629 
01630                                 rdata[x0 + y0 * nx + z0 * nxy] += weight * dt[0];
01631                                 rdata[x0 + y0 * nx + z0 * nxy + 1] += weight * dt[1];
01632                                 norm[x0 + y0 * nx + z0 * nxy] += weight;
01633                                 break;
01634 
01635                         case 2:
01636                                 x0 = (int) floor(xx);
01637                                 y0 = (int) floor(yy);
01638                                 z0 = (int) floor(zz);
01639 
01640                                 dx = xx - x0;
01641                                 dy = yy - y0;
01642                                 dz = zz - z0;
01643 
01644                                 weight /= (float)pow((float)(EMConsts::I2G * M_PI), 1.5f);
01645 
01646                                 if (x0 > nx - 2 || y0 > ny - 1 || z0 > nz - 1) {
01647                                         break;
01648                                 }
01649 
01650                                 i = (int) (x0 * 2 + y0 * nx + z0 * nxy);
01651 
01652 
01653                                 g[0] = Util::agauss(1, dx, dy, dz, EMConsts::I2G);
01654                                 g[1] = Util::agauss(1, 1 - dx, dy, dz, EMConsts::I2G);
01655                                 g[2] = Util::agauss(1, dx, 1 - dy, dz, EMConsts::I2G);
01656                                 g[3] = Util::agauss(1, 1 - dx, 1 - dy, dz, EMConsts::I2G);
01657                                 g[4] = Util::agauss(1, dx, dy, 1 - dz, EMConsts::I2G);
01658                                 g[5] = Util::agauss(1, 1 - dx, dy, 1 - dz, EMConsts::I2G);
01659                                 g[6] = Util::agauss(1, dx, 1 - dy, 1 - dz, EMConsts::I2G);
01660                                 g[7] = Util::agauss(1, 1 - dx, 1 - dy, 1 - dz, EMConsts::I2G);
01661 
01662                                 for (int j = 0; j < 8; j++) {
01663                                         int k = i + off[j];
01664                                         rdata[k] += weight * dt[0] * g[j];
01665                                         rdata[k + 1] += weight * dt[1] * g[j];
01666                                         norm[k] += weight * g[j];
01667                                 }
01668 
01669                                 break;
01670                         case 3:
01671                                 x0 = 2 * (int) floor(xx + 0.5f);
01672                                 y0 = (int) floor(yy + 0.5f);
01673                                 z0 = (int) floor(zz + 0.5f);
01674 
01675                                 weight /= (float)pow((float)(EMConsts::I3G * M_PI), 1.5f);
01676 
01677                                 if (x0 >= nx - 4 || y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2) {
01678                                         break;
01679                                 }
01680 
01681                                 l = x0 - 2;
01682                                 if (x0 == 0) {
01683                                         l = x0;
01684                                 }
01685 
01686                                 for (int k = z0 - 1; k <= z0 + 1; k++) {
01687                                         for (int j = y0 - 1; j <= y0 + 1; j++) {
01688                                                 for (int i = l; i <= x0 + 2; i += 2) {
01689                                                         float r = Util::hypot3((float) i / 2 - xx, j - yy, k - zz);
01690                                                         float gg = exp(-r / EMConsts::I3G);
01691 
01692                                                         idx = i + j * nx + k * nxy;
01693                                                         rdata[idx] += weight * gg * dt[0];
01694                                                         rdata[idx + 1] += weight * gg * dt[1];
01695                                                         norm[idx] += weight * gg;
01696                                                 }
01697                                         }
01698                                 }
01699                                 break;
01700 
01701                         case 4:
01702                                 x0 = 2 * (int) floor(xx);
01703                                 y0 = (int) floor(yy);
01704                                 z0 = (int) floor(zz);
01705 
01706                                 weight /= (float)pow((float)(EMConsts::I4G * M_PI), 1.5f);
01707 
01708                                 if (x0 >= nx - 4 || y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2) {
01709                                         break;
01710                                 }
01711 
01712                                 l = x0 - 2;
01713                                 if (x0 == 0) {
01714                                         l = x0;
01715                                 }
01716 
01717                                 for (int k = z0 - 1; k <= z0 + 2; ++k) {
01718                                         for (int j = y0 - 1; j <= y0 + 2; ++j) {
01719                                                 for (int i = l; i <= x0 + 4; i += 2) {
01720                                                         float r = Util::hypot3((float) i / 2 - xx, j - yy, k - zz);
01721                                                         float gg = exp(-r / EMConsts::I4G);
01722 
01723                                                         idx = i + j * nx + k * nxy;
01724                                                         rdata[idx] += weight * gg * dt[0];
01725                                                         rdata[idx + 1] += weight * gg * dt[1];
01726                                                         norm[idx] += weight * gg;
01727                                                 }
01728                                         }
01729                                 }
01730                                 break;
01731 
01732                         case 5:
01733                                 x0 = (int) floor(xx + .5);
01734                                 y0 = (int) floor(yy + .5);
01735                                 z0 = (int) floor(zz + .5);
01736 
01737                                 weight /= (float)pow((float)(EMConsts::I5G * M_PI), 1.5f);
01738 
01739                                 mx0 = -(int) floor((xx - x0) * 39.0f + 0.5) - 78;
01740                                 my0 = -(int) floor((yy - y0) * 39.0f + 0.5) - 78;
01741                                 mz0 = -(int) floor((zz - z0) * 39.0f + 0.5) - 78;
01742                                 x0 *= 2;
01743 
01744                                 if (x0 >= nx - 4 || y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01745                                         break;
01746 
01747                                 if (x0 == 0) {
01748                                         l = 0;
01749                                         mx0 += 78;
01750                                 }
01751                                 else if (x0 == 2) {
01752                                         l = 0;
01753                                         mx0 += 39;
01754                                 }
01755                                 else
01756                                         l = x0 - 4;
01757                                 for (int k = z0 - 2, mmz = mz0; k <= z0 + 2; k++, mmz += 39) {
01758                                         for (int j = y0 - 2, mmy = my0; j <= y0 + 2; j++, mmy += 39) {
01759                                                 for (int i = l, mmx = mx0; i <= x0 + 4; i += 2, mmx += 39) {
01760                                                         size_t ii = i + j * nx + k * nxy;
01761                                                         float gg = weight * gimx[abs(mmx) + abs(mmy) * 100 + abs(mmz) * 10000];
01762 
01763                                                         rdata[ii] += gg * dt[0];
01764                                                         rdata[ii + 1] += gg * dt[1];
01765                                                         norm[ii] += gg;
01766                                                 }
01767                                         }
01768                                 }
01769 
01770                                 if (x0 <= 2) {
01771                                         xx = -xx;
01772                                         yy = -(yy - ny / 2) + ny / 2;
01773                                         zz = -(zz - nz / 2) + nz / 2;
01774                                         x0 = (int) floor(xx + 0.5f);
01775                                         y0 = (int) floor(yy + 0.5f);
01776                                         z0 = (int) floor(zz + 0.5f);
01777                                         int mx0 = -(int) floor((xx - x0) * 39.0f + .5);
01778                                         x0 *= 2;
01779 
01780                                         if (y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01781                                                 break;
01782 
01783                                         for (int k = z0 - 2, mmz = mz0; k <= z0 + 2; k++, mmz += 39) {
01784                                                 for (int j = y0 - 2, mmy = my0; j <= y0 + 2; j++, mmy += 39) {
01785                                                         for (int i = 0, mmx = mx0; i <= x0 + 4; i += 2, mmx += 39) {
01786                                                                 size_t ii = i + j * nx + k * nxy;
01787                                                                 float gg =
01788                                                                         weight * gimx[abs(mmx) + abs(mmy) * 100 + abs(mmz) * 10000];
01789 
01790                                                                 rdata[ii] += gg * dt[0];
01791                                                                 rdata[ii + 1] -= gg * dt[1];
01792                                                                 norm[ii] += gg;
01793                                                         }
01794                                                 }
01795                                         }
01796                                 }
01797                                 break;
01798                                 // mode 6 is now mode 5 without the fast interpolation
01799                         case 6:
01800                                 x0 = 2 * (int) floor(xx + .5);
01801                                 y0 = (int) floor(yy + .5);
01802                                 z0 = (int) floor(zz + .5);
01803 
01804                                 weight /= (float)pow((float)(EMConsts::I5G * M_PI), 1.5f);
01805 
01806                                 if (x0 >= nx - 4 || y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01807                                         break;
01808 
01809                                 if (x0 <= 2)
01810                                         l = 0;
01811                                 else
01812                                         l = x0 - 4;
01813                                 for (int k = z0 - 2; k <= z0 + 2; ++k) {
01814                                         for (int j = y0 - 2; j <= y0 + 2; ++j) {
01815                                                 for (int i = l; i <= x0 + 4; i += 2) {
01816                                                         size_t ii = i + j * nx + k * nxy;
01817                                                         float r = Util::hypot3((float) i / 2 - xx, (float) j - yy,
01818                                                                                                    (float) k - zz);
01819                                                         float gg = weight * exp(-r / EMConsts::I5G);
01820 
01821                                                         rdata[ii] += gg * dt[0];
01822                                                         rdata[ii + 1] += gg * dt[1];
01823                                                         norm[ii] += gg;
01824                                                 }
01825                                         }
01826                                 }
01827 
01828                                 if (x0 <= 2) {
01829                                         xx = -xx;
01830                                         yy = -(yy - ny / 2) + ny / 2;
01831                                         zz = -(zz - nz / 2) + nz / 2;
01832                                         x0 = 2 * (int) floor(xx + 0.5f);
01833                                         y0 = (int) floor(yy + 0.5f);
01834                                         z0 = (int) floor(zz + 0.5f);
01835 
01836                                         if (y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01837                                                 break;
01838 
01839                                         for (int k = z0 - 2; k <= z0 + 2; ++k) {
01840                                                 for (int j = y0 - 2; j <= y0 + 2; ++j) {
01841                                                         for (int i = 0; i <= x0 + 4; i += 2) {
01842                                                                 size_t ii = i + j * nx + k * nxy;
01843                                                                 float r = Util::hypot3((float) i / 2 - xx, (float) j - yy,
01844                                                                                                            (float) k - zz);
01845                                                                 float gg = weight * exp(-r / EMConsts::I5G);
01846 
01847                                                                 rdata[ii] += gg * dt[0];
01848                                                                 rdata[ii + 1] -= gg * dt[1];    // note the -, complex conj.
01849                                                                 norm[ii] += gg;
01850                                                         }
01851                                                 }
01852                                         }
01853                                 }
01854                                 break;
01855 
01856                         case 7:
01857                                 x0 = 2 * (int) floor(xx + .5);
01858                                 y0 = (int) floor(yy + .5);
01859                                 z0 = (int) floor(zz + .5);
01860 
01861                                 if (x0 >= nx - 4 || y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01862                                         break;
01863 
01864                                 if (x0 <= 2)
01865                                         l = 0;
01866                                 else
01867                                         l = x0 - 4;
01868                                 for (int k = z0 - 2; k <= z0 + 2; k++) {
01869                                         for (int j = y0 - 2; j <= y0 + 2; j++) {
01870                                                 for (int i = l; i <= x0 + 4; i += 2) {
01871                                                         size_t ii = i + j * nx + k * nxy;
01872                                                         float r = (float)sqrt(Util::hypot3((float) i / 2 - xx,
01873                                                                                                                            (float) j - yy,
01874                                                                                                                            (float) k - zz));
01875                                                         float gg = weight * Interp::hyperg(r);
01876 
01877                                                         rdata[ii] += gg * dt[0];
01878                                                         rdata[ii + 1] += gg * dt[1];
01879                                                         norm[ii] += gg;
01880                                                 }
01881                                         }
01882                                 }
01883 
01884                                 if (x0 <= 2) {
01885                                         xx = -xx;
01886                                         yy = -(yy - ny / 2) + ny / 2;
01887                                         zz = -(zz - nz / 2) + nz / 2;
01888                                         x0 = 2 * (int) floor(xx + .5);
01889                                         y0 = (int) floor(yy + .5);
01890                                         z0 = (int) floor(zz + .5);
01891 
01892                                         if (y0 > ny - 3 || z0 > nz - 3 || y0 < 2 || z0 < 2)
01893                                                 break;
01894 
01895                                         for (int k = z0 - 2; k <= z0 + 2; ++k) {
01896                                                 for (int j = y0 - 2; j <= y0 + 2; ++j) {
01897                                                         for (int i = 0; i <= x0 + 4; i += 2) {
01898                                                                 size_t ii = i + j * nx + k * nxy;
01899                                                                 float r = sqrt(Util::hypot3((float) i / 2 - xx, (float) j - yy,
01900                                                                                                                         (float) k - zz));
01901                                                                 float gg = weight * Interp::hyperg(r);
01902 
01903                                                                 rdata[ii] += gg * dt[0];
01904                                                                 rdata[ii + 1] -= gg * dt[1];
01905                                                                 norm[ii] += gg;
01906                                                         }
01907                                                 }
01908                                         }
01909                                 }
01910                                 break;
01911                         }
01912 
01913                 }
01914         }
01915 
01916         image->update();
01917         tmp_data->update();
01918 //      slice->update();
01919 
01920         return 0;
01921 }
01922 
01923 void BackProjectionReconstructor::setup()
01924 {
01925         int size = params["size"];
01926         image = new EMData();
01927         nx = size;
01928         ny = size;
01929         if ( (int) params["zsample"] != 0 ) nz = params["zsample"];
01930         else nz = size;
01931         image->set_size(nx, ny, nz);
01932 }
01933 
01934 EMData* BackProjectionReconstructor::preprocess_slice(const EMData* const slice, const Transform& t)
01935 {
01936 
01937         EMData* return_slice = slice->process("normalize.edgemean");
01938         return_slice->process_inplace("filter.linearfourier");
01939 
01940         Transform tmp(t);
01941         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly
01942         Vec2f trans = tmp.get_trans_2d();
01943         float scale = tmp.get_scale();
01944         bool mirror = tmp.get_mirror();
01945         if (trans[0] != 0 || trans[1] != 0 || scale != 1.0 ) {
01946                 return_slice->transform(tmp);
01947         } else if ( mirror == true ) {
01948                 return_slice = slice->process("xform.flip",Dict("axis","x"));
01949         }
01950 
01951         return return_slice;
01952 }
01953 
01954 int BackProjectionReconstructor::insert_slice(const EMData* const input, const Transform &t)
01955 {
01956         if (!input) {
01957                 LOGERR("try to insert NULL slice");
01958                 return 1;
01959         }
01960 
01961         if (input->get_xsize() != input->get_ysize() || input->get_xsize() != nx) {
01962                 LOGERR("tried to insert image that was not correction dimensions");
01963                 return 1;
01964         }
01965 
01966         Transform * transform;
01967         if ( input->has_attr("xform.projection") ) {
01968                 transform = (Transform*) (input->get_attr("xform.projection")); // assignment operator
01969         } else {
01970                 transform = new Transform(t); // assignment operator
01971         }
01972         EMData* slice = preprocess_slice(input, t);
01973 
01974         float weight = params["weight"];
01975         slice->mult(weight);
01976 
01977         EMData *tmp = new EMData();
01978         tmp->set_size(nx, ny, nz);
01979 
01980         float *slice_data = slice->get_data();
01981         float *tmp_data = tmp->get_data();
01982 
01983         size_t nxy = nx * ny;
01984         size_t nxy_size = nxy * sizeof(float);;
01985         for (int i = 0; i < nz; ++i) {
01986                 memcpy(&tmp_data[nxy * i], slice_data, nxy_size);
01987         }
01988 
01989         transform->set_scale(1.0);
01990         transform->set_mirror(false);
01991         transform->set_trans(0,0,0);
01992         transform->invert();
01993 
01994         tmp->transform(*transform);
01995         image->add(*tmp);
01996 
01997         if(transform) {delete transform; transform=0;}
01998         delete tmp;
01999         delete slice;
02000 
02001         return 0;
02002 }
02003 
02004 EMData *BackProjectionReconstructor::finish()
02005 {
02006 
02007         Symmetry3D* sym = Factory<Symmetry3D>::get((string)params["sym"]);
02008         vector<Transform> syms = sym->get_syms();
02009 
02010         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
02011 
02012                 EMData tmpcopy(*image);
02013                 tmpcopy.transform(*it);
02014                 image->add(tmpcopy);
02015         }
02016 
02017         image->mult(1.0f/(float)sym->get_nsym());
02018         delete sym;
02019         return image;
02020 }
02021 
02022 EMData* EMAN::padfft_slice( const EMData* const slice, const Transform& t, int npad )
02023 {
02024         int nx = slice->get_xsize();
02025         int ny = slice->get_ysize();
02026         int ndim = (ny==1) ? 1 : 2;
02027 
02028         if( ndim==2 && nx!=ny )
02029         {
02030                 // FIXME: What kind of exception should we throw here?
02031                 throw std::runtime_error("Tried to padfft a 2D slice which is not square.");
02032         }
02033 
02034         // process 2D slice or 1D line -- subtract the average outside of the circle, zero-pad, fft extend, and fft
02035         EMData* temp = slice->average_circ_sub();
02036 
02037         Assert( temp != NULL );
02038         EMData* zeropadded = temp->norm_pad( false, npad );
02039         Assert( zeropadded != NULL );
02040         checked_delete( temp );
02041 
02042         zeropadded->do_fft_inplace();
02043         EMData* padfftslice = zeropadded;
02044 
02045         // shift the projection
02046         Vec2f trans = t.get_trans_2d();
02047         float sx = -trans[0];
02048         float sy = -trans[1];
02049         if(sx != 0.0f || sy != 0.0)
02050                 padfftslice->process_inplace("filter.shift", Dict("x_shift", sx, "y_shift", sy, "z_shift", 0.0f));
02051 
02052         int remove = slice->get_attr_default("remove", 0);
02053         padfftslice->set_attr( "remove", remove );
02054 
02055 
02056 
02057         padfftslice->center_origin_fft();
02058         return padfftslice;
02059 }
02060 
02061 nn4Reconstructor::nn4Reconstructor()
02062 {
02063     m_volume = NULL;
02064     m_wptr   = NULL;
02065     m_result = NULL;
02066 }
02067 
02068 nn4Reconstructor::nn4Reconstructor( const string& symmetry, int size, int npad )
02069 {
02070     m_volume = NULL;
02071     m_wptr   = NULL;
02072     m_result = NULL;
02073         setup( symmetry, size, npad );
02074         load_default_settings();
02075         print_params();
02076 }
02077 
02078 nn4Reconstructor::~nn4Reconstructor()
02079 {
02080     if( m_delete_volume )
02081         checked_delete(m_volume);
02082 
02083     if( m_delete_weight )
02084         checked_delete( m_wptr );
02085 
02086     checked_delete( m_result );
02087 }
02088 
02089 enum weighting_method { NONE, ESTIMATE, VORONOI };
02090 
02091 float max2d( int kc, const vector<float>& pow_a )
02092 {
02093         float max = 0.0;
02094         for( int i=-kc; i <= kc; ++i ) {
02095                 for( int j=-kc; j <= kc; ++j ) {
02096                         if( i==0 && j==0 ) continue;
02097                         {
02098                                 int c = 2*kc+1 - std::abs(i) - std::abs(j);
02099                                 max = max + pow_a[c];
02100                         }
02101                 }
02102         }
02103         return max;
02104 }
02105 
02106 float max3d( int kc, const vector<float>& pow_a )
02107 {
02108         float max = 0.0;
02109         for( int i=-kc; i <= kc; ++i ) {
02110                 for( int j=-kc; j <= kc; ++j ) {
02111                         for( int k=-kc; k <= kc; ++k ) {
02112                                 if( i==0 && j==0 && k==0 ) continue;
02113                                 // if( i!=0 )
02114                                 {
02115                                         int c = 3*kc+1 - std::abs(i) - std::abs(j) - std::abs(k);
02116                                         max = max + pow_a[c];
02117                                         // max = max + c * c;
02118                                         // max = max + c;
02119                                 }
02120                         }
02121                 }
02122         }
02123         return max;
02124 }
02125 
02126 
02127 void nn4Reconstructor::setup()
02128 {
02129         int size = params["size"];
02130         int npad = params["npad"];
02131 
02132 
02133         string symmetry;
02134         if( params.has_key("symmetry") ) {
02135                 symmetry = params["symmetry"].to_str();
02136         } else {
02137                 symmetry = "c1";
02138         }
02139 
02140         if( params.has_key("ndim") ) {
02141             m_ndim = params["ndim"];
02142         } else {
02143                 m_ndim = 3;
02144         }
02145 
02146     if( params.has_key( "snr" ) ) {
02147         m_osnr = 1.0f/float( params["snr"] );
02148     } else {
02149         m_osnr = 0.0;
02150     }
02151 
02152         setup( symmetry, size, npad );
02153 }
02154 
02155 void nn4Reconstructor::setup( const string& symmetry, int size, int npad )
02156 {
02157         m_weighting = ESTIMATE;
02158         m_wghta = 0.2f;
02159 
02160         m_symmetry = symmetry;
02161         m_npad = npad;
02162         m_nsym = Transform::get_nsym(m_symmetry);
02163 
02164         m_vnx = size;
02165         m_vny = size;
02166         m_vnz = (m_ndim==3) ? size : 1;
02167 
02168         m_vnxp = size*npad;
02169         m_vnyp = size*npad;
02170         m_vnzp = (m_ndim==3) ? size*npad : 1;
02171 
02172         m_vnxc = m_vnxp/2;
02173         m_vnyc = m_vnyp/2;
02174         m_vnzc = (m_ndim==3) ? m_vnzp/2 : 1;
02175 
02176         buildFFTVolume();
02177         buildNormVolume();
02178 
02179 }
02180 
02181 
02182 void nn4Reconstructor::buildFFTVolume() {
02183         int offset = 2 - m_vnxp%2;
02184 
02185         if( params.has_key("fftvol") ) {
02186                 m_volume = params["fftvol"];
02187                 m_delete_volume = false;
02188         } else {
02189                 m_volume = new EMData();
02190                 m_delete_volume = true;
02191         }
02192 
02193         if( m_volume->get_xsize() != m_vnxp+offset &&
02194             m_volume->get_ysize() != m_vnyp &&
02195             m_volume->get_zsize() != m_vnzp ) {
02196                 m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
02197                 m_volume->to_zero();
02198         }
02199         // ----------------------------------------------------------------
02200         // Added by Zhengfan Yang on 03/15/07
02201         // Original author: please check whether my revision is correct and
02202         // other Reconstructor need similiar revision.
02203         if ( m_vnxp % 2 == 0 )  m_volume->set_fftodd(0);
02204         else                    m_volume->set_fftodd(1);
02205         // ----------------------------------------------------------------
02206 
02207         m_volume->set_nxc(m_vnxp/2);
02208         m_volume->set_complex(true);
02209         m_volume->set_ri(true);
02210         m_volume->set_fftpad(true);
02211         m_volume->set_attr("npad", m_npad);
02212         m_volume->set_array_offsets(0,1,1);
02213 }
02214 
02215 void nn4Reconstructor::buildNormVolume() {
02216 
02217         if( params.has_key("weight") ) {
02218                 m_wptr = params["weight"];
02219                 m_delete_weight = false;
02220         } else {
02221                 m_wptr = new EMData();
02222                 m_delete_weight = true;
02223         }
02224 
02225         if( m_wptr->get_xsize() != m_vnxc+1 &&
02226                 m_wptr->get_ysize() != m_vnyp &&
02227                 m_wptr->get_zsize() != m_vnzp ) {
02228                 m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02229                 m_wptr->to_zero();
02230         }
02231 
02232         m_wptr->set_array_offsets(0,1,1);
02233 }
02234 
02235 void printImage( const EMData* line )
02236 {
02237         Assert( line->get_zsize()==1 );
02238 
02239 
02240         int nx = line->get_xsize();
02241         int ny = line->get_ysize();
02242         for( int j=0; j < ny; ++j ) {
02243                 for( int i=0; i < nx; ++i )  printf( "%10.3f ", line->get_value_at(i,j) );
02244                 printf( "\n" );
02245         }
02246 }
02247 
02248 
02249 
02250 int nn4Reconstructor::insert_slice(const EMData* const slice, const Transform& t) {
02251         // sanity checks
02252         if (!slice) {
02253                 LOGERR("try to insert NULL slice");
02254                 return 1;
02255         }
02256 
02257         int padffted= slice->get_attr_default( "padffted", 0 );
02258         if( m_ndim==3 ) {
02259                 if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  ) {
02260                         // FIXME: Why doesn't this throw an exception?
02261                         LOGERR("Tried to insert a slice that is the wrong size.");
02262                         return 1;
02263                 }
02264         } else {
02265                 Assert( m_ndim==2 );
02266                 if( slice->get_ysize() !=1 ) {
02267                         LOGERR( "for 2D reconstruction, a line is excepted" );
02268                         return 1;
02269                 }
02270         }
02271 
02272         EMData* padfft = NULL;
02273 
02274         if( padffted != 0 ) padfft = new EMData(*slice);
02275         else                padfft = padfft_slice( slice, t,  m_npad );
02276 
02277         int mult= slice->get_attr_default( "mult", 1 );
02278         Assert( mult > 0 );
02279 
02280         if( m_ndim==3 ) {
02281                 insert_padfft_slice( padfft, t, mult );
02282         } else {
02283                 float alpha = padfft->get_attr( "alpha" );
02284                 alpha = alpha/180.0f*M_PI;
02285                 for(int i=0; i < m_vnxc+1; ++i ) {
02286                         float xnew = i*cos(alpha);
02287                         float ynew = -i*sin(alpha);
02288                         float btqr = padfft->get_value_at( 2*i, 0, 0 );
02289                         float btqi = padfft->get_value_at( 2*i+1, 0, 0 );
02290                         if( xnew < 0.0 ) {
02291                                 xnew *= -1;
02292                                 ynew *= -1;
02293                                 btqi *= -1;
02294                         }
02295 
02296                         int ixn = int(xnew+0.5+m_vnxp) - m_vnxp;
02297                         int iyn = int(ynew+0.5+m_vnyp) - m_vnyp;
02298 
02299                         if(iyn < 0 ) iyn += m_vnyp;
02300 
02301                         (*m_volume)( 2*ixn, iyn+1, 1 ) += btqr *float(mult);
02302                         (*m_volume)( 2*ixn+1, iyn+1, 1 ) += btqi * float(mult);
02303                         (*m_wptr)(ixn,iyn+1, 1) += float(mult);
02304                 }
02305 
02306         }
02307         checked_delete( padfft );
02308         return 0;
02309 }
02310 
02311 int nn4Reconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
02312 {
02313         Assert( padfft != NULL );
02314         // insert slice for all symmetry related positions
02315         for (int isym=0; isym < m_nsym; isym++) {
02316                 Transform tsym = t.get_sym(m_symmetry, isym);
02317                 m_volume->nn( m_wptr, padfft, tsym, mult);
02318         }
02319         return 0;
02320 }
02321 
02322 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02323 
02324 void circumference( EMData* win )
02325 {
02326         float *tw = win->get_data();
02327         //  mask and subtract circumference average
02328         int ix = win->get_xsize();
02329         int iy = win->get_ysize();
02330         int iz = win->get_zsize();
02331         int L2 = (ix/2)*(ix/2);
02332         int L2P = (ix/2-1)*(ix/2-1);
02333 
02334         int IP = ix/2+1;
02335         int JP = iy/2+1;
02336         int KP = iz/2+1;
02337 
02338         float  TNR = 0.0f;
02339         size_t m = 0;
02340         for (int k = 1; k <= iz; ++k) {
02341                 for (int j = 1; j <= iy; ++j) {
02342                         for (int i = 1; i <= ix; ++i) {
02343                                 size_t LR = (k-KP)*(k-KP)+(j-JP)*(j-JP)+(i-IP)*(i-IP);
02344                                 if (LR<=(size_t)L2) {
02345                                         if(LR >= (size_t)L2P && LR <= (size_t)L2) {
02346                                                 TNR += tw(i,j,k);
02347                                                 ++m;
02348                                         }
02349                                 }
02350                         }
02351                 }
02352         }
02353 
02354         TNR /=float(m);
02355         for (int k = 1; k <= iz; ++k) {
02356                 for (int j = 1; j <= iy; ++j) {
02357                         for (int i = 1; i <= ix; ++i) {
02358                                 size_t LR = (k-KP)*(k-KP)+(j-JP)*(j-JP)+(i-IP)*(i-IP);
02359                                 if (LR<=(size_t)L2) tw(i,j,k) -= TNR; else tw(i,j,k) = 0.0f;
02360                         }
02361                 }
02362         }
02363 
02364 }
02365 
02366 
02367 EMData* nn4Reconstructor::finish()
02368 {
02369         if( m_ndim==3 ) {
02370                 m_volume->symplane0(m_wptr);
02371         } else {
02372                 for( int i=1; i <= m_vnyp; ++i ) {
02373 
02374                         if( (*m_wptr)(0, i, 1)==0.0 ) {
02375                                 int j = m_vnyp + 1 - i;
02376                                 (*m_wptr)(0, i, 1) = (*m_wptr)(0, j, 1);
02377                                 (*m_volume)(0, i, 1) = (*m_volume)(0, j, 1);
02378                                 (*m_volume)(1, i, 1) = (*m_volume)(1, j, 1);
02379                         }
02380                 }
02381         }
02382 
02383 
02384         int box = 7;
02385         int kc = (box-1)/2;
02386         vector< float > pow_a( m_ndim*kc+1, 1.0 );
02387         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
02388         pow_a.back()=0.0;
02389 
02390         float alpha = 0.0;
02391         if( m_ndim==3) {
02392                 int vol = box*box*box;
02393                 float max = max3d( kc, pow_a );
02394                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
02395         } else {
02396                 int ara = box*box;
02397                 float max = max2d( kc, pow_a );
02398                 alpha = ( 1.0f - 1.0f/(float)ara ) / max;
02399         }
02400 
02401         int ix,iy,iz;
02402         for (iz = 1; iz <= m_vnzp; iz++) {
02403                 for (iy = 1; iy <= m_vnyp; iy++) {
02404                         for (ix = 0; ix <= m_vnxc; ix++) {
02405                                 if ( (*m_wptr)(ix,iy,iz) > 0) {//(*v) should be treated as complex!!
02406                                         float tmp;
02407                                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+m_osnr);
02408 
02409                                         if( m_weighting == ESTIMATE ) {
02410                                                 int cx = ix;
02411                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
02412                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
02413                                                 float sum = 0.0;
02414                                                 for( int ii = -kc; ii <= kc; ++ii ) {
02415                                                         int nbrcx = cx + ii;
02416                                                         if( nbrcx >= m_vnxc ) continue;
02417                                                         for( int jj= -kc; jj <= kc; ++jj ) {
02418                                                                 int nbrcy = cy + jj;
02419                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
02420 
02421                                                                 int kcz = (m_ndim==3) ? kc : 0;
02422                                                                 for( int kk = -kcz; kk <= kcz; ++kk ) {
02423                                                                         int nbrcz = cz + kk;
02424                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
02425                                                                         if( nbrcx < 0 ) {
02426                                                                                 nbrcx = -nbrcx;
02427                                                                                 nbrcy = -nbrcy;
02428                                                                                 nbrcz = -nbrcz;
02429                                                                         }
02430                                                                         int nbrix = nbrcx;
02431                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
02432                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
02433                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
02434                                                                                 int c = m_ndim*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
02435                                                                                 sum = sum + pow_a[c];
02436                                                                         }
02437                                                                 }
02438                                                         }
02439                                                 }
02440                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
02441                                                 tmp = tmp * wght;
02442                                         }
02443                                         (*m_volume)(2*ix,iy,iz) *= tmp;
02444                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
02445                                 }
02446                         }
02447                 }
02448         }
02449 
02450         //if(m_ndim==2) printImage( m_volume );
02451 
02452         // back fft
02453         m_volume->do_ift_inplace();
02454 
02455         // EMData* win = m_volume->window_center(m_vnx);
02456         m_volume->depad();
02457         circumference( m_volume );
02458         m_volume->set_array_offsets( 0, 0, 0 );
02459 
02460     m_result = m_volume->copy();
02461         return m_result;
02462 }
02463 #undef  tw
02464 
02465 // Added By Zhengfan Yang on 03/16/07
02466 // Beginning of the addition
02467 // --------------------------------------------------------------------------------
02468 
02469 nnSSNR_Reconstructor::nnSSNR_Reconstructor()
02470 {
02471         m_volume = NULL;
02472         m_wptr   = NULL;
02473         m_wptr2  = NULL;
02474         m_result = NULL;
02475 }
02476 
02477 nnSSNR_Reconstructor::nnSSNR_Reconstructor( const string& symmetry, int size, int npad)
02478 {
02479         m_volume = NULL;
02480         m_wptr   = NULL;
02481         m_wptr2  = NULL;
02482         m_result = NULL;
02483 
02484         setup( symmetry, size, npad );
02485 }
02486 
02487 nnSSNR_Reconstructor::~nnSSNR_Reconstructor()
02488 {
02489         if( m_delete_volume ) checked_delete(m_volume);
02490 
02491         if( m_delete_weight ) checked_delete( m_wptr );
02492 
02493         if( m_delete_weight2 ) checked_delete( m_wptr2 );
02494 
02495         checked_delete( m_result );
02496 }
02497 
02498 void nnSSNR_Reconstructor::setup()
02499 {
02500         int size = params["size"];
02501         int npad = params["npad"];
02502 
02503         string symmetry;
02504         if( params.has_key("symmetry") ) symmetry = params["symmetry"].to_str();
02505         else                             symmetry = "c1";
02506 
02507         setup( symmetry, size, npad );
02508 }
02509 
02510 void nnSSNR_Reconstructor::setup( const string& symmetry, int size, int npad )
02511 {
02512 
02513         m_weighting = ESTIMATE;
02514         m_wghta = 0.2f;
02515         m_wghtb = 0.004f;
02516 
02517         m_symmetry = symmetry;
02518         m_npad = npad;
02519         m_nsym = Transform::get_nsym(m_symmetry);
02520 
02521         m_vnx = size;
02522         m_vny = size;
02523         m_vnz = size;
02524 
02525         m_vnxp = size*npad;
02526         m_vnyp = size*npad;
02527         m_vnzp = size*npad;
02528 
02529         m_vnxc = m_vnxp/2;
02530         m_vnyc = m_vnyp/2;
02531         m_vnzc = m_vnzp/2;
02532 
02533         buildFFTVolume();
02534         buildNormVolume();
02535         buildNorm2Volume();
02536 
02537 }
02538 
02539 void nnSSNR_Reconstructor::buildFFTVolume() {
02540 
02541         if( params.has_key("fftvol") ) {
02542                 m_volume = params["fftvol"]; /* volume should be defined in python when PMI is turned on*/
02543                 m_delete_volume = false;
02544         } else {
02545                 m_volume = new EMData();
02546                 m_delete_volume = true;
02547         }
02548         m_volume->set_size(m_vnxp+ 2 - m_vnxp%2,m_vnyp,m_vnzp);
02549         m_volume->to_zero();
02550         if ( m_vnxp % 2 == 0 ) m_volume->set_fftodd(0);
02551         else                   m_volume->set_fftodd(1);
02552 
02553         m_volume->set_nxc(m_vnxc);
02554         m_volume->set_complex(true);
02555         m_volume->set_ri(true);
02556         m_volume->set_fftpad(true);
02557         m_volume->set_attr("npad", m_npad);
02558         m_volume->set_array_offsets(0,1,1);
02559 }
02560 
02561 void nnSSNR_Reconstructor::buildNormVolume() {
02562         if( params.has_key("weight") ) {
02563                 m_wptr          = params["weight"];
02564                 m_delete_weight = false;
02565         } else {
02566                 m_wptr = new EMData();
02567                 m_delete_weight = true;
02568         }
02569 
02570         m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02571         m_wptr->to_zero();
02572 
02573         m_wptr->set_array_offsets(0,1,1);
02574 }
02575 
02576 void nnSSNR_Reconstructor::buildNorm2Volume() {
02577 
02578         if( params.has_key("weight2") ) {
02579                 m_wptr2          = params["weight2"];
02580                 m_delete_weight2 = false;
02581         } else {
02582                 m_wptr2 = new EMData();
02583                 m_delete_weight2 = true;
02584         }
02585         m_wptr2->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02586         m_wptr2->to_zero();
02587         m_wptr2->set_array_offsets(0,1,1);
02588 }
02589 
02590 
02591 int nnSSNR_Reconstructor::insert_slice(const EMData* const slice, const Transform& t) {
02592         // sanity checks
02593         if (!slice) {
02594                 LOGERR("try to insert NULL slice");
02595                 return 1;
02596         }
02597 
02598         int padffted=slice->get_attr_default( "padffted", 0 );
02599 
02600         if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  ) {
02601                 // FIXME: Why doesn't this throw an exception?
02602                 LOGERR("Tried to insert a slice that has wrong size.");
02603                 return 1;
02604         }
02605 
02606         EMData* padfft = NULL;
02607 
02608         if( padffted != 0 ) padfft = new EMData(*slice);
02609         else                padfft = padfft_slice( slice, t, m_npad );
02610 
02611         int mult = slice->get_attr_default("mult", 1);
02612 
02613         Assert( mult > 0 );
02614         insert_padfft_slice( padfft, t, mult );
02615 
02616         checked_delete( padfft );
02617         return 0;
02618 }
02619 
02620 int nnSSNR_Reconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
02621 {
02622         Assert( padfft != NULL );
02623         // insert slice for all symmetry related positions
02624         for (int isym=0; isym < m_nsym; isym++) {
02625                 Transform tsym = t.get_sym(m_symmetry, isym);
02626                 m_volume->nn_SSNR( m_wptr, m_wptr2, padfft, tsym, mult);
02627         }
02628         return 0;
02629 }
02630 
02631 
02632 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02633 EMData* nnSSNR_Reconstructor::finish()
02634 {
02635 /*
02636   I changed the code on 05/15 so it only returns variance.
02637   Lines commented out are marked by //#
02638   The version prior to the currect changes is r1.190
02639   PAP
02640 */
02641         int kz, ky;
02642         //#int iix, iiy, iiz;
02643         int box = 7;
02644         int kc = (box-1)/2;
02645         float alpha = 0.0;
02646         float argx, argy, argz;
02647         vector< float > pow_a( 3*kc+1, 1.0 );
02648         float w = params["w"];
02649         EMData* SSNR = params["SSNR"];
02650         //#EMData* vol_ssnr = new EMData();
02651         //#vol_ssnr->set_size(m_vnxp, m_vnyp, m_vnzp);
02652         //#vol_ssnr->to_zero();
02653         //#  new line follow
02654         EMData* vol_ssnr = new EMData();
02655         vol_ssnr->set_size(m_vnxp+ 2 - m_vnxp%2, m_vnyp ,m_vnzp);
02656         vol_ssnr->to_zero();
02657         if ( m_vnxp % 2 == 0 ) vol_ssnr->set_fftodd(0);
02658         else                   vol_ssnr->set_fftodd(1);
02659         vol_ssnr->set_nxc(m_vnxc);
02660         vol_ssnr->set_complex(true);
02661         vol_ssnr->set_ri(true);
02662         vol_ssnr->set_fftpad(false);
02663         //#
02664 
02665         float dx2 = 1.0f/float(m_vnxc)/float(m_vnxc);
02666         float dy2 = 1.0f/float(m_vnyc)/float(m_vnyc);
02667 #ifdef _WIN32
02668         float dz2 = 1.0f/_cpp_max(float(m_vnzc),1.0f)/_cpp_max(float(m_vnzc),1.0f);
02669         int  inc = Util::round(float(_cpp_max(_cpp_max(m_vnxc,m_vnyc),m_vnzc))/w);
02670 #else
02671         float dz2 = 1.0f/std::max(float(m_vnzc),1.0f)/std::max(float(m_vnzc),1.0f);
02672         int  inc = Util::round(float(std::max(std::max(m_vnxc,m_vnyc),m_vnzc))/w);
02673 #endif  //_WIN32
02674         SSNR->set_size(inc+1,4,1);
02675 
02676         float *nom    = new float[inc+1];
02677         float *denom  = new float[inc+1];
02678         int  *nn     = new int[inc+1];
02679         int  *ka     = new int[inc+1];
02680         float wght = 1.0f;
02681         for (int i = 0; i <= inc; i++) {
02682                 nom[i] = 0.0f;
02683                 denom[i] = 0.0f;
02684                 nn[i] = 0;
02685                 ka[i] = 0;
02686         }
02687 
02688         m_volume->symplane1(m_wptr, m_wptr2);
02689 
02690         if ( m_weighting == ESTIMATE ) {
02691                 int vol = box*box*box;
02692                 for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
02693                 pow_a[3*kc] = 0.0;
02694                 float max = max3d( kc, pow_a );
02695                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
02696         }
02697 
02698         for (int iz = 1; iz <= m_vnzp; iz++) {
02699                 if ( iz-1 > m_vnzc ) kz = iz-1-m_vnzp; else kz = iz-1;
02700                 argz = float(kz*kz)*dz2;
02701                 for (int iy = 1; iy <= m_vnyp; iy++) {
02702                         if ( iy-1 > m_vnyc ) ky = iy-1-m_vnyp; else ky = iy-1;
02703                         argy = argz + float(ky*ky)*dy2;
02704                         for (int ix = 0; ix <= m_vnxc; ix++) {
02705                                 float Kn = (*m_wptr)(ix,iy,iz);
02706                                 argx = std::sqrt(argy + float(ix*ix)*dx2);
02707                                 int r = Util::round(float(inc)*argx);
02708                                 if ( r >= 0 && Kn > 4.5f ) {
02709                                         if ( m_weighting == ESTIMATE ) {
02710                                                 int cx = ix;
02711                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
02712                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
02713 
02714                                                 float sum = 0.0;
02715                                                 for( int ii = -kc; ii <= kc; ++ii ) {
02716                                                         int nbrcx = cx + ii;
02717                                                         if( nbrcx >= m_vnxc ) continue;
02718                                                     for ( int jj= -kc; jj <= kc; ++jj ) {
02719                                                                 int nbrcy = cy + jj;
02720                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
02721                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
02722                                                                         int nbrcz = cz + jj;
02723                                                                         if ( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
02724                                                                         if( nbrcx < 0 ) {
02725                                                                                 nbrcx = -nbrcx;
02726                                                                                 nbrcy = -nbrcy;
02727                                                                                 nbrcz = -nbrcz;
02728                                                                         }
02729                                                                         int nbrix = nbrcx;
02730                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
02731                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
02732                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
02733                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
02734                                                                                 sum = sum + pow_a[c];
02735                                                                         }
02736                                                                 }
02737                                                         }
02738                                                 }
02739                                                 wght = 1.0f / ( 1.0f - alpha * sum );
02740                                         } // end of ( m_weighting == ESTIMATE )
02741                                         float nominator = std::norm(m_volume->cmplx(ix,iy,iz))/Kn;
02742                                         float denominator = ((*m_wptr2)(ix,iy,iz)-nominator)/(Kn-1.0f);
02743                                         // Skip Friedel related values
02744                                         if( (ix>0 || (kz>=0 && (ky>=0 || kz!=0)))) {
02745                                                 if ( r <= inc ) {
02746                                                         nom[r]   += nominator*wght;
02747                                                         denom[r] += denominator/Kn*wght;
02748                                                         nn[r]    += 2;
02749                                                         ka[r]    += int(Kn);
02750                                                 }
02751 /*
02752 #ifdef  _WIN32
02753                                                 //#float  tmp = _cpp_max(nominator/denominator/Kn-1.0f,0.0f);
02754 #else
02755                                                 //#float  tmp = std::max(nominator/denominator/Kn-1.0f,0.0f);
02756 #endif  //_WIN32
02757                                                 //  Create SSNR as a 3D array (-n/2:n/2+n%2-1)
02758                                                 iix = m_vnxc + ix; iiy = m_vnyc + ky; iiz = m_vnzc + kz;
02759                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
02760                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
02761                                                 // Friedel part
02762                                                 iix = m_vnxc - ix; iiy = m_vnyc - ky; iiz = m_vnzc - kz;
02763                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
02764                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
02765 */
02766 
02767                                         }
02768                                         (*vol_ssnr)(2*ix, iy-1, iz-1) = denominator*wght;
02769                                         //(*vol_ssnr)(2*ix, iy-1, iz-1) =  real(m_volume->cmplx(ix,iy,iz))*wght/Kn;
02770                                         //(*vol_ssnr)(2*ix+1, iy-1, iz-1) = imag(m_volume->cmplx(ix,iy,iz))*wght/Kn;
02771                                 } // end of Kn>4.5
02772                         }
02773                 }
02774         }
02775 
02776         for (int i = 0; i <= inc; i++)  {
02777                 (*SSNR)(i,0,0) = nom[i];  
02778                 (*SSNR)(i,1,0) = denom[i];    // variance
02779                 (*SSNR)(i,2,0) = static_cast<float>(nn[i]);
02780                 (*SSNR)(i,3,0) = static_cast<float>(ka[i]);
02781         }
02782         vol_ssnr->update();
02783         return vol_ssnr;
02784 }
02785 #undef  tw
02786 
02787 // -----------------------------------------------------------------------------------
02788 // End of this addition
02789 
02790 //####################################################################################
02791 //** nn4 ctf reconstructor
02792 
02793 nn4_ctfReconstructor::nn4_ctfReconstructor()
02794 {
02795         m_volume  = NULL;
02796         m_wptr    = NULL;
02797         m_result  = NULL;
02798 }
02799 
02800 nn4_ctfReconstructor::nn4_ctfReconstructor( const string& symmetry, int size, int npad, float snr, int sign )
02801 {
02802         setup( symmetry, size, npad, snr, sign );
02803 }
02804 
02805 nn4_ctfReconstructor::~nn4_ctfReconstructor()
02806 {
02807         if( m_delete_volume ) checked_delete(m_volume);
02808 
02809         if( m_delete_weight ) checked_delete( m_wptr );
02810 
02811         checked_delete( m_result );
02812 }
02813 
02814 void nn4_ctfReconstructor::setup()
02815 {
02816         if( ! params.has_key("size") ) throw std::logic_error("Error: image size is not given");
02817 
02818         int size = params["size"];
02819         int npad = params.has_key("npad") ? int(params["npad"]) : 4;
02820         // int sign = params.has_key("sign") ? int(params["sign"]) : 1;
02821         int sign = 1;
02822         string symmetry = params.has_key("symmetry")? params["symmetry"].to_str() : "c1";
02823 
02824         float snr = params["snr"];
02825 
02826     m_varsnr = params.has_key("varsnr") ? int(params["varsnr"]) : 0;
02827         setup( symmetry, size, npad, snr, sign );
02828 
02829 }
02830 
02831 void nn4_ctfReconstructor::setup( const string& symmetry, int size, int npad, float snr, int sign )
02832 {
02833         m_weighting = ESTIMATE;
02834         if( params.has_key("weighting") ) {
02835                 int tmp = int( params["weighting"] );
02836                 if( tmp==0 ) m_weighting = NONE;
02837         }
02838 
02839 
02840 
02841         m_wghta = 0.2f;
02842         m_wghtb = 0.004f;
02843 
02844         m_symmetry = symmetry;
02845         m_npad = npad;
02846         m_sign = sign;
02847         m_nsym = Transform::get_nsym(m_symmetry);
02848 
02849         m_snr = snr;
02850 
02851         m_vnx = size;
02852         m_vny = size;
02853         m_vnz = size;
02854 
02855         m_vnxp = size*npad;
02856         m_vnyp = size*npad;
02857         m_vnzp = size*npad;
02858 
02859         m_vnxc = m_vnxp/2;
02860         m_vnyc = m_vnyp/2;
02861         m_vnzc = m_vnzp/2;
02862 
02863         buildFFTVolume();
02864         buildNormVolume();
02865 }
02866 
02867 void nn4_ctfReconstructor::buildFFTVolume() {
02868         int offset = 2 - m_vnxp%2;
02869         if( params.has_key("fftvol") ) {
02870             m_volume = params["fftvol"];
02871             m_delete_volume = false;
02872         } else {
02873             m_volume = new EMData();
02874             m_delete_volume = true;
02875         }
02876 
02877         if( m_volume->get_xsize() != m_vnxp+offset &&
02878             m_volume->get_ysize() != m_vnyp &&
02879             m_volume->get_zsize() != m_vnzp )
02880         {
02881             m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
02882             m_volume->to_zero();
02883         }
02884 
02885         m_volume->set_nxc(m_vnxp/2);
02886         m_volume->set_complex(true);
02887         m_volume->set_ri(true);
02888         m_volume->set_fftpad(true);
02889         m_volume->set_attr("npad", m_npad);
02890         m_volume->set_array_offsets(0,1,1);
02891 }
02892 
02893 void nn4_ctfReconstructor::buildNormVolume()
02894 {
02895         if( params.has_key("weight") )
02896         {
02897             m_wptr = params["weight"];
02898             m_delete_weight = false;
02899         } else {
02900             m_wptr = new EMData();
02901             m_delete_weight = true;
02902         }
02903 
02904         if( m_wptr->get_xsize() != m_vnxc+1 &&
02905             m_wptr->get_ysize() != m_vnyp &&
02906             m_wptr->get_zsize() != m_vnzp )
02907         {
02908             m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02909             m_wptr->to_zero();
02910         }
02911 
02912         m_wptr->set_array_offsets(0,1,1);
02913 
02914 }
02915 
02916 int nn4_ctfReconstructor::insert_slice(const EMData* const slice, const Transform& t)
02917 {
02918         // sanity checks
02919         if (!slice) {
02920                 LOGERR("try to insert NULL slice");
02921                 return 1;
02922         }
02923 
02924         int buffed = slice->get_attr_default( "buffed", 0 );
02925         if( buffed > 0 )
02926         {
02927             int mult = slice->get_attr_default( "mult", 1 );
02928             insert_buffed_slice( slice, mult );
02929             return 0;
02930         }
02931 
02932         int padffted= slice->get_attr_default("padffted", 0);
02933         if( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  )
02934         {
02935                 // FIXME: Why doesn't this throw an exception?
02936                 LOGERR("Tried to insert a slice that is the wrong size.");
02937                 return 1;
02938         }
02939 
02940         EMData* padfft = NULL;
02941 
02942         if( padffted != 0 ) padfft = new EMData(*slice);
02943         else                padfft = padfft_slice( slice, t, m_npad );
02944 
02945         int mult= slice->get_attr_default("mult", 1);
02946 
02947         Assert( mult > 0 );
02948         insert_padfft_slice( padfft, t, mult );
02949 
02950         checked_delete( padfft );
02951 
02952         return 0;
02953 }
02954 
02955 int nn4_ctfReconstructor::insert_buffed_slice( const EMData* buffed, int mult )
02956 {
02957         const float* bufdata = buffed->get_data();
02958         float* cdata = m_volume->get_data();
02959         float* wdata = m_wptr->get_data();
02960 
02961         int npoint = buffed->get_xsize()/4;
02962         for( int i=0; i < npoint; ++i ) {
02963 
02964                int pos2 = int( bufdata[4*i] );
02965                int pos1 = pos2 * 2;
02966                cdata[pos1  ] += bufdata[4*i+1]*mult;
02967                cdata[pos1+1] += bufdata[4*i+2]*mult;
02968                wdata[pos2  ] += bufdata[4*i+3]*mult;
02969 /*
02970         std::cout << "pos1, pos2, ctfv1, ctfv2, ctf2: ";
02971         std::cout << pos1 << " " << bufdata[5*i+1] << " " << bufdata[5*i+2] << " ";
02972         std::cout << pos2 << " " << bufdata[5*i+4] << std::endl;
02973  */
02974         }
02975         return 0;
02976 }
02977 
02978 int nn4_ctfReconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
02979 {
02980         Assert( padfft != NULL );
02981         float tmp = padfft->get_attr("ctf_applied");
02982         int   ctf_applied = (int) tmp;
02983 
02984         for( int isym=0; isym < m_nsym; isym++) {
02985                 Transform tsym = t.get_sym( m_symmetry, isym );
02986 
02987                 if(ctf_applied) m_volume->nn_ctf_applied(m_wptr, padfft, tsym, mult);
02988                 else            m_volume->nn_ctf(m_wptr, padfft, tsym, mult);
02989         }
02990 
02991         return 0;
02992 
02993 }
02994 
02995 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02996 EMData* nn4_ctfReconstructor::finish()
02997 {
02998         m_volume->set_array_offsets(0, 1, 1);
02999         m_wptr->set_array_offsets(0, 1, 1);
03000         m_volume->symplane0_ctf(m_wptr);
03001 
03002         int box = 7;
03003         int vol = box*box*box;
03004         int kc = (box-1)/2;
03005         vector< float > pow_a( 3*kc+1, 1.0 );
03006         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
03007         pow_a[3*kc]=0.0;
03008 
03009 
03010         float max = max3d( kc, pow_a );
03011         float alpha = ( 1.0f - 1.0f/(float)vol ) / max;
03012         float osnr = 1.0f/m_snr;
03013 
03014         // normalize
03015         int ix,iy,iz;
03016         for (iz = 1; iz <= m_vnzp; iz++) {
03017                 for (iy = 1; iy <= m_vnyp; iy++) {
03018                         for (ix = 0; ix <= m_vnxc; ix++) {
03019                                 if ( (*m_wptr)(ix,iy,iz) > 0.0f) {//(*v) should be treated as complex!!
03020                     int iyp = (iy<=m_vnyc) ? iy - 1 : iy-m_vnyp-1;
03021                     int izp = (iz<=m_vnzc) ? iz - 1 : iz-m_vnzp-1;
03022                     float tmp=0.0;
03023                     if( m_varsnr )
03024                     {
03025                                             float freq = sqrt( (float)(ix*ix+iyp*iyp+izp*izp) );
03026                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+freq*osnr)*m_sign;
03027                     }
03028                     else
03029                     {
03030                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+osnr)*m_sign;
03031                     }
03032 
03033                                         if( m_weighting == ESTIMATE ) {
03034                                                 int cx = ix;
03035                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
03036                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
03037                                                 float sum = 0.0;
03038                                                 for( int ii = -kc; ii <= kc; ++ii ) {
03039                                                         int nbrcx = cx + ii;
03040                                                         if( nbrcx >= m_vnxc ) continue;
03041                                                         for( int jj= -kc; jj <= kc; ++jj ) {
03042                                                                 int nbrcy = cy + jj;
03043                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
03044                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
03045                                                                         int nbrcz = cz + jj;
03046                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
03047                                                                         if( nbrcx < 0 ) {
03048                                                                                 nbrcx = -nbrcx;
03049                                                                                 nbrcy = -nbrcy;
03050                                                                                 nbrcz = -nbrcz;
03051                                                                         }
03052 
03053                                                                         int nbrix = nbrcx;
03054                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
03055                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
03056                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0.0 ) {
03057                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
03058                                                                                 sum = sum + pow_a[c];
03059                                                                                   // if(ix%20==0 && iy%20==0 && iz%20==0)
03060                                                                                  //   std::cout << boost::format( "%4d %4d %4d %4d %10.3f" ) % nbrix % nbriy % nbriz % c % sum << std::endl;
03061                                                                         }
03062                                                                 }
03063                                                         }
03064                                                 }
03065                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
03066 /*
03067                         if(ix%10==0 && iy%10==0)
03068                         {
03069                             std::cout << boost::format( "%4d %4d %4d " ) % ix % iy %iz;
03070                             std::cout << boost::format( "%10.3f %10.3f %10.3f " )  % tmp % wght % sum;
03071                             std::  << boost::format( "%10.3f %10.3e " ) % pow_b[r] % alpha;
03072                             std::cout << std::endl;
03073                         }
03074  */
03075                                                 tmp = tmp * wght;
03076                                         }
03077                                         (*m_volume)(2*ix,iy,iz) *= tmp;
03078                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
03079                                 }
03080                         }
03081                 }
03082         }
03083 
03084     // back fft
03085     m_volume->do_ift_inplace();
03086     m_volume->depad();
03087     circumference( m_volume );
03088     m_volume->set_array_offsets( 0, 0, 0 );
03089     m_result = m_volume->copy();
03090     return m_result;
03091 }
03092 #undef  tw
03093 
03094 
03095 
03096 
03097 // Added By Zhengfan Yang on 04/11/07
03098 // Beginning of the addition
03099 // --------------------------------------------------------------------------------
03100 
03101 nnSSNR_ctfReconstructor::nnSSNR_ctfReconstructor()
03102 {
03103     m_volume  = NULL;
03104     m_wptr    = NULL;
03105     m_wptr2   = NULL;
03106     m_wptr3   = NULL;
03107     m_result  = NULL;
03108 }
03109 
03110 nnSSNR_ctfReconstructor::nnSSNR_ctfReconstructor( const string& symmetry, int size, int npad, float snr, int sign)
03111 {
03112     m_volume  = NULL;
03113     m_wptr    = NULL;
03114     m_wptr2   = NULL;
03115     m_wptr3   = NULL;
03116     m_result  = NULL;
03117 
03118     setup( symmetry, size, npad, snr, sign );
03119 }
03120 
03121 nnSSNR_ctfReconstructor::~nnSSNR_ctfReconstructor()
03122 {
03123 
03124    if( m_delete_volume )
03125         checked_delete(m_volume);
03126    if( m_delete_weight )
03127         checked_delete( m_wptr );
03128    if ( m_delete_weight2 )
03129         checked_delete( m_wptr2 );
03130    if ( m_delete_weight3 )
03131         checked_delete( m_wptr3 );
03132    checked_delete( m_result );
03133 }
03134 
03135 void nnSSNR_ctfReconstructor::setup()
03136 {
03137     int  size = params["size"];
03138     int  npad = params["npad"];
03139     int  sign = params["sign"];
03140     float snr = params["snr"];
03141     string symmetry;
03142     if( params.has_key("symmetry") ) {
03143                 symmetry = params["symmetry"].to_str();
03144     } else {
03145                 symmetry = "c1";
03146     }
03147     setup( symmetry, size, npad, snr, sign );
03148 }
03149 void nnSSNR_ctfReconstructor::setup( const string& symmetry, int size, int npad, float snr, int sign )
03150 {
03151 
03152     m_weighting = ESTIMATE;
03153     m_wghta     = 0.2f;
03154     m_wghtb     = 0.004f;
03155     wiener      = 1;
03156 
03157     m_symmetry  = symmetry;
03158     m_npad      = npad;
03159     m_nsym      = Transform::get_nsym(m_symmetry);
03160 
03161     m_sign      = sign;
03162     m_snr       = snr;
03163 
03164     m_vnx       = size;
03165     m_vny       = size;
03166     m_vnz       = size;
03167 
03168     m_vnxp      = size*npad;
03169     m_vnyp      = size*npad;
03170     m_vnzp      = size*npad;
03171 
03172     m_vnxc      = m_vnxp/2;
03173     m_vnyc      = m_vnyp/2;
03174     m_vnzc      = m_vnzp/2;
03175 
03176     buildFFTVolume();
03177     buildNormVolume();
03178     buildNorm2Volume();
03179     buildNorm3Volume();
03180 }
03181 
03182 void nnSSNR_ctfReconstructor::buildFFTVolume() {
03183 
03184         int offset = 2 - m_vnxp%2;
03185         if( params.has_key("fftvol") ) {
03186                 m_volume = params["fftvol"]; /* volume should be defined in python when PMI is turned on*/
03187                 m_delete_volume = false;
03188     } else {
03189                 m_volume = new EMData();
03190                 m_delete_volume = true;
03191         }
03192 
03193         m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
03194         m_volume->to_zero();
03195 
03196         if ( m_vnxp % 2 == 0 ) {
03197                 m_volume->set_fftodd(0);
03198         } else {
03199                 m_volume->set_fftodd(1);
03200         }
03201 
03202         m_volume->set_nxc(m_vnxc);
03203         m_volume->set_complex(true);
03204         m_volume->set_ri(true); //(real, imaginary) instead of polar coordinate
03205         m_volume->set_fftpad(true);
03206         m_volume->set_attr("npad", m_npad);
03207         m_volume->set_array_offsets(0,1,1);
03208 }
03209 
03210 
03211 void nnSSNR_ctfReconstructor::buildNormVolume()
03212 {
03213         if( params.has_key("weight") ) {
03214                  m_wptr          = params["weight"];
03215                  m_delete_weight = false;
03216         } else {
03217                 m_wptr = new EMData();
03218                 m_delete_weight = true;
03219         }
03220         m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03221