Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

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 "plugins/reconstructor_template.h"
00038 #include "ctf.h"
00039 #include "emassert.h"
00040 #include "symmetry.h"
00041 #include <cstring>
00042 #include <fstream>
00043 #include <iomanip>
00044 #include <boost/bind.hpp>
00045 #include <boost/format.hpp>
00046 
00047 #include <gsl/gsl_statistics_double.h>
00048 #include <gsl/gsl_fit.h>
00049 
00050 using namespace EMAN;
00051 using std::complex;
00052 
00053 
00054 #include <iostream>
00055 using std::cerr;
00056 using std::endl;
00057 using std::cout; // for debug
00058 
00059 #include <algorithm>
00060 // find, for_each
00061 
00062 #include <iomanip>
00063 using std::setprecision;
00064 
00065 template < typename T > void checked_delete( T*& x )
00066 {
00067     typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
00068     (void) sizeof(type_must_be_complete);
00069     delete x;
00070     x = NULL;
00071 }
00072 
00073 const string FourierReconstructor::NAME = "fourier";
00074 const string FourierReconstructorSimple2D::NAME = "fouriersimple2D";
00075 const string WienerFourierReconstructor::NAME = "wiener_fourier";
00076 const string BackProjectionReconstructor::NAME = "back_projection";
00077 const string nn4Reconstructor::NAME = "nn4";
00078 const string nn4_rectReconstructor::NAME = "nn4_rect";
00079 const string nnSSNR_Reconstructor::NAME = "nnSSNR";
00080 const string nn4_ctfReconstructor::NAME = "nn4_ctf";
00081 const string nn4_ctf_rectReconstructor::NAME = "nn4_ctf_rect";
00082 const string nnSSNR_ctfReconstructor::NAME = "nnSSNR_ctf";
00083 
00084 template <> Factory < Reconstructor >::Factory()
00085 {
00086         force_add<FourierReconstructor>();
00087         force_add<FourierReconstructorSimple2D>();
00088 //      force_add(&BaldwinWoolfordReconstructor::NEW);
00089         force_add<WienerFourierReconstructor>();
00090         force_add<BackProjectionReconstructor>();
00091         force_add<nn4Reconstructor>();
00092         force_add<nn4_rectReconstructor>();
00093         force_add<nnSSNR_Reconstructor>();
00094         force_add<nn4_ctfReconstructor>();
00095         force_add<nn4_ctf_rectReconstructor>();
00096         force_add<nnSSNR_ctfReconstructor>();
00097 //      force_add<XYZReconstructor>();
00098 }
00099 
00100 void FourierReconstructorSimple2D::setup()
00101 {
00102         nx = params.set_default("nx",0);
00103 
00104         if ( nx < 0 ) throw InvalidValueException(nx, "nx must be positive");
00105 
00106         bool is_fftodd = (nx % 2 == 1);
00107 
00108         ny = nx;
00109         nx += 2-is_fftodd;
00110 
00111         image = new EMData();
00112         image->set_size(nx, ny);
00113         image->set_complex(true);
00114         image->set_fftodd(is_fftodd);
00115         image->set_ri(true);
00116 
00117         tmp_data = new EMData();
00118         tmp_data->set_size(nx/2, nx);
00119 }
00120 
00121 int FourierReconstructorSimple2D::insert_slice(const EMData* const slice, const Transform & euler, const float weight)
00122 {
00123 
00124         // Are these exceptions really necessary? (d.woolford)
00125         if (!slice) throw NullPointerException("EMData pointer (input image) is NULL");
00126 
00127         if ( slice->get_ndim() != 1 ) throw ImageDimensionException("Image dimension must be 1");
00128 
00129         // I could also test to make sure the image is the right dimensions...
00130         if (slice->is_complex()) throw ImageFormatException("The image is complex, expecting real");
00131 
00132         EMData* working_slice = slice->process("xform.phaseorigin.tocorner");
00133 
00134         // Fourier transform the slice
00135         working_slice->do_fft_inplace();
00136 
00137         float* rdata = image->get_data();
00138         float* norm = tmp_data->get_data();
00139         float* dat = working_slice->get_data();
00140 
00141         float g[4];
00142         int offset[4];
00143         float dt[2];
00144         offset[0] = 0; offset[1] = 2; offset[2] = nx; offset[3] = nx+2;
00145 
00146         float alt = -((float)(euler.get_rotation("2d"))["alpha"])*M_PI/180.0f;
00147         for (int x = 0; x < working_slice->get_xsize() / 2; x++) {
00148 
00149                 float rx = (float) x;
00150 
00151                 float xx = rx*cos(alt);
00152                 float yy = rx*sin(alt);
00153                 float cc = 1.0;
00154 
00155                 if (xx < 0) {
00156                         xx = -xx;
00157                         yy = -yy;
00158                         cc = -1.0;
00159                 }
00160 
00161                 yy += ny / 2;
00162 
00163 
00164                 dt[0] = dat[2*x];
00165                 dt[1] = cc * dat[2*x+1];
00166 
00167                 // PHIL IS INTERESTED FROM HERE DOWN
00168                 int x0 = (int) floor(xx);
00169                 int y0 = (int) floor(yy);
00170 
00171                 int i = 2*x0 + y0*nx;
00172 
00173                 float dx = xx - x0;
00174                 float dy = yy - y0;
00175 
00176                 g[0] = Util::agauss(1, dx, dy, 0, EMConsts::I2G);
00177                 g[1] = Util::agauss(1, 1 - dx, dy, 0, EMConsts::I2G);
00178                 g[2] = Util::agauss(1, dx, 1 - dy, 0, EMConsts::I2G);
00179                 g[3] = Util::agauss(1, 1 - dx, 1 - dy, 0, EMConsts::I2G);
00180 
00181                 // At the extreme we can only do some much...
00182                 if ( x0 == nx-2 ) {
00183                         int k = i + offset[0];
00184                         rdata[k] += g[0] * dt[0];
00185                         rdata[k + 1] += g[0] * dt[1];
00186                         norm[k/2] += g[0];
00187 
00188                         k = i + offset[2];
00189                         rdata[k] += g[2] * dt[0];
00190                         rdata[k + 1] += g[2] * dt[1];
00191                         norm[k/2] += g[2];
00192                         continue;
00193 
00194                 }
00195                 // capture and accommodate for periodic boundary conditions in the x direction
00196                 if ( x0 > nx-2 ) {
00197                         int dif = x0 - (nx-2);
00198                         x0 -= dif;
00199                 }
00200                 // At the extreme we can only do some much...
00201                 if ( y0 == ny -1 ) {
00202                         int k = i + offset[0];
00203                         rdata[k] += g[0] * dt[0];
00204                         rdata[k + 1] += g[0] * dt[1];
00205                         norm[k/2] += g[0];
00206 
00207                         k = i + offset[1];
00208                         rdata[k] += g[1] * dt[0];
00209                         rdata[k + 1] += g[1] * dt[1];
00210                         norm[k/2] += g[1];
00211                         continue;
00212                 }
00213                 // capture and accommodate for periodic boundary conditions in the y direction
00214                 if ( y0 > ny-1) {
00215                         int dif = y0 - (ny-1);
00216                         y0 -= dif;
00217                 }
00218 
00219                 if (x0 >= nx - 2 || y0 >= ny - 1) continue;
00220 
00221 
00222 
00223 
00224                 for (int j = 0; j < 4; j++)
00225                 {
00226                         int k = i + offset[j];
00227                         rdata[k] += g[j] * dt[0];
00228                         rdata[k + 1] += g[j] * dt[1];
00229                         norm[k/2] += g[j];
00230 
00231                 }
00232         }
00233 
00234         return 0;
00235 
00236 }
00237 
00238 EMData *FourierReconstructorSimple2D::finish(bool doift)
00239 {
00240         normalize_threed();
00241 
00242         image->process_inplace("xform.fourierorigin.tocorner");
00243         image->do_ift_inplace();
00244         image->depad();
00245         image->process_inplace("xform.phaseorigin.tocenter");
00246 
00247         return          image;
00248 }
00249 
00250 void ReconstructorVolumeData::normalize_threed(const bool sqrt_damp,const bool wiener)
00251 // normalizes the 3-D Fourier volume. Also imposes appropriate complex conjugate relationships
00252 {
00253         float* norm = tmp_data->get_data();
00254         float* rdata = image->get_data();
00255 
00256 //      printf("%d %d %d %d %d %d\n",subnx,subny,subnz,image->get_xsize(),image->get_ysize(),image->get_zsize());
00257 
00258         // FIXME should throw a sensible error
00259         if ( 0 == norm ) throw NullPointerException("The normalization volume was null!");
00260         if ( 0 == rdata ) throw NullPointerException("The complex reconstruction volume was null!");
00261 
00262         // The math is a bit tricky to explain. Wiener filter is basically SNR/(1+SNR)
00263         // In this case, data have already been effectively multiplied by SNR (one image at a time),
00264         // so without Wiener filter, we just divide by total SNR. With Wiener filter, we just add
00265         // 1.0 to total SNR, and we're done             --steve
00266         float wfilt=0.0;
00267         if (wiener) wfilt=1.0;          
00268         
00269         for (int i = 0; i < subnx * subny * subnz; i += 2) {
00270                 float d = norm[i/2];
00271                 if (sqrt_damp) d*=sqrt(d);
00272                 if (d == 0) {
00273                         rdata[i] = 0;
00274                         rdata[i + 1] = 0;
00275                 }
00276                 else {
00277 //                      rdata[i]=1.0/d;
00278 //                      rdata[i+1]=0.0;         // for debugging only
00279                         rdata[i] /= d+wfilt;
00280                         rdata[i + 1] /= d+wfilt;
00281                 }
00282         }
00283 
00284         // enforce complex conj, only works on subvolumes if the complete conjugate plane is in the volume
00285         if (subx0==0 && subnx>1 && subny==ny && subnz==nz) {
00286                 for (int z=0; z<=nz/2; z++) {
00287                         for (int y=1; y<=ny; y++) {
00288                                 if (y==0 && z==0) continue;
00289                                 // x=0
00290                                 int i=(y%ny)*subnx+(z%nz)*subnx*subny;
00291                                 int i2=(ny-y)*subnx+((nz-z)%nz)*subnx*subny;
00292                                 float ar=(rdata[i]+rdata[i2])/2.0f;
00293                                 float ai=(rdata[i+1]-rdata[i2+1])/2.0f;
00294                                 rdata[i]=ar;
00295                                 rdata[i2]=ar;
00296                                 rdata[i+1]=ai;
00297                                 rdata[i2+1]=-ai;
00298                         }
00299                 }
00300         }
00301 
00302         if (subx0+subnx==nx && subnx>1 && subny==ny && subnz==nz) {
00303                 for (int z=0; z<=nz/2; z++) {
00304                         for (int y=1; y<=ny; y++) {
00305                                 if (y==0 && z==0) continue;
00306                                 // x=0
00307                                 int i=(y%ny)*subnx+(z%nz)*subnx*subny+subnx-2;
00308                                 int i2=(ny-y)*subnx+((nz-z)%nz)*subnx*subny+subnx-2;
00309                                 float ar=(rdata[i]+rdata[i2])/2.0f;
00310                                 float ai=(rdata[i+1]-rdata[i2+1])/2.0f;
00311                                 rdata[i]=ar;
00312                                 rdata[i2]=ar;
00313                                 rdata[i+1]=ai;
00314                                 rdata[i2+1]=-ai;
00315                         }
00316                 }
00317         }
00318 }
00319 
00320 void FourierReconstructor::load_default_settings()
00321 {
00322         inserter=0;
00323         image=0;
00324         tmp_data=0;
00325 }
00326 
00327 void FourierReconstructor::free_memory()
00328 {
00329         if (image) { delete image; image=0; }
00330         if (tmp_data) { delete tmp_data; tmp_data=0; }
00331         if ( inserter != 0 )
00332         {
00333                 delete inserter;
00334                 inserter = 0;
00335         }
00336 }
00337 
00338 #include <sstream>
00339 
00340 void FourierReconstructor::load_inserter()
00341 {
00342 //      ss
00343 //      string mode = (string)params["mode"];
00344         Dict parms;
00345         parms["data"] = image;
00346         parms["norm"] = tmp_data->get_data();
00347         // These aren't necessary because we deal with them before calling the inserter
00348 //      parms["subnx"] = nx;
00349 //      parms["subny"] = ny;
00350 //      parms["subnx"] = nz;
00351 //      parms["subx0"] = x0;
00352 //      parms["suby0"] = y0;
00353 //      parms["subz0"] = z0;
00354 
00355         if ( inserter != 0 )
00356         {
00357                 delete inserter;
00358         }
00359 
00360         inserter = Factory<FourierPixelInserter3D>::get((string)params["mode"], parms);
00361         inserter->init();
00362 }
00363 
00364 void FourierReconstructor::setup()
00365 {
00366         // default setting behavior - does not override if the parameter is already set
00367         params.set_default("mode","gauss_2");
00368 
00369         vector<int> size=params["size"];
00370 
00371         nx = size[0];
00372         ny = size[1];
00373         nz = size[2];
00374         nx2=nx/2-1;
00375         ny2=ny/2;
00376         nz2=nz/2;
00377 
00378 
00379         // Adjust nx if for Fourier transform even odd issues
00380         bool is_fftodd = (nx % 2 == 1);
00381         // The Fourier transform requires one extra pixel in the x direction,
00382         // which is two spaces in memory, one each for the complex and the
00383         // real components
00384         nx += 2-is_fftodd;
00385 
00386         if (params.has_key("subvolume")) {
00387                 vector<int> sub=params["subvolume"];
00388                 subx0=sub[0];
00389                 suby0=sub[1];
00390                 subz0=sub[2];
00391                 subnx=sub[3];
00392                 subny=sub[4];
00393                 subnz=sub[5];
00394 
00395                 if (subx0<0 || suby0<0 || subz0<0 || subx0+subnx>nx || suby0+subny>ny || subz0+subnz>nz)
00396                         throw ImageDimensionException("The subvolume cannot extend outside the reconstructed volume");
00397 
00398         }
00399         else {
00400                 subx0=suby0=subz0=0;
00401                 subnx=nx;
00402                 subny=ny;
00403                 subnz=nz;
00404         }
00405 
00406 
00407         // Odd dimension support is here atm, but not above.
00408         if (image) delete image;
00409         image = new EMData();
00410         image->set_size(subnx, subny, subnz);
00411         image->set_complex(true);
00412         image->set_fftodd(is_fftodd);
00413         image->set_ri(true);
00414         image->to_zero();
00415 
00416         if (params.has_key("subvolume")) {
00417                 image->set_attr("subvolume_x0",subx0);
00418                 image->set_attr("subvolume_y0",suby0);
00419                 image->set_attr("subvolume_z0",subz0);
00420                 image->set_attr("subvolume_full_nx",nx);
00421                 image->set_attr("subvolume_full_ny",ny);
00422                 image->set_attr("subvolume_full_nz",nz);
00423         }
00424         
00425         if (tmp_data) delete tmp_data;
00426         tmp_data = new EMData();
00427         tmp_data->set_size(subnx/2, subny, subnz);
00428         tmp_data->to_zero();
00429         tmp_data->update();
00430 
00431         load_inserter();
00432 
00433         if ( (bool) params["quiet"] == false )
00434         {
00435                 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
00436                 cout << "3D Fourier subvolume is " << subnx << " " << subny << " " << subnz << endl;
00437                 cout << "You will require approximately " << setprecision(3) << (subnx*subny*subnz*sizeof(float)*1.5)/1000000000.0 << "GB of memory to reconstruct this volume" << endl;
00438         }
00439 }
00440 
00441 void FourierReconstructor::setup_seed(EMData* seed,float seed_weight) {
00442         // default setting behavior - does not override if the parameter is already set
00443         params.set_default("mode","gauss_2");
00444 
00445         vector<int> size=params["size"];
00446 
00447         nx = size[0];
00448         ny = size[1];
00449         nz = size[2];
00450         nx2=nx/2-1;
00451         ny2=ny/2;
00452         nz2=nz/2;
00453 
00454 
00455         // Adjust nx if for Fourier transform even odd issues
00456         bool is_fftodd = (nx % 2 == 1);
00457         // The Fourier transform requires one extra pixel in the x direction,
00458         // which is two spaces in memory, one each for the complex and the
00459         // real components
00460         nx += 2-is_fftodd;
00461 
00462         if (params.has_key("subvolume")) {
00463                 vector<int> sub=params["subvolume"];
00464                 subx0=sub[0];
00465                 suby0=sub[1];
00466                 subz0=sub[2];
00467                 subnx=sub[3];
00468                 subny=sub[4];
00469                 subnz=sub[5];
00470 
00471                 if (subx0<0 || suby0<0 || subz0<0 || subx0+subnx>nx || suby0+subny>ny || subz0+subnz>nz)
00472                         throw ImageDimensionException("The subvolume cannot extend outside the reconstructed volume");
00473 
00474         }
00475         else {
00476                 subx0=suby0=subz0=0;
00477                 subnx=nx;
00478                 subny=ny;
00479                 subnz=nz;
00480         }
00481 
00482         if (seed->get_xsize()!=subnx || seed->get_ysize()!=subny || seed->get_zsize()!=subnz || !seed->is_complex())
00483                 throw ImageDimensionException("The dimensions of the seed volume do not match the reconstruction size");
00484 
00485         // Odd dimension support is here atm, but not above.
00486         image = seed;
00487         if (params.has_key("subvolume")) {
00488                 image->set_attr("subvolume_x0",subx0);
00489                 image->set_attr("subvolume_y0",suby0);
00490                 image->set_attr("subvolume_z0",subz0);
00491                 image->set_attr("subvolume_full_nx",nx);
00492                 image->set_attr("subvolume_full_ny",ny);
00493                 image->set_attr("subvolume_full_nz",nz);
00494         }
00495 
00496         if (tmp_data) delete tmp_data;
00497         tmp_data = new EMData();
00498         tmp_data->set_size(subnx/2, subny, subnz);
00499         tmp_data->to_value(seed_weight);
00500 
00501         load_inserter();
00502 
00503         if ( (bool) params["quiet"] == false )
00504         {
00505                 cout << "Seeded direct Fourier inversion";
00506                 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
00507                 cout << "3D Fourier subvolume is " << subnx << " " << subny << " " << subnz << endl;
00508                 cout << "You will require approximately " << setprecision(3) << (subnx*subny*subnz*sizeof(float)*1.5)/1000000000.0 << "GB of memory to reconstruct this volume" << endl;
00509         }
00510 }
00511 
00512 
00513 EMData* FourierReconstructor::preprocess_slice( const EMData* const slice,  const Transform& t )
00514 {
00515         // Shift the image pixels so the real space origin is now located at the phase origin (at the bottom left of the image)
00516         EMData* return_slice = 0;
00517         Transform tmp(t);
00518         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly, this way we only do 2d translation,scaling and mirroring
00519 
00520         if (tmp.is_identity()) return_slice=slice->copy();
00521         else return_slice = slice->process("xform",Dict("transform",&tmp));
00522 
00523         return_slice->process_inplace("xform.phaseorigin.tocorner");
00524 
00525 //      printf("@@@ %d\n",(int)return_slice->get_attr("nx"));
00526         // Fourier transform the slice
00527         return_slice->do_fft_inplace();
00528 
00529 //      printf("%d\n",(int)return_slice->get_attr("nx"));
00530 
00531         return_slice->mult((float)sqrt(1.0f/(return_slice->get_ysize())*return_slice->get_xsize()));
00532 
00533         // Shift the Fourier transform so that it's origin is in the center (bottom) of the image.
00534 //      return_slice->process_inplace("xform.fourierorigin.tocenter");
00535 
00536         return_slice->set_attr("reconstruct_preproc",(int)1);
00537         return return_slice;
00538 }
00539 
00540 
00541 int FourierReconstructor::insert_slice(const EMData* const input_slice, const Transform & arg, const float weight)
00542 {
00543         // Are these exceptions really necessary? (d.woolford)
00544         if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
00545 
00546         Transform * rotation;
00547 /*      if ( input_slice->has_attr("xform.projection") ) {
00548                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
00549         } else {*/
00550         rotation = new Transform(arg); // assignment operator
00551 //      }
00552 
00553         EMData *slice;
00554         if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
00555         else slice = preprocess_slice( input_slice, *rotation);
00556 
00557 
00558         // We must use only the rotational component of the transform, scaling, translation and mirroring
00559         // are not implemented in Fourier space, but are in preprocess_slice
00560         rotation->set_scale(1.0);
00561         rotation->set_mirror(false);
00562         rotation->set_trans(0,0,0);
00563 
00564         // Finally to the pixel wise slice insertion
00565         do_insert_slice_work(slice, *rotation, weight);
00566 
00567         delete rotation; rotation=0;
00568         delete slice;
00569 
00570 //      image->update();
00571         return 0;
00572 }
00573 
00574 void FourierReconstructor::do_insert_slice_work(const EMData* const input_slice, const Transform & arg,const float weight)
00575 {
00576         // Reload the inserter if the mode has changed
00577 //      string mode = (string) params["mode"];
00578 //      if ( mode != inserter->get_name() )     load_inserter();
00579 
00580 //      int y_in = input_slice->get_ysize();
00581 //      int x_in = input_slice->get_xsize();
00582 //      // Adjust the dimensions to account for odd and even ffts
00583 //      if (input_slice->is_fftodd()) x_in -= 1;
00584 //      else x_in -= 2;
00585 
00586         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
00587 
00588         float inx=(float)(input_slice->get_xsize());            // x/y dimensions of the input image
00589         float iny=(float)(input_slice->get_ysize());
00590 
00591         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
00592                 Transform t3d = arg*(*it);
00593                 for (int y = -iny/2; y < iny/2; y++) {
00594                         for (int x = 0; x <=  inx/2; x++) {
00595 
00596                                 float rx = (float) x/(inx-2.0f);        // coords relative to Nyquist=.5
00597                                 float ry = (float) y/iny;
00598 
00599                                 Vec3f coord(rx,ry,0);
00600                                 coord = coord*t3d; // transpose multiplication
00601                                 float xx = coord[0]; // transformed coordinates in terms of Nyquist
00602                                 float yy = coord[1];
00603                                 float zz = coord[2];
00604 
00605                                 // Map back to real pixel coordinates in output volume
00606                                 xx=xx*(nx-2);
00607                                 yy=yy*ny;
00608                                 zz=zz*nz;
00609 
00610 //                              if (x==10 && y==0) printf("10,0 -> %1.2f,%1.2f,%1.2f\t(%5.2f %5.2f %5.2f   %5.2f %5.2f %5.2f   %5.2f %5.2f %5.2f) %1.0f %d\n",
00611 //                                      xx,yy,zz,t3d.at(0,0),t3d.at(0,1),t3d.at(0,2),t3d.at(1,0),t3d.at(1,1),t3d.at(1,2),t3d.at(2,0),t3d.at(2,1),t3d.at(2,2),inx,nx);
00612 //                              if (x==0 && y==10) printf("0,10 -> %1.2f,%1.2f,%1.2f\t(%5.2f %5.2f %5.2f   %5.2f %5.2f %5.2f   %5.2f %5.2f %5.2f)\n",
00613 //                                      xx,yy,zz,t3d.at(0,0),t3d.at(0,1),t3d.at(0,2),t3d.at(1,0),t3d.at(1,1),t3d.at(1,2),t3d.at(2,0),t3d.at(2,1),t3d.at(2,2));
00614 
00615                                 //printf("%3.1f %3.1f %3.1f\t %1.4f %1.4f\t%1.4f\n",xx,yy,zz,input_slice->get_complex_at(x,y).real(),input_slice->get_complex_at(x,y).imag(),weight);
00616 //                              if (floor(xx)==45 && floor(yy)==45 &&floor(zz)==0) printf("%d. 45 45 0\t %d %d\t %1.4f %1.4f\t%1.4f\n",(int)input_slice->get_attr("n"),x,y,input_slice->get_complex_at(x,y).real(),input_slice->get_complex_at(x,y).imag(),weight);
00617 //                              if (floor(xx)==21 && floor(yy)==21 &&floor(zz)==0) printf("%d. 21 21 0\t %d %d\t %1.4f %1.4f\t%1.4f\n",(int)input_slice->get_attr("n"),x,y,input_slice->get_complex_at(x,y).real(),input_slice->get_complex_at(x,y).imag(),weight);
00618                                 inserter->insert_pixel(xx,yy,zz,input_slice->get_complex_at(x,y),weight);
00619                         }
00620                 }
00621         }
00622 }
00623 
00624 int FourierReconstructor::determine_slice_agreement(EMData*  input_slice, const Transform & arg, const float weight,bool sub)
00625 {
00626         // Are these exceptions really necessary? (d.woolford)
00627         if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
00628 
00629         Transform * rotation;
00630         rotation = new Transform(arg); // assignment operator
00631 
00632         EMData *slice;
00633         if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
00634         else slice = preprocess_slice( input_slice, *rotation);
00635 
00636 
00637         // We must use only the rotational component of the transform, scaling, translation and mirroring
00638         // are not implemented in Fourier space, but are in preprocess_slice
00639         rotation->set_scale(1.0);
00640         rotation->set_mirror(false);
00641         rotation->set_trans(0,0,0);
00642 
00643         // Remove the current slice first (not threadsafe, but otherwise performance would be awful)
00644         if (sub) do_insert_slice_work(slice, *rotation, -weight);
00645 
00646         // Compare
00647         do_compare_slice_work(slice, *rotation,weight);
00648 
00649         input_slice->set_attr("reconstruct_norm",slice->get_attr("reconstruct_norm"));
00650         input_slice->set_attr("reconstruct_absqual",slice->get_attr("reconstruct_absqual"));
00651 //      input_slice->set_attr("reconstruct_qual",slice->get_attr("reconstruct_qual"));
00652         input_slice->set_attr("reconstruct_weight",slice->get_attr("reconstruct_weight"));
00653 
00654         // Now put the slice back
00655         if (sub) do_insert_slice_work(slice, *rotation, weight);
00656 
00657 
00658         delete rotation;
00659         delete slice;
00660 
00661 //      image->update();
00662         return 0;
00663 
00664 }
00665 
00666 void FourierReconstructor::do_compare_slice_work(EMData* input_slice, const Transform & arg,float weight)
00667 {
00668 
00669         float dt[3];    // This stores the complex and weight from the volume
00670         float dt2[2];   // This stores the local image complex
00671         float *dat = input_slice->get_data();
00672         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
00673 
00674         float inx=(float)(input_slice->get_xsize());            // x/y dimensions of the input image
00675         float iny=(float)(input_slice->get_ysize());
00676 
00677         double dot=0;           // summed pixel*weight dot product
00678         double vweight=0;               // sum of weights
00679         double power=0;         // sum of inten*weight from volume
00680         double power2=0;                // sum of inten*weight from image
00681         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
00682                 Transform t3d = arg*(*it);
00683                 for (int y = -iny/2; y < iny/2; y++) {
00684                         for (int x = 0; x <=  inx/2; x++) {
00685                                 if (x==0 && y==0) continue;             // We don't want to use the Fourier origin
00686 
00687                                 float rx = (float) x/(inx-2);   // coords relative to Nyquist=.5
00688                                 float ry = (float) y/iny;
00689 
00690 //                              if ((rx * rx + Util::square(ry - max_input_dim / 2)) > rl)
00691 //                                      continue;
00692 
00693                                 Vec3f coord(rx,ry,0);
00694                                 coord = coord*t3d; // transpose multiplication
00695                                 float xx = coord[0]; // transformed coordinates in terms of Nyquist
00696                                 float yy = coord[1];
00697                                 float zz = coord[2];
00698 
00699 
00700                                 if (fabs(xx)>0.5 || fabs(yy)>=0.5 || fabs(zz)>=0.5) continue;
00701 
00702                                 // Map back to actual pixel coordinates in output volume
00703                                 xx=xx*(nx-2);
00704                                 yy=yy*ny;
00705                                 zz=zz*nz;
00706 
00707 
00708                                 int idx = (int)(x * 2 + inx*(y<0?iny+y:y));
00709                                 dt2[0] = dat[idx];
00710                                 dt2[1] = dat[idx+1];
00711 
00712                                 // value returned indirectly in dt
00713                                 if (!pixel_at(xx,yy,zz,dt) || dt[2]==0) continue;
00714 
00715 //                              printf("%f\t%f\t%f\t%f\t%f\n",dt[0],dt[1],dt[2],dt2[0],dt2[1]);
00716                                 dot+=(dt[0]*dt2[0]+dt[1]*dt2[1])*dt[2];
00717                                 vweight+=dt[2];
00718                                 power+=(dt[0]*dt[0]+dt[1]*dt[1])*dt[2];
00719                                 power2+=(dt2[0]*dt2[0]+dt2[1]*dt2[1])*dt[2];
00720                         }
00721                 }
00722         }
00723 
00724         dot/=sqrt(power*power2);                // normalize the dot product
00725 //      input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)/(inx*iny)));
00726         input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)));
00727         input_slice->set_attr("reconstruct_absqual",(float)dot);
00728         float rw=weight<=0?1.0f:1.0f/weight;
00729         input_slice->set_attr("reconstruct_qual",(float)(dot*rw/((rw-1.0)*dot+1.0)));   // here weight is a proxy for SNR
00730         input_slice->set_attr("reconstruct_weight",(float)vweight/(float)(subnx*subny*subnz));
00731 //      printf("** %g\t%g\t%g\t%g ##\n",dot,vweight,power,power2);
00732         //printf("** %f %f %f ##\n",(float)(power2<=0?1.0:sqrt(power/power2)/(inx*iny)),(float)dot,(float)(dot*weight/((weight-1.0)*dot+1.0)));
00733 }
00734 
00735 bool FourierReconstructor::pixel_at(const float& xx, const float& yy, const float& zz, float *dt)
00736 {
00737         int x0 = (int) floor(xx);
00738         int y0 = (int) floor(yy);
00739         int z0 = (int) floor(zz);
00740         
00741         float *rdata=image->get_data();
00742         float *norm=tmp_data->get_data();
00743         float normsum=0,normsum2=0;
00744 
00745         dt[0]=dt[1]=dt[2]=0.0;
00746 
00747         if (nx==subnx) {                        // normal full reconstruction
00748                 if (x0<-nx2-1 || y0<-ny2-1 || z0<-nz2-1 || x0>nx2 || y0>ny2 || z0>nz2 ) return false;
00749 
00750                 // no error checking on add_complex_fast, so we need to be careful here
00751                 int x1=x0+1;
00752                 int y1=y0+1;
00753                 int z1=z0+1;
00754                 if (x0<-nx2) x0=-nx2;
00755                 if (x1>nx2) x1=nx2;
00756                 if (y0<-ny2) y0=-ny2;
00757                 if (y1>ny2) y1=ny2;
00758                 if (z0<-nz2) z0=-nz2;
00759                 if (z1>nz2) z1=nz2;
00760                 
00761                 size_t idx=0;
00762                 float r, gg;
00763                 for (int k = z0 ; k <= z1; k++) {
00764                         for (int j = y0 ; j <= y1; j++) {
00765                                 for (int i = x0; i <= x1; i ++) {
00766                                         r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
00767                                         idx=image->get_complex_index_fast(i,j,k);
00768                                         gg = Util::fast_exp(-r / EMConsts::I2G);
00769                                         
00770                                         dt[0]+=gg*rdata[idx];
00771                                         dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
00772                                         dt[2]+=norm[idx/2]*gg;
00773                                         normsum2+=gg;
00774                                         normsum+=gg*norm[idx/2];                                
00775                                 }
00776                         }
00777                 }
00778                 if (normsum==0) return false;
00779                 dt[0]/=normsum;
00780                 dt[1]/=normsum;
00781                 dt[2]/=normsum2;
00782 //              printf("%1.2f,%1.2f,%1.2f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\n",xx,yy,zz,dt[0],dt[1],dt[2],rdata[idx],rdata[idx+1]);
00783                 return true;
00784         } 
00785         else {                                  // for subvolumes, not optimized yet
00786                 size_t idx;
00787                 float r, gg;
00788                 for (int k = z0 ; k <= z0 + 1; k++) {
00789                         for (int j = y0 ; j <= y0 + 1; j++) {
00790                                 for (int i = x0; i <= x0 + 1; i ++) {
00791                                         r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
00792                                         idx=image->get_complex_index(i,j,k,subx0,suby0,subz0,nx,ny,nz);
00793                                         gg = Util::fast_exp(-r / EMConsts::I2G)*norm[idx/2];
00794                                         
00795                                         dt[0]+=gg*rdata[idx];
00796                                         dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
00797                                         dt[2]+=norm[idx/2];
00798                                         normsum+=gg;                            
00799                                 }
00800                         }
00801                 }
00802                 
00803                 if (normsum==0)  return false;
00804                 return true;
00805         }
00806 }
00807 
00808 
00809 EMData *FourierReconstructor::finish(bool doift)
00810 {
00811 //      float *norm = tmp_data->get_data();
00812 //      float *rdata = image->get_data();
00813 
00814         bool sqrtnorm=params.set_default("sqrtnorm",false);
00815         normalize_threed(sqrtnorm);
00816 
00817 //      tmp_data->write_image("density.mrc");
00818 
00819         // we may as well delete the tmp data now... it saves memory and the calling program might
00820         // need memory after it gets the return volume.
00821         // If this delete didn't happen now, it would happen when the deconstructor was called --david
00822         // no longer a good idea with the new iterative scheme -- steve
00823 //      if ( tmp_data != 0 )
00824 //      {
00825 //              delete tmp_data;
00826 //              tmp_data = 0;
00827 //      }
00828 
00829 /*      image->process_inplace("xform.fourierorigin.tocorner");*/
00830 
00831         if (doift) {
00832                 image->do_ift_inplace();
00833                 image->depad();
00834                 image->process_inplace("xform.phaseorigin.tocenter");
00835         }
00836         // If the image was padded it should be the original size, as the client would expect
00837         //  I blocked the rest, it is almost certainly incorrect  PAP 07/31/08
00838         // No, it's not incorrect. You are wrong. You have the meaning of nx mixed up. DSAW 09/23/cd
00839         // This should now be handled in the calling program --steve 11/03/09
00840 //      bool is_fftodd = (nx % 2 == 1);
00841 //      if ( (nx-2*(!is_fftodd)) != output_x || ny != output_y || nz != output_z )
00842 //      {
00843 //              FloatPoint origin( (nx-output_x)/2, (ny-output_y)/2, (nz-output_z)/2 );
00844 //              FloatSize region_size( output_x, output_y, output_z);
00845 //              Region clip_region( origin, region_size );
00846 //              image->clip_inplace( clip_region );
00847 //      }
00848 
00849         // Should be an "if (verbose)" here or something
00850         //print_stats(quality_scores);
00851 
00852         image->update();
00853         
00854         if (params.has_key("savenorm") && strlen((const char *)params["savenorm"])>0) {
00855                 if (tmp_data->get_ysize()%2==0 && tmp_data->get_zsize()%2==0) tmp_data->process_inplace("xform.fourierorigin.tocenter");
00856                 tmp_data->write_image((const char *)params["savenorm"]);
00857         }
00858 
00859         delete tmp_data;
00860         tmp_data=0;
00861         EMData *ret=image;
00862         image=0;
00863         
00864         return ret;
00865 }
00866 
00867 int WienerFourierReconstructor::insert_slice(const EMData* const input_slice, const Transform & arg, const float weight)
00868 {
00869         // Are these exceptions really necessary? (d.woolford)
00870         if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
00871 
00872         Transform * rotation;
00873 /*      if ( input_slice->has_attr("xform.projection") ) {
00874                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
00875         } else {*/
00876         rotation = new Transform(arg); // assignment operator
00877 //      }
00878 
00879         if (!input_slice->has_attr("ctf_snr_total")) 
00880                 throw NotExistingObjectException("ctf_snr_total","No SNR information present in class-average. Must use the ctf.auto or ctfw.auto averager.");
00881 
00882         EMData *slice;
00883         if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
00884         else slice = preprocess_slice( input_slice, *rotation);
00885 
00886 
00887         // We must use only the rotational component of the transform, scaling, translation and mirroring
00888         // are not implemented in Fourier space, but are in preprocess_slice
00889         rotation->set_scale(1.0);
00890         rotation->set_mirror(false);
00891         rotation->set_trans(0,0,0);
00892 
00893         // Finally to the pixel wise slice insertion
00894         do_insert_slice_work(slice, *rotation, weight);
00895 
00896         delete rotation; rotation=0;
00897         delete slice;
00898 
00899 //      image->update();
00900         return 0;
00901 }
00902 
00903 void WienerFourierReconstructor::do_insert_slice_work(const EMData* const input_slice, const Transform & arg,const float inweight)
00904 {
00905 
00906         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
00907 
00908         float inx=(float)(input_slice->get_xsize());            // x/y dimensions of the input image
00909         float iny=(float)(input_slice->get_ysize());
00910         
00911         int undo_wiener=(int)input_slice->get_attr_default("ctf_wiener_filtered",0);    // indicates whether we need to undo a wiener filter before insertion
00912 //      if (undo_wiener) throw UnexpectedBehaviorException("wiener_fourier does not yet accept already Wiener filtered class-averages. Suggest using ctf.auto averager for now.");
00913         
00914         vector<float> snr=input_slice->get_attr("ctf_snr_total");
00915         float sub=1.0;
00916         if (inweight<0) sub=-1.0;
00917         float weight;
00918         
00919         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
00920                 Transform t3d = arg*(*it);
00921                 for (int y = -iny/2; y < iny/2; y++) {
00922                         for (int x = 0; x <=  inx/2; x++) {
00923 
00924                                 float rx = (float) x/(inx-2.0f);        // coords relative to Nyquist=.5
00925                                 float ry = (float) y/iny;
00926 
00927                                 // This deals with the SNR weight
00928                                 float rn = hypot(rx,ry);
00929                                 if (rn>=.5) continue;           // no SNR in the corners, and we're going to mask them later anyway
00930                                 rn*=snr.size()*2.0;
00931                                 int rni=(int)floor(rn);
00932                                 if (rni>=snr.size()-1) weight=snr[snr.size()-1]*sub;
00933                                 else {
00934                                         rn-=rni;
00935                                         weight=Util::linear_interpolate(snr[rni],snr[rni+1],rn);
00936                                 }
00937 //                              if (weight>500.0) printf("%f %d %d %f %f %d %f\n",weight,x,y,rx,ry,rni);
00938                                 
00939                                 Vec3f coord(rx,ry,0);
00940                                 coord = coord*t3d; // transpose multiplication
00941                                 float xx = coord[0]; // transformed coordinates in terms of Nyquist
00942                                 float yy = coord[1];
00943                                 float zz = coord[2];
00944 
00945                                 // Map back to real pixel coordinates in output volume
00946                                 xx=xx*(nx-2);
00947                                 yy=yy*ny;
00948                                 zz=zz*nz;
00949 
00950 //                              printf("%f\n",weight);
00951                                 if (undo_wiener) inserter->insert_pixel(xx,yy,zz,(input_slice->get_complex_at(x,y))*((weight+1.0f)/weight),weight*sub);
00952                                 else inserter->insert_pixel(xx,yy,zz,input_slice->get_complex_at(x,y),weight*sub);
00953                         }
00954                 }
00955         }
00956 }
00957 
00958 int WienerFourierReconstructor::determine_slice_agreement(EMData*  input_slice, const Transform & arg, const float weight,bool sub)
00959 {
00960         // Are these exceptions really necessary? (d.woolford)
00961         if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
00962 
00963         Transform * rotation;
00964         rotation = new Transform(arg); // assignment operator
00965 
00966         EMData *slice;
00967         if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
00968         else slice = preprocess_slice( input_slice, *rotation);
00969 
00970 
00971         // We must use only the rotational component of the transform, scaling, translation and mirroring
00972         // are not implemented in Fourier space, but are in preprocess_slice
00973         rotation->set_scale(1.0);
00974         rotation->set_mirror(false);
00975         rotation->set_trans(0,0,0);
00976 
00977 //      tmp_data->write_image("dbug.hdf",0);
00978         
00979         // Remove the current slice first (not threadsafe, but otherwise performance would be awful)
00980         if (sub) do_insert_slice_work(slice, *rotation, -weight);
00981 
00982         // Compare
00983         do_compare_slice_work(slice, *rotation,weight);
00984 
00985         input_slice->set_attr("reconstruct_norm",slice->get_attr("reconstruct_norm"));
00986         input_slice->set_attr("reconstruct_absqual",slice->get_attr("reconstruct_absqual"));
00987 //      input_slice->set_attr("reconstruct_qual",slice->get_attr("reconstruct_qual"));
00988         input_slice->set_attr("reconstruct_weight",slice->get_attr("reconstruct_weight"));
00989 
00990         // Now put the slice back
00991         if (sub) do_insert_slice_work(slice, *rotation, weight);
00992 
00993 
00994         delete rotation;
00995         delete slice;
00996 
00997 //      image->update();
00998         return 0;
00999 
01000 }
01001 
01002 void WienerFourierReconstructor::do_compare_slice_work(EMData* input_slice, const Transform & arg,float weight)
01003 {
01004 
01005         float dt[3];    // This stores the complex and weight from the volume
01006         float dt2[2];   // This stores the local image complex
01007         float *dat = input_slice->get_data();
01008         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
01009 
01010         float inx=(float)(input_slice->get_xsize());            // x/y dimensions of the input image
01011         float iny=(float)(input_slice->get_ysize());
01012 
01013         double dot=0;           // summed pixel*weight dot product
01014         double vweight=0;               // sum of weights
01015         double power=0;         // sum of inten*weight from volume
01016         double power2=0;                // sum of inten*weight from image
01017         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
01018                 Transform t3d = arg*(*it);
01019                 for (int y = -iny/2; y < iny/2; y++) {
01020                         for (int x = 0; x <=  inx/2; x++) {
01021                                 if (x==0 && y==0) continue;             // We don't want to use the Fourier origin
01022 
01023                                 float rx = (float) x/(inx-2);   // coords relative to Nyquist=.5
01024                                 float ry = (float) y/iny;
01025 
01026 //                              if ((rx * rx + Util::square(ry - max_input_dim / 2)) > rl)
01027 //                                      continue;
01028 
01029                                 Vec3f coord(rx,ry,0);
01030                                 coord = coord*t3d; // transpose multiplication
01031                                 float xx = coord[0]; // transformed coordinates in terms of Nyquist
01032                                 float yy = coord[1];
01033                                 float zz = coord[2];
01034 
01035 
01036                                 if (fabs(xx)>0.5 || fabs(yy)>=0.5 || fabs(zz)>=0.5) continue;
01037 
01038                                 // Map back to actual pixel coordinates in output volume
01039                                 xx=xx*(nx-2);
01040                                 yy=yy*ny;
01041                                 zz=zz*nz;
01042 
01043 
01044                                 int idx = (int)(x * 2 + inx*(y<0?iny+y:y));
01045                                 dt2[0] = dat[idx];
01046                                 dt2[1] = dat[idx+1];
01047 
01048                                 // value returned indirectly in dt
01049                                 if (!pixel_at(xx,yy,zz,dt) || dt[2]<=0) continue;
01050 
01051 //                              printf("%f\t%f\t%f\t%f\t%f\n",dt[0],dt[1],dt[2],dt2[0],dt2[1]);
01052                                 dot+=(dt[0]*dt2[0]+dt[1]*dt2[1])*dt[2];
01053                                 vweight+=dt[2];
01054                                 power+=(dt[0]*dt[0]+dt[1]*dt[1])*dt[2];
01055                                 power2+=(dt2[0]*dt2[0]+dt2[1]*dt2[1])*dt[2];
01056                         }
01057                 }
01058         }
01059 
01060         dot/=sqrt(power*power2);                // normalize the dot product
01061 //      input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)/(inx*iny)));
01062         input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)));
01063         input_slice->set_attr("reconstruct_absqual",(float)dot);
01064         float rw=weight<=0?1.0f:1.0f/weight;
01065         input_slice->set_attr("reconstruct_qual",(float)(dot*rw/((rw-1.0)*dot+1.0)));   // here weight is a proxy for SNR
01066         input_slice->set_attr("reconstruct_weight",(float)vweight/(float)(subnx*subny*subnz));
01067 //      printf("** %g\t%g\t%g\t%g ##\n",dot,vweight,power,power2);
01068         //printf("** %f %f %f ##\n",(float)(power2<=0?1.0:sqrt(power/power2)/(inx*iny)),(float)dot,(float)(dot*weight/((weight-1.0)*dot+1.0)));
01069 }
01070 
01071 bool WienerFourierReconstructor::pixel_at(const float& xx, const float& yy, const float& zz, float *dt)
01072 {
01073         int x0 = (int) floor(xx);
01074         int y0 = (int) floor(yy);
01075         int z0 = (int) floor(zz);
01076         
01077         float *rdata=image->get_data();
01078         float *norm=tmp_data->get_data();
01079         float normsum=0,normsum2=0;
01080 
01081         dt[0]=dt[1]=dt[2]=0.0;
01082 
01083         if (nx==subnx) {                        // normal full reconstruction
01084                 if (x0<-nx2-1 || y0<-ny2-1 || z0<-nz2-1 || x0>nx2 || y0>ny2 || z0>nz2 ) return false;
01085 
01086                 // no error checking on add_complex_fast, so we need to be careful here
01087                 int x1=x0+1;
01088                 int y1=y0+1;
01089                 int z1=z0+1;
01090                 if (x0<-nx2) x0=-nx2;
01091                 if (x1>nx2) x1=nx2;
01092                 if (y0<-ny2) y0=-ny2;
01093                 if (y1>ny2) y1=ny2;
01094                 if (z0<-nz2) z0=-nz2;
01095                 if (z1>nz2) z1=nz2;
01096                 
01097                 size_t idx=0;
01098                 float r, gg;
01099                 for (int k = z0 ; k <= z1; k++) {
01100                         for (int j = y0 ; j <= y1; j++) {
01101                                 for (int i = x0; i <= x1; i ++) {
01102                                         r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
01103                                         idx=image->get_complex_index_fast(i,j,k);
01104                                         gg = Util::fast_exp(-r / EMConsts::I2G);
01105                                         
01106                                         dt[0]+=gg*rdata[idx];
01107                                         dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
01108                                         dt[2]+=norm[idx/2]*gg;
01109                                         normsum2+=gg;
01110                                         normsum+=gg*norm[idx/2];                                
01111                                 }
01112                         }
01113                 }
01114                 if (normsum==0) return false;
01115                 dt[0]/=normsum;
01116                 dt[1]/=normsum;
01117                 dt[2]/=normsum2;
01118 //              printf("%1.2f,%1.2f,%1.2f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\n",xx,yy,zz,dt[0],dt[1],dt[2],rdata[idx],rdata[idx+1]);
01119                 return true;
01120         } 
01121         else {                                  // for subvolumes, not optimized yet
01122                 size_t idx;
01123                 float r, gg;
01124                 for (int k = z0 ; k <= z0 + 1; k++) {
01125                         for (int j = y0 ; j <= y0 + 1; j++) {
01126                                 for (int i = x0; i <= x0 + 1; i ++) {
01127                                         r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
01128                                         idx=image->get_complex_index(i,j,k,subx0,suby0,subz0,nx,ny,nz);
01129                                         gg = Util::fast_exp(-r / EMConsts::I2G)*norm[idx/2];
01130                                         
01131                                         dt[0]+=gg*rdata[idx];
01132                                         dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
01133                                         dt[2]+=norm[idx/2];
01134                                         normsum+=gg;                            
01135                                 }
01136                         }
01137                 }
01138                 
01139                 if (normsum==0)  return false;
01140                 return true;
01141         }
01142 }
01143 
01144 
01145 EMData *WienerFourierReconstructor::finish(bool doift)
01146 {
01147 
01148         bool sqrtnorm=params.set_default("sqrtnorm",false);
01149         normalize_threed(sqrtnorm,true);                // true is the wiener filter
01150 
01151         if (doift) {
01152                 image->do_ift_inplace();
01153                 image->depad();
01154                 image->process_inplace("xform.phaseorigin.tocenter");
01155         }
01156 
01157         image->update();
01158         
01159         if (params.has_key("savenorm") && strlen((const char *)params["savenorm"])>0) {
01160                 if (tmp_data->get_ysize()%2==0 && tmp_data->get_zsize()%2==0) tmp_data->process_inplace("xform.fourierorigin.tocenter");
01161                 tmp_data->write_image((const char *)params["savenorm"]);
01162         }
01163 
01164         delete tmp_data;
01165         tmp_data=0;
01166         EMData *ret=image;
01167         image=0;
01168         
01169         return ret;
01170 }
01171 
01172 /*
01173 void BaldwinWoolfordReconstructor::setup()
01174 {
01175         //This is a bit of a hack - but for now it suffices
01176         params.set_default("mode","nearest_neighbor");
01177         WienerFourierReconstructor::setup();
01178         // Set up the Baldwin Kernel
01179         int P = (int)((1.0+0.25)*max_input_dim+1);
01180         float r = (float)(max_input_dim+1)/(float)P;
01181         dfreq = 0.2f;
01182         if (W != 0) delete [] W;
01183         int maskwidth = params.set_default("maskwidth",2);
01184         W = Util::getBaldwinGridWeights(maskwidth, (float)P, r,dfreq,0.5f,0.2f);
01185 }
01186 
01187 EMData* BaldwinWoolfordReconstructor::finish(bool doift)
01188 {
01189         tmp_data->write_image("density.mrc");
01190         image->process_inplace("xform.fourierorigin.tocorner");
01191         image->do_ift_inplace();
01192         image->depad();
01193         image->process_inplace("xform.phaseorigin.tocenter");
01194 
01195         if ( (bool) params.set_default("postmultiply", false) )
01196         {
01197                 cout << "POST MULTIPLYING" << endl;
01198         // now undo the Fourier convolution with real space division
01199                 float* d = image->get_data();
01200                 float N = (float) image->get_xsize()/2.0f;
01201                 N *= N;
01202                 size_t rnx = image->get_xsize();
01203                 size_t rny = image->get_ysize();
01204                 size_t rnxy = rnx*rny;
01205                 int cx = image->get_xsize()/2;
01206                 int cy = image->get_ysize()/2;
01207                 int cz = image->get_zsize()/2;
01208                 size_t idx;
01209                 for (int k = 0; k < image->get_zsize(); ++k ){
01210                         for (int j = 0; j < image->get_ysize(); ++j ) {
01211                                 for (int i =0; i < image->get_xsize(); ++i ) {
01212                                         float xd = (float)(i-cx); xd *= xd;
01213                                         float yd = (float)(j-cy); yd *= yd;
01214                                         float zd = (float)(k-cz); zd *= zd;
01215                                         float weight = exp((xd+yd+zd)/N);
01216                                         idx = k*rnxy + j*rnx + i;
01217                                         d[idx] *=  weight;
01218                                 }
01219                         }
01220                 }
01221         }
01222         image->update();
01223         return  image;
01224 }
01225 
01226 #include <iomanip>
01227 
01228 // int BaldwinWoolfordReconstructor::insert_slice_weights(const Transform& t3d)
01229 // {
01230 //      bool fftodd = image->is_fftodd();
01231 //      int rnx = nx-2*!fftodd;
01232 //
01233 //      float y_scale = 1.0, x_scale = 1.0;
01234 //
01235 //      if ( ny != rnx  )
01236 //      {
01237 //              if ( rnx > ny ) y_scale = (float) rnx / (float) ny;
01238 //              else x_scale = (float) ny / (float) rnx;
01239 //      }
01240 //
01241 //      int tnx = tmp_data->get_xsize();
01242 //      int tny = tmp_data->get_ysize();
01243 //      int tnz = tmp_data->get_zsize();
01244 //
01245 //      vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
01246 //      for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
01247 //              Transform n3d = t3d*(*it);
01248 //
01249 //              for (int y = 0; y < tny; y++) {
01250 //                      for (int x = 0; x < tnx; x++) {
01251 //
01252 //                              float rx = (float) x;
01253 //                              float ry = (float) y;
01254 //
01255 //                              if ( ny != rnx )
01256 //                              {
01257 //                                      if ( rnx > ny ) ry *= y_scale;
01258 //                                      else rx *= x_scale;
01259 //                              }
01260 // //                           float xx = rx * n3d[0][0] + (ry - tny/2) * n3d[1][0];
01261 // //                           float yy = rx * n3d[0][1] + (ry - tny/2) * n3d[1][1];
01262 // //                           float zz = rx * n3d[0][2] + (ry - tny/2) * n3d[1][2];
01263 //
01264 //                              Vec3f coord(rx,(ry - tny/2),0);
01265 //                              coord = coord*n3d; // transpose multiplication
01266 //                              float xx = coord[0];
01267 //                              float yy = coord[1];
01268 //                              float zz = coord[2];
01269 //
01270 //                              if (xx < 0 ){
01271 //                                      xx = -xx;
01272 //                                      yy = -yy;
01273 //                                      zz = -zz;
01274 //                              }
01275 //
01276 //                              yy += tny/2;
01277 //                              zz += tnz/2;
01278 //                              insert_density_at(xx,yy,zz);
01279 //                      }
01280 //              }
01281 //      }
01282 //
01283 //      return 0;
01284 // }
01285 
01286 void BaldwinWoolfordReconstructor::insert_density_at(const float& x, const float& y, const float& z)
01287 {
01288         int xl = Util::fast_floor(x);
01289         int yl = Util::fast_floor(y);
01290         int zl = Util::fast_floor(z);
01291 
01292         // w is the windowing width
01293         int w = params.set_default("maskwidth",2);
01294         float wsquared = (float) w*w;
01295         float dw = 1.0f/w;
01296         dw *= dw;
01297 
01298         // w minus one - this control the number of
01299         // pixels/voxels to the left of the main pixel
01300         // that will have density
01301         int wmox = w-1;
01302         int wmoy = w-1;
01303         int wmoz = w-1;
01304 
01305         // If any coordinate is incedental with a vertex, then
01306         // make sure there is symmetry in density accruing.
01307         // i.e. the window width must be equal in both directions
01308         if ( ((float) xl) == x ) wmox = w;
01309         if ( ((float) yl) == y ) wmoy = w;
01310         if ( ((float) zl) == z ) wmoz = w;
01311 
01312         float* d = tmp_data->get_data();
01313         int tnx = tmp_data->get_xsize();
01314         int tny = tmp_data->get_ysize();
01315         int tnz = tmp_data->get_zsize();
01316         size_t tnxy = tnx*tny;
01317 
01318         int mode = params.set_default("mode","nearest_neighbor");
01319 
01320         for(int k = zl-wmoz; k <= zl+w; ++k ) {
01321                 for(int j = yl-wmoy; j <= yl+w; ++j) {
01322                         for( int i = xl-wmox; i <= xl+w; ++i) {
01323                                 float fac = 1.0;
01324                                 int ic = i, jc = j, kc = k;
01325 
01326                                 // Fourier space is periodic, which is enforced
01327                                 // by the next 6 if statements. These if statements
01328                                 // assume that the Fourier DC components is at
01329                                 // (0,ny/2,nz/2).
01330                                 if ( i <= 0 ) {
01331 
01332                                         if ( x != 0 && i == 0 ) fac = 1.0;
01333                                         else if ( x == 0 && i < 0) continue;
01334 //                                      if (i < 0 ) ic = -i;
01335                                         if (i < 0 ) {
01336                                                 continue;
01337                                                 ic = -i;
01338                                                 jc = tny-jc;
01339                                                 kc = tnz-kc;
01340                                         }
01341                                 }
01342                                 if ( ic >= tnx ) ic = 2*tnx-ic-1;
01343                                 if ( jc < 0 ) jc = tny+jc;
01344                                 if ( jc >= tny ) jc = jc-tny;
01345                                 if ( kc < 0 ) kc = tnz+kc;
01346                                 if ( kc >= tnz ) kc = kc-tnz;
01347 //                              if ( ic >= tnx ) continue;
01348 //                              if ( jc < 0 ) continue;
01349 //                              if ( jc >= tny ) continue;
01350 //                              if ( kc < 0 ) continue;
01351 //                              if ( kc >= tnz ) continue;
01352                                 // This shouldn't happen
01353                                 // Debug remove later
01354                                 if ( ic < 0 ) { cout << "wo 1" << endl; }
01355                                 if ( ic >= tnx  ){ cout << "wo 2" << endl; }
01356                                 if ( jc < 0 ) { cout << "wo 3" << endl; }
01357                                 if ( jc >= tny ) { cout << "wo 4" << endl; }
01358                                 if ( kc < 0 ) { cout << "wo 5" << endl; }
01359                                 if ( kc >= tnz ) { cout << "wo 6" << endl; }
01360 
01361 
01362                                 float zd = (z-(float)k);
01363                                 float yd = (y-(float)j);
01364                                 float xd = (x-(float)i);
01365                                 zd *= zd; yd *= yd; xd *= xd;
01366                                 float distsquared = xd+yd+zd;
01367                                 // We enforce a spherical kernel
01368                                 if ( mode == 1 && distsquared > wsquared ) continue;
01369 
01370 //                              float f = fac*exp(-dw*(distsquared));
01371                                 float f = fac*exp(-2.467f*(distsquared));
01372                                 // Debug - this error should never occur.
01373                                 if ( (kc*tnxy+jc*tnx+ic) >= tnxy*tnz ) throw OutofRangeException(0,tnxy*tnz,kc*tnxy+jc*tnx+ic, "in density insertion" );
01374                                 d[kc*tnxy+jc*tnx+ic] += f;
01375                         }
01376                 }
01377         }
01378 }
01379 
01380 int BaldwinWoolfordReconstructor::insert_slice(const EMData* const input_slice, const Transform & t, const float weight)
01381 {
01382         Transform * rotation;
01383         if ( input_slice->has_attr("xform.projection") ) {
01384                 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
01385         } else {
01386                 rotation = new Transform(t); // assignment operator
01387         }
01388         Transform tmp(*rotation);
01389         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly
01390 
01391         Vec2f trans = tmp.get_trans_2d();
01392         float scale = tmp.get_scale();
01393         bool mirror = tmp.get_mirror();
01394         EMData* slice = 0;
01395         if (trans[0] != 0 || trans[1] != 0 || scale != 1.0 ) {
01396                 slice = input_slice->process("xform",Dict("transform",&tmp));
01397         } else if ( mirror == true ) {
01398                 slice = input_slice->process("xform.flip",Dict("axis","x"));
01399         }
01400         if ( slice == 0 ) {
01401                 slice = input_slice->process("xform.phaseorigin.tocorner");
01402         } else {
01403                 slice->process_inplace("xform.phaseorigin.tocorner");
01404         }
01405 
01406         slice->do_fft_inplace();
01407         slice->process_inplace("xform.fourierorigin.tocenter");
01408         float *dat = slice->get_data();
01409         float dt[2];
01410 
01411         bool fftodd = image->is_fftodd();
01412         int rnx = nx-2*!fftodd;
01413 
01414         float y_scale = 1.0, x_scale = 1.0;
01415 
01416         if ( ny != rnx  )
01417         {
01418                 if ( rnx > ny ) y_scale = (float) rnx / (float) ny;
01419                 else x_scale = (float) ny / (float) rnx;
01420         }
01421 
01422         int tnx = tmp_data->get_xsize();
01423         int tny = tmp_data->get_ysize();
01424         int tnz = tmp_data->get_zsize();
01425 
01426         vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
01427 //      float weight = params.set_default("weight",1.0f);
01428 
01429         rotation->set_scale(1.0); rotation->set_mirror(false); rotation->set_trans(0,0,0);
01430         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
01431                 Transform t3d = (*rotation)*(*it);
01432 
01433                 for (int y = 0; y < tny; y++) {
01434                         for (int x = 0; x < tnx; x++) {
01435                                 float rx = (float) x;
01436                                 float ry = (float) y;
01437 
01438                                 if ( ny != rnx )
01439                                 {
01440                                         if ( rnx > ny ) ry *= y_scale;
01441                                         else rx *= x_scale;
01442                                 }
01443 
01444 //                              float xx = rx * n3d[0][0] + (ry - tny/2) * n3d[1][0];
01445 //                              float yy = rx * n3d[0][1] + (ry - tny/2) * n3d[1][1];
01446 //                              float zz = rx * n3d[0][2] + (ry - tny/2) * n3d[1][2];
01447 
01448                                 Vec3f coord(rx,(ry - tny/2),0);
01449                                 coord = coord*t3d; // transpose multiplication
01450                                 float xx = coord[0];
01451                                 float yy = coord[1];
01452                                 float zz = coord[2];
01453 
01454 
01455                                 float cc = 1;
01456                                 if (xx < 0 ){
01457                                         xx = -xx;
01458                                         yy = -yy;
01459                                         zz = -zz;
01460                                         cc = -1;
01461                                 }
01462 
01463                                 yy += tny/2;
01464                                 zz += tnz/2;
01465 
01466                                 int idx = x * 2 + y * (slice->get_xsize());
01467                                 dt[0] = dat[idx];
01468                                 dt[1] = cc * dat[idx+1];
01469 
01470                                 insert_pixel(xx,yy,zz,dt);
01471                         }
01472                 }
01473         }
01474 
01475         if(rotation) {delete rotation; rotation=0;}
01476         delete slice;
01477 
01478         return 0;
01479 }
01480 
01481 void BaldwinWoolfordReconstructor::insert_pixel(const float& x, const float& y, const float& z, const float dt[2])
01482 {
01483         int xl = Util::fast_floor(x);
01484         int yl = Util::fast_floor(y);
01485         int zl = Util::fast_floor(z);
01486 
01487         // w is the windowing width
01488         int w = params.set_default("maskwidth",2);
01489         float wsquared = (float) w*w;
01490         float dw = 1.0f/w;
01491         dw *= dw;
01492 
01493         int wmox = w-1;
01494         int wmoy = w-1;
01495         int wmoz = w-1;
01496 
01497         // If any coordinate is incedental with a vertex, then
01498         // make sure there is symmetry in density accruing.
01499         // i.e. the window width must be equal in both directions
01500         if ( ((float) xl) == x ) wmox = w;
01501         if ( ((float) yl) == y ) wmoy = w;
01502         if ( ((float) zl) == z ) wmoz = w;
01503 
01504         float* we = tmp_data->get_data();
01505         int tnx = tmp_data->get_xsize();
01506         int tny = tmp_data->get_ysize();
01507         int tnz = tmp_data->get_zsize();
01508         int tnxy = tnx*tny;
01509 
01510         int rnx = 2*tnx;
01511         int rnxy = 2*tnxy;
01512 
01513         int mode = params.set_default("mode","nearest_neighbor");
01514 
01515         float* d = image->get_data();
01516         for(int k = zl-wmoz; k <= zl+w; ++k ) {
01517                 for(int j = yl-wmoy; j <= yl+w; ++j) {
01518                         for( int i = xl-wmox; i <= xl+w; ++i) {
01519                                 float fac = 1.0;
01520                                 int ic = i, jc = j, kc = k;
01521 
01522                                 // Fourier space is periodic, which is enforced
01523                                 // by the next 6 if statements. These if statements
01524                                 // assume that the Fourier DC component is at
01525                                 // (0,ny/2,nz/2).
01526                                 float negfac=1.0;
01527                                 if ( i <= 0 ) {
01528                                         if ( x != 0 && i == 0 ) fac = 1.0;
01529                                         else if ( x == 0 && i < 0) continue;
01530                                         if (i < 0 ) {
01531                                                 continue;
01532                                                 ic = -i;
01533                                                 jc = tny-jc;
01534                                                 kc = tnz-kc;
01535                                                 negfac=-1.0;
01536                                         }
01537                                 }
01538                                 if ( ic >= tnx ) ic = 2*tnx-ic-1;
01539                                 if ( jc < 0 ) jc = tny+jc;
01540                                 if ( jc >= tny ) jc = jc-tny;
01541                                 if ( kc < 0 ) kc = tnz+kc;
01542                                 if ( kc >= tnz ) kc = kc-tnz;
01543 //                              if ( ic >= tnx ) continue;
01544 //                              if ( jc < 0 ) continue;
01545 //                              if ( jc >= tny ) continue;
01546 //                              if ( kc < 0 ) continue;
01547 //                              if ( kc >= tnz ) continue;
01548 
01549                                 float zd = (z-(float)k);
01550                                 float yd = (y-(float)j);
01551                                 float xd = (x-(float)i);
01552                                 zd *= zd; yd *= yd; xd *= xd;
01553                                 float distsquared = xd+yd+zd;
01554 //                              float f = fac*exp(-dw*(distsquared));
01555                                 float f = fac*exp(-2.467f*(distsquared));
01556                                 float weight = f/we[kc*tnxy+jc*tnx+ic];
01557                                 // debug - this error should never occur
01558                                 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" );
01559                                 size_t k = kc*rnxy+jc*rnx+2*ic;
01560 
01561                                 float factor, dist,residual;
01562                                 int sizeW,sizeWmid,idx;
01563                                 switch (mode) {
01564                                         case 0:
01565                                                 d[k] += weight*f*dt[0];
01566                                                 d[k+1] += negfac*weight*f*dt[1];
01567                                                 cout << "hello" << endl;
01568                                         break;
01569 
01570                                         case 1:
01571                                                 // We enforce a spherical kernel
01572                                                 if ( distsquared > wsquared ) continue;
01573 
01574                                                 sizeW = (int)(1+2*w/dfreq);
01575                                                 sizeWmid = sizeW/2;
01576 
01577                                                 dist = sqrtf(distsquared);
01578                                                 idx = (int)(sizeWmid + dist/dfreq);
01579                                                 if (idx >= sizeW) throw InvalidValueException(idx, "idx was greater than or equal to sizeW");
01580                                                 residual = dist/dfreq - (int)(dist/dfreq);
01581                                                 if ( fabs(residual) > 1) throw InvalidValueException(residual, "Residual was too big");
01582 
01583                                                 factor = (W[idx]*(1.0f-residual)+W[idx+1]*residual)*weight;
01584 
01585                                                 d[k] += dt[0]*factor;
01586                                                 d[k+1] += dt[1]*factor;
01587                                         break;
01588 
01589                                         default:
01590                                                 throw InvalidValueException(mode, "The mode was unsupported in BaldwinWoolfordReconstructor::insert_pixel");
01591                                         break;
01592                                 }
01593                         }
01594                 }
01595         }
01596 }
01597 
01598 // void BaldwinWoolfordReconstructor::insert_pixel(const float& x, const float& y, const float& z, const float dt[2])
01599 // {
01600 //      int xl = Util::fast_floor(x);
01601 //      int yl = Util::fast_floor(y);
01602 //      int zl = Util::fast_floor(z);
01603 //
01604 //      // w is the windowing width
01605 //      int w = params.set_default("maskwidth",2);
01606 //      float dw = 1.0/w;
01607 //      dw *= dw;
01608 // //   dw = 2;
01609 // //   cout << w << endl;
01610 //      //      int w = 3;
01611 //      // w minus one - this control the number of
01612 //      // pixels/voxels to the left of the main pixel
01613 //      // that will have density
01614 //      int wmox = w-1;
01615 //      int wmoy = w-1;
01616 //      int wmoz = w-1;
01617 //
01618 //      // If any coordinate is incedental with a vertex, then
01619 //      // make sure there is symmetry in density accruing.
01620 //      // i.e. the window width must be equal in both directions
01621 //      if ( ((float) xl) == x ) wmox = w;
01622 //      if ( ((float) yl) == y ) wmoy = w;
01623 //      if ( ((float) zl) == z ) wmoz = w;
01624 //
01625 //      float* d = tmp_data->get_data();
01626 //      int tnx = tmp_data->get_xsize();
01627 //      int tny = tmp_data->get_ysize();
01628 //      int tnz = tmp_data->get_zsize();
01629 //      int tnxy = tnx*tny;
01630 //
01631 //      float weight = 1.0;
01632 // //
01633 //      for(int k = zl-wmoz; k <= zl+w; ++k ) {
01634 //              for(int j = yl-wmoy; j <= yl+w; ++j) {
01635 //                      for( int i = xl-wmox; i <= xl+w; ++i) {
01636 //                              float fac = 1.0;
01637 //                              int ic = i, jc = j, kc = k;
01638 //
01639 //                              // Fourier space is periodic, which is enforced
01640 //                              // by the next 6 if statements. These if statements
01641 //                              // assume that the Fourier DC components is at
01642 //                              // (0,ny/2,nz/2).
01643 //                              if ( i <= 0 ) {
01644 //                                      if ( x != 0 && i == 0 ) fac = 1.0;
01645 //                                      else if ( x == 0 && i < 0) continue;
01646 // //                                   if (i < 0 ) ic = -i;
01647 //                                      if (i < 0 ) {
01648 //                                              ic = -i;
01649 //                                              jc = tny-jc;
01650 //                                              kc = tnz-kc;
01651 //                                      }
01652 //                              }
01653 //                              if ( ic >= tnx ) ic = 2*tnx-ic-1;
01654 //                              if ( jc < 0 ) jc = tny+jc;
01655 //                              if ( jc >= tny ) jc = jc-tny;
01656 //                              if ( kc < 0 ) kc = tnz+kc;
01657 //                              if ( kc >= tnz ) kc = kc-tnz;
01658 //                              // This shouldn't happen
01659 //                              // Debug remove later
01660 //                              if ( ic < 0 ) { cout << "wo 1" << endl; }
01661 //                              if ( ic >= tnx  ){ cout << "wo 2" << endl; }
01662 //                              if ( jc < 0 ) { cout << "wo 3" << endl; }
01663 //                              if ( jc >= tny ) { cout << "wo 4" << endl; }
01664 //                              if ( kc < 0 ) { cout << "wo 5" << endl; }
01665 //                              if ( kc >= tnz ) { cout << "wo 6" << endl; }
01666 //
01667 //
01668 //                              float zd = (z-(float)k);
01669 //                              float yd = (y-(float)j);
01670 //                              float xd = (x-(float)i);
01671 //                              zd *= zd; yd *= yd; xd *= xd;
01672 //                              // Debug - this error should never occur.
01673 //                              if ( (kc*tnxy+jc*tnx+ic) >= tnxy*tnz ) throw OutofRangeException(0,tnxy*tnz,kc*tnxy+jc*tnx+ic, "in weight determination insertion" );
01674 // //                           float f = fac*exp(-dw*(xd+yd+zd)*0.5);
01675 //                              float f = exp(-2.467*(xd+yd+zd));
01676 //                              weight += f*(d[kc*tnxy+jc*tnx+ic] - f);
01677 //                      }
01678 //              }
01679 //      }
01680 //      weight = 1.0/weight;
01681 //      int rnx = 2*tnx;
01682 //      int rnxy = 2*tnxy;
01683 //      d = image->get_data();
01684 //      for(int k = zl-wmoz; k <= zl+w; ++k ) {
01685 //              for(int j = yl-wmoy; j <= yl+w; ++j) {
01686 //                      for( int i = xl-wmox; i <= xl+w; ++i) {
01687 //                              float fac = 1.0;
01688 //                              int ic = i, jc = j, kc = k;
01689 //
01690 //                              // Fourier space is periodic, which is enforced
01691 //                              // by the next 6 if statements. These if statements
01692 //                              // assume that the Fourier DC components is at
01693 //                              // (0,ny/2,nz/2).
01694 //                              float negfac=1.0;
01695 //                              if ( i <= 0 ) {
01696 //                                      if ( x != 0 && i == 0 ) fac = 1.0;
01697 //                                      else if ( x == 0 && i < 0) continue;
01698 //                                      if (i < 0 ) {
01699 //                                              continue;
01700 //                                              ic = -i;
01701 //                                              jc = tny-jc;
01702 //                                              kc = tnz-kc;
01703 //                                              negfac=-1.0;
01704 //                                      }
01705 //                              }
01706 //                              if ( ic >= tnx ) ic = 2*tnx-ic-1;
01707 //                              if ( jc < 0 ) jc = tny+jc;
01708 //                              if ( jc >= tny ) jc = jc-tny;
01709 //                              if ( kc < 0 ) kc = tnz+kc;
01710 //                              if ( kc >= tnz ) kc = kc-tnz;
01711 //                              // This shouldn't happen
01712 //                              // Debug remove later
01713 //
01714 //
01715 //                              float zd = (z-(float)k);
01716 //                              float yd = (y-(float)j);
01717 //                              float xd = (x-(float)i);
01718 //                              zd *= zd; yd *= yd; xd *= xd;
01719 // //                           float f = fac*exp(-dw*(xd+yd+zd));
01720 //                              float f = exp(-4.934*(xd+yd+zd));
01721 //                              // Debug - this error should never occur.
01722 //                              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" );
01723 //
01724 //                              d[kc*rnxy+jc*rnx+2*ic] += weight*f*dt[0];
01725 //                              d[kc*rnxy+jc*rnx+2*ic+1] += negfac*weight*f*dt[1];
01726 //                      }
01727 //              }
01728 //      }
01729 // }
01730 */
01731 
01732 
01733 void BackProjectionReconstructor::setup()
01734 {
01735         int size = params["size"];
01736         image = new EMData();
01737         nx = size;
01738         ny = size;
01739         if ( (int) params["zsample"] != 0 ) nz = params["zsample"];
01740         else nz = size;
01741         image->set_size(nx, ny, nz);
01742 }
01743 
01744 EMData* BackProjectionReconstructor::preprocess_slice(const EMData* const slice, const Transform& t)
01745 {
01746 
01747         EMData* return_slice = slice->process("normalize.edgemean");
01748         return_slice->process_inplace("filter.linearfourier");
01749 
01750         Transform tmp(t);
01751         tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly
01752         Vec2f trans = tmp.get_trans_2d();
01753         float scale = tmp.get_scale();
01754         bool mirror = tmp.get_mirror();
01755         if (trans[0] != 0 || trans[1] != 0 || scale != 1.0 ) {
01756                 return_slice->transform(tmp);
01757         } else if ( mirror == true ) {
01758                 return_slice = slice->process("xform.flip",Dict("axis","x"));
01759         }
01760 
01761         return return_slice;
01762 }
01763 
01764 int BackProjectionReconstructor::insert_slice(const EMData* const input, const Transform &t, const float sliceweight)
01765 {
01766         if (!input) {
01767                 LOGERR("try to insert NULL slice");
01768                 return 1;
01769         }
01770 
01771         if (input->get_xsize() != input->get_ysize() || input->get_xsize() != nx) {
01772                 LOGERR("tried to insert image that was not correction dimensions");
01773                 return 1;
01774         }
01775 
01776         Transform * transform;
01777         if ( input->has_attr("xform.projection") ) {
01778                 transform = (Transform*) (input->get_attr("xform.projection")); // assignment operator
01779         } else {
01780                 transform = new Transform(t); // assignment operator
01781         }
01782         EMData* slice = preprocess_slice(input, t);
01783 
01784         float weight = params["weight"];
01785         slice->mult(weight);
01786 
01787         EMData *tmp = new EMData();
01788         tmp->set_size(nx, ny, nz);
01789 
01790         float *slice_data = slice->get_data();
01791         float *tmp_data = tmp->get_data();
01792 
01793         size_t nxy = nx * ny;
01794         size_t nxy_size = nxy * sizeof(float);;
01795         for (int i = 0; i < nz; ++i) {
01796                 memcpy(&tmp_data[nxy * i], slice_data, nxy_size);
01797         }
01798 
01799         transform->set_scale(1.0);
01800         transform->set_mirror(false);
01801         transform->set_trans(0,0,0);
01802         transform->invert();
01803 
01804         tmp->transform(*transform);
01805         image->add(*tmp);
01806 
01807         if(transform) {delete transform; transform=0;}
01808         delete tmp;
01809         delete slice;
01810 
01811         return 0;
01812 }
01813 
01814 EMData *BackProjectionReconstructor::finish(bool doift)
01815 {
01816 
01817         Symmetry3D* sym = Factory<Symmetry3D>::get((string)params["sym"]);
01818         vector<Transform> syms = sym->get_syms();
01819 
01820         for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
01821 
01822                 EMData tmpcopy(*image);
01823                 tmpcopy.transform(*it);
01824                 image->add(tmpcopy);
01825         }
01826 
01827         image->mult(1.0f/(float)sym->get_nsym());
01828         delete sym;
01829         return image;
01830 }
01831 
01832 EMData* EMAN::padfft_slice( const EMData* const slice, const Transform& t, int npad )
01833 {
01834         int nx = slice->get_xsize();
01835         int ny = slice->get_ysize();
01836         int ndim = (ny==1) ? 1 : 2;
01837 
01838         if( ndim==2 && nx!=ny )
01839         {
01840                 // FIXME: What kind of exception should we throw here?
01841                 throw std::runtime_error("Tried to padfft a 2D slice which is not square.");
01842         }
01843 
01844         // process 2D slice or 1D line -- subtract the average outside of the circle, zero-pad, fft extend, and fft
01845         EMData* temp = slice->average_circ_sub();
01846 
01847         Assert( temp != NULL );
01848         EMData* zeropadded = temp->norm_pad( false, npad );
01849         Assert( zeropadded != NULL );
01850         checked_delete( temp );
01851 
01852         zeropadded->do_fft_inplace();
01853         EMData* padfftslice = zeropadded;
01854 
01855         // shift the projection
01856         Vec2f trans = t.get_trans_2d();
01857         float sx = -trans[0];
01858         float sy = -trans[1];
01859         if(sx != 0.0f || sy != 0.0)
01860                 padfftslice->process_inplace("filter.shift", Dict("x_shift", sx, "y_shift", sy, "z_shift", 0.0f));
01861 
01862         int remove = slice->get_attr_default("remove", 0);
01863         padfftslice->set_attr( "remove", remove );
01864 
01865 
01866 
01867         padfftslice->center_origin_fft();
01868         return padfftslice;
01869 }
01870 
01871 nn4Reconstructor::nn4Reconstructor()
01872 {
01873         m_volume = NULL;
01874         m_wptr   = NULL;
01875         m_result = NULL;
01876 }
01877 
01878 nn4Reconstructor::nn4Reconstructor( const string& symmetry, int size, int npad )
01879 {
01880         m_volume = NULL;
01881         m_wptr   = NULL;
01882         m_result = NULL;
01883         setup( symmetry, size, npad );
01884         load_default_settings();
01885         print_params();
01886 }
01887 
01888 nn4Reconstructor::~nn4Reconstructor()
01889 {
01890         if( m_delete_volume ) checked_delete(m_volume);
01891 
01892         if( m_delete_weight ) checked_delete( m_wptr );
01893 
01894         checked_delete( m_result );
01895 }
01896 
01897 enum weighting_method { NONE, ESTIMATE, VORONOI };
01898 
01899 float max2d( int kc, const vector<float>& pow_a )
01900 {
01901         float max = 0.0;
01902         for( int i=-kc; i <= kc; ++i ) {
01903                 for( int j=-kc; j <= kc; ++j ) {
01904                         if( i==0 && j==0 ) continue;
01905                         {
01906                                 int c = 2*kc+1 - std::abs(i) - std::abs(j);
01907                                 max = max + pow_a[c];
01908                         }
01909                 }
01910         }
01911         return max;
01912 }
01913 
01914 float max3d( int kc, const vector<float>& pow_a )
01915 {
01916         float max = 0.0;
01917         for( int i=-kc; i <= kc; ++i ) {
01918                 for( int j=-kc; j <= kc; ++j ) {
01919                         for( int k=-kc; k <= kc; ++k ) {
01920                                 if( i==0 && j==0 && k==0 ) continue;
01921                                 // if( i!=0 )
01922                                 {
01923                                         int c = 3*kc+1 - std::abs(i) - std::abs(j) - std::abs(k);
01924                                         max = max + pow_a[c];
01925                                         // max = max + c * c;
01926                                         // max = max + c;
01927                                 }
01928                         }
01929                 }
01930         }
01931         return max;
01932 }
01933 
01934 
01935 void nn4Reconstructor::setup()
01936 {
01937         int size = params["size"];
01938         int npad = params["npad"];
01939 
01940 
01941         string symmetry;
01942         if( params.has_key("symmetry") )  symmetry = params["symmetry"].to_str();
01943         else                               symmetry = "c1";
01944 
01945         if( params.has_key("ndim") )  m_ndim = params["ndim"];
01946         else                          m_ndim = 3;
01947 
01948         if( params.has_key( "snr" ) )  m_osnr = 1.0f/float( params["snr"] );
01949         else                           m_osnr = 0.0;
01950 
01951         setup( symmetry, size, npad );
01952 }
01953 
01954 void nn4Reconstructor::setup( const string& symmetry, int size, int npad )
01955 {
01956         m_weighting = ESTIMATE;
01957         m_wghta = 0.2f;
01958 
01959         m_symmetry = symmetry;
01960         m_npad = npad;
01961         m_nsym = Transform::get_nsym(m_symmetry);
01962 
01963         m_vnx = size;
01964         m_vny = size;
01965         m_vnz = (m_ndim==3) ? size : 1;
01966 
01967         m_vnxp = size*npad;
01968         m_vnyp = size*npad;
01969         m_vnzp = (m_ndim==3) ? size*npad : 1;
01970 
01971         m_vnxc = m_vnxp/2;
01972         m_vnyc = m_vnyp/2;
01973         m_vnzc = (m_ndim==3) ? m_vnzp/2 : 1;
01974 
01975         buildFFTVolume();
01976         buildNormVolume();
01977 
01978 }
01979 
01980 
01981 void nn4Reconstructor::buildFFTVolume() {
01982         int offset = 2 - m_vnxp%2;
01983 
01984         if( params.has_key("fftvol") ) {
01985                 m_volume = params["fftvol"];
01986                 m_delete_volume = false;
01987         } else {
01988                 m_volume = new EMData();
01989                 m_delete_volume = true;
01990         }
01991 
01992         if( m_volume->get_xsize() != m_vnxp+offset && m_volume->get_ysize() != m_vnyp && m_volume->get_zsize() != m_vnzp ) {
01993                 m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
01994                 m_volume->to_zero();
01995         }
01996         // ----------------------------------------------------------------
01997         // Added by Zhengfan Yang on 03/15/07
01998         // Original author: please check whether my revision is correct and
01999         // other Reconstructor need similiar revision.
02000         if ( m_vnxp % 2 == 0 )  m_volume->set_fftodd(0);
02001         else                    m_volume->set_fftodd(1);
02002         // ----------------------------------------------------------------
02003 
02004         m_volume->set_nxc(m_vnxp/2);
02005         m_volume->set_complex(true);
02006         m_volume->set_ri(true);
02007         m_volume->set_fftpad(true);
02008         m_volume->set_attr("npad", m_npad);
02009         m_volume->set_array_offsets(0,1,1);
02010 }
02011 
02012 void nn4Reconstructor::buildNormVolume() {
02013 
02014         if( params.has_key("weight") ) {
02015                 m_wptr = params["weight"];
02016                 m_delete_weight = false;
02017         } else {
02018                 m_wptr = new EMData();
02019                 m_delete_weight = true;
02020         }
02021 
02022         if( m_wptr->get_xsize() != m_vnxc+1 &&
02023                 m_wptr->get_ysize() != m_vnyp &&
02024                 m_wptr->get_zsize() != m_vnzp ) {
02025                 m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02026                 m_wptr->to_zero();
02027         }
02028 
02029         m_wptr->set_array_offsets(0,1,1);
02030 }
02031 
02032 void printImage( const EMData* line )
02033 {
02034         Assert( line->get_zsize()==1 );
02035 
02036 
02037         int nx = line->get_xsize();
02038         int ny = line->get_ysize();
02039         for( int j=0; j < ny; ++j ) {
02040                 for( int i=0; i < nx; ++i )  printf( "%10.3f ", line->get_value_at(i,j) );
02041                 printf( "\n" );
02042         }
02043 }
02044 
02045 
02046 
02047 int nn4Reconstructor::insert_slice(const EMData* const slice, const Transform& t, const float weight) {
02048         // sanity checks
02049         if (!slice) {
02050                 LOGERR("try to insert NULL slice");
02051                 return 1;
02052         }
02053 
02054         int padffted= slice->get_attr_default( "padffted", 0 );
02055         if( m_ndim==3 ) {
02056                 if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  ) {
02057                         // FIXME: Why doesn't this throw an exception?
02058                         LOGERR("Tried to insert a slice that is the wrong size.");
02059                         return 1;
02060                 }
02061         } else {
02062                 Assert( m_ndim==2 );
02063                 if( slice->get_ysize() !=1 ) {
02064                         LOGERR( "for 2D reconstruction, a line is excepted" );
02065                         return 1;
02066                 }
02067         }
02068 
02069         EMData* padfft = NULL;
02070 
02071         if( padffted != 0 ) padfft = new EMData(*slice);
02072         else                padfft = padfft_slice( slice, t,  m_npad );
02073 
02074         int mult= slice->get_attr_default( "mult", 1 );
02075         Assert( mult > 0 );
02076 
02077         if( m_ndim==3 ) {
02078                 insert_padfft_slice( padfft, t, mult );
02079         } else {
02080                 float alpha = padfft->get_attr( "alpha" );
02081                 alpha = alpha/180.0f*M_PI;
02082                 for(int i=0; i < m_vnxc+1; ++i ) {
02083                         float xnew = i*cos(alpha);
02084                         float ynew = -i*sin(alpha);
02085                         float btqr = padfft->get_value_at( 2*i, 0, 0 );
02086                         float btqi = padfft->get_value_at( 2*i+1, 0, 0 );
02087                         if( xnew < 0.0 ) {
02088                                 xnew *= -1;
02089                                 ynew *= -1;
02090                                 btqi *= -1;
02091                         }
02092 
02093                         int ixn = int(xnew+0.5+m_vnxp) - m_vnxp;
02094                         int iyn = int(ynew+0.5+m_vnyp) - m_vnyp;
02095 
02096                         if(iyn < 0 ) iyn += m_vnyp;
02097 
02098                         (*m_volume)( 2*ixn, iyn+1, 1 ) += btqr *float(mult);
02099                         (*m_volume)( 2*ixn+1, iyn+1, 1 ) += btqi * float(mult);
02100                         (*m_wptr)(ixn,iyn+1, 1) += float(mult);
02101                 }
02102 
02103         }
02104         checked_delete( padfft );
02105         return 0;
02106 }
02107 
02108 int nn4Reconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
02109 {
02110         Assert( padfft != NULL );
02111         // insert slice for all symmetry related positions
02112 
02113         for (int isym=0; isym < m_nsym; isym++) {
02114                 Transform tsym = t.get_sym(m_symmetry, isym);
02115         
02116                 m_volume->nn( m_wptr, padfft, tsym, mult);
02117         }
02118         return 0;
02119 }
02120 
02121 
02122 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02123 
02124 void circumf( EMData* win , int npad)
02125 {
02126         float *tw = win->get_data();
02127         //  correct for the fall-off
02128         //  mask and subtract circumference average
02129         int ix = win->get_xsize();
02130         int iy = win->get_ysize();
02131         int iz = win->get_zsize();
02132         int L2 = (ix/2)*(ix/2);
02133         int L2P = (ix/2-1)*(ix/2-1);
02134 
02135         int IP = ix/2+1;
02136         int JP = iy/2+1;
02137         int KP = iz/2+1;
02138 
02139         //  sinc functions tabulated for fall-off
02140         float* sincx = new float[IP+1];
02141         float* sincy = new float[JP+1];
02142         float* sincz = new float[KP+1];
02143 
02144         sincx[0] = 1.0f;
02145         sincy[0] = 1.0f;
02146         sincz[0] = 1.0f;
02147 
02148         float cdf = M_PI/float(npad*2*ix);
02149         for (int i = 1; i <= IP; ++i)  sincx[i] = sin(i*cdf)/(i*cdf);
02150         cdf = M_PI/float(npad*2*iy);
02151         for (int i = 1; i <= JP; ++i)  sincy[i] = sin(i*cdf)/(i*cdf);
02152         cdf = M_PI/float(npad*2*iz);
02153         for (int i = 1; i <= KP; ++i)  sincz[i] = sin(i*cdf)/(i*cdf);
02154         for (int k = 1; k <= iz; ++k) {
02155                 int kkp = abs(k-KP);
02156                 for (int j = 1; j <= iy; ++j) {
02157                         cdf = sincy[abs(j- JP)]*sincz[kkp];
02158                         for (int i = 1; i <= ix; ++i)  tw(i,j,k) /= (sincx[abs(i-IP)]*cdf);
02159                 }
02160         }
02161 
02162         delete[] sincx;
02163         delete[] sincy;
02164         delete[] sincz;
02165 
02166         float  TNR = 0.0f;
02167         size_t m = 0;
02168         for (int k = 1; k <= iz; ++k) {
02169                 for (int j = 1; j <= iy; ++j) {
02170                         for (int i = 1; i <= ix; ++i) {
02171                                 size_t LR = (k-KP)*(k-KP)+(j-JP)*(j-JP)+(i-IP)*(i-IP);
02172                                 if (LR >= (size_t)L2P && LR<=(size_t)L2) {
02173                                         TNR += tw(i,j,k);
02174                                         ++m;
02175                                 }
02176                         }
02177                 }
02178         }
02179 
02180         TNR /=float(m);
02181         
02182         
02183         for (int k = 1; k <= iz; ++k) {
02184                 for (int j = 1; j <= iy; ++j) {
02185                         for (int i = 1; i <= ix; ++i) {
02186                                 size_t LR = (k-KP)*(k-KP)+(j-JP)*(j-JP)+(i-IP)*(i-IP);
02187                                 if (LR<=(size_t)L2) tw(i,j,k) -= TNR;
02188                                 else                tw(i,j,k) = 0.0f;
02189 
02190                         }
02191                 }
02192         }
02193 
02194 }
02195 
02196 
02197 EMData* nn4Reconstructor::finish(bool doift)
02198 {
02199         if( m_ndim==3 ) {
02200                 m_volume->symplane0(m_wptr);
02201         } else {
02202                 for( int i=1; i <= m_vnyp; ++i ) {
02203 
02204                         if( (*m_wptr)(0, i, 1)==0.0 ) {
02205                                 int j = m_vnyp + 1 - i;
02206                                 (*m_wptr)(0, i, 1) = (*m_wptr)(0, j, 1);
02207                                 (*m_volume)(0, i, 1) = (*m_volume)(0, j, 1);
02208                                 (*m_volume)(1, i, 1) = (*m_volume)(1, j, 1);
02209                         }
02210                 }
02211         }
02212 
02213 
02214         int box = 7;
02215         int kc = (box-1)/2;
02216         vector< float > pow_a( m_ndim*kc+1, 1.0 );
02217         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
02218         pow_a.back()=0.0;
02219 
02220         float alpha = 0.0;
02221         if( m_ndim==3) {
02222                 int vol = box*box*box;
02223                 float max = max3d( kc, pow_a );
02224                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
02225         } else {
02226                 int ara = box*box;
02227                 float max = max2d( kc, pow_a );
02228                 alpha = ( 1.0f - 1.0f/(float)ara ) / max;
02229         }
02230 
02231         int ix,iy,iz;
02232         for (iz = 1; iz <= m_vnzp; iz++) {
02233                 for (iy = 1; iy <= m_vnyp; iy++) {
02234                         for (ix = 0; ix <= m_vnxc; ix++) {
02235                                 if ( (*m_wptr)(ix,iy,iz) > 0) {//(*v) should be treated as complex!!
02236                                         float tmp;
02237                                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+m_osnr);
02238 
02239                                         if( m_weighting == ESTIMATE ) {
02240                                                 int cx = ix;
02241                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
02242                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
02243                                                 float sum = 0.0;
02244                                                 for( int ii = -kc; ii <= kc; ++ii ) {
02245                                                         int nbrcx = cx + ii;
02246                                                         if( nbrcx >= m_vnxc ) continue;
02247                                                         for( int jj= -kc; jj <= kc; ++jj ) {
02248                                                                 int nbrcy = cy + jj;
02249                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
02250 
02251                                                                 int kcz = (m_ndim==3) ? kc : 0;
02252                                                                 for( int kk = -kcz; kk <= kcz; ++kk ) {
02253                                                                         int nbrcz = cz + kk;
02254                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
02255                                                                         if( nbrcx < 0 ) {
02256                                                                                 nbrcx = -nbrcx;
02257                                                                                 nbrcy = -nbrcy;
02258                                                                                 nbrcz = -nbrcz;
02259                                                                         }
02260                                                                         int nbrix = nbrcx;
02261                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
02262                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
02263                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
02264                                                                                 int c = m_ndim*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
02265                                                                                 sum = sum + pow_a[c];
02266                                                                         }
02267                                                                 }
02268                                                         }
02269                                                 }
02270                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
02271                                                 tmp = tmp * wght;
02272                                         }
02273                                         (*m_volume)(2*ix,iy,iz)   *= tmp;
02274                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
02275                                 }
02276                         }
02277                 }
02278         }
02279 
02280         //if(m_ndim==2) printImage( m_volume );
02281 
02282         // back fft
02283         m_volume->do_ift_inplace();
02284 
02285         // EMData* win = m_volume->window_center(m_vnx);
02286         int npad = m_volume->get_attr("npad");
02287         m_volume->depad();
02288         circumf( m_volume, npad );
02289         m_volume->set_array_offsets( 0, 0, 0 );
02290 
02291         m_result = m_volume->copy();
02292         return m_result;
02293 }
02294 #undef  tw
02295 
02296 
02297 nn4_rectReconstructor::nn4_rectReconstructor()
02298 {
02299         m_volume = NULL;
02300         m_wptr   = NULL;
02301         m_result = NULL;
02302 }
02303 
02304 nn4_rectReconstructor::nn4_rectReconstructor( const string& symmetry, int size, int npad )
02305 {
02306         m_volume = NULL;
02307         m_wptr   = NULL;
02308         m_result = NULL;
02309         setup( symmetry, size, npad );
02310         load_default_settings();
02311         print_params();
02312 }
02313 
02314 nn4_rectReconstructor::~nn4_rectReconstructor()
02315 {
02316         if( m_delete_volume ) checked_delete(m_volume);
02317 
02318         if( m_delete_weight ) checked_delete( m_wptr );
02319 
02320         checked_delete( m_result );
02321 }
02322 
02323 
02324 void nn4_rectReconstructor::setup()
02325 {
02326         m_sizeofprojection = params["sizeprojection"];
02327         int npad = params["npad"];
02328         m_count=0;
02329 
02330         string symmetry;
02331         if( params.has_key("symmetry") )  symmetry = params["symmetry"].to_str();
02332         else                               symmetry = "c1";
02333 
02334         if( params.has_key("ndim") )  m_ndim = params["ndim"];             
02335         else                            m_ndim = 3;
02336     
02337         if( params.has_key( "snr" ) )  m_osnr = 1.0f/float( params["snr"] );
02338         else                           m_osnr = 0.0;
02339 
02340         setup( symmetry, m_sizeofprojection, npad );
02341 }
02342 
02343 void nn4_rectReconstructor::setup( const string& symmetry, int sizeprojection, int npad )
02344 {
02345         m_weighting = ESTIMATE;
02346         m_wghta = 0.2f;
02347         m_symmetry = symmetry;
02348         m_npad = npad;
02349         m_nsym = Transform::get_nsym(m_symmetry);
02350 
02351         if( params.has_key("sizex") )  m_vnx = params["sizex"];
02352         else if(params.has_key("xratio")) 
02353                 {
02354                 float temp=params["xratio"];
02355                 m_vnx=int(float(sizeprojection)*temp);
02356                 }
02357         else                           m_vnx=sizeprojection;
02358 
02359         if( params.has_key("sizey") )  m_vny = params["sizey"];
02360         else if (params.has_key("yratio"))  
02361                {
02362                 float temp=params["yratio"];
02363                  m_vny=int(float(sizeprojection)*temp);
02364                 }
02365         else m_vny=sizeprojection;
02366 
02367         if( params.has_key("sizez") ) 
02368                 m_vnz = params["sizez"];
02369         else                          
02370                 m_vnz = (m_ndim==3) ? sizeprojection : 1;
02371         
02372         m_xratio=float(m_vnx)/float(sizeprojection);    
02373         m_yratio=float(m_vny)/float(sizeprojection);
02374 
02375         //std::cout<<"dim==="<<m_ndim<<"xratio=="<<m_xratio<<"yratio=="<<m_yratio<<std::endl;
02376         //std::cout<<"sx=="<<m_vnx<<"sy=="<<m_vny<<"sz=="<<m_vnz<<std::endl;
02377         
02378 
02379         m_vnxp = m_vnx*npad;
02380         m_vnyp = m_vny*npad;
02381         m_vnzp = (m_ndim==3) ? m_vnz*npad : 1;
02382 
02383         m_vnxc = m_vnxp/2;
02384         m_vnyc = m_vnyp/2;
02385         m_vnzc = (m_ndim==3) ? m_vnzp/2 : 1;
02386 
02387         buildFFTVolume();
02388         buildNormVolume();
02389 
02390 
02391 }
02392 
02393 
02394 void nn4_rectReconstructor::buildFFTVolume() {
02395         int offset = 2 - m_vnxp%2;
02396 
02397         if( params.has_key("fftvol") ) {
02398                 m_volume = params["fftvol"];
02399                 m_delete_volume = false;
02400         } else {
02401                 m_volume = new EMData();
02402                 m_delete_volume = true;
02403         }
02404 
02405         if( m_volume->get_xsize() != m_vnxp+offset && m_volume->get_ysize() != m_vnyp && m_volume->get_zsize() != m_vnzp ) {
02406                 m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
02407                 m_volume->to_zero();
02408         }
02409         // ----------------------------------------------------------------
02410         // Added by Zhengfan Yang on 03/15/07
02411         // Original author: please check whether my revision is correct and
02412         // other Reconstructor need similiar revision.
02413         if ( m_vnxp % 2 == 0 )  m_volume->set_fftodd(0);
02414         else                    m_volume->set_fftodd(1);
02415         // ----------------------------------------------------------------
02416 
02417         m_volume->set_nxc(m_vnxp/2);
02418         m_volume->set_complex(true);
02419         m_volume->set_ri(true);
02420         m_volume->set_fftpad(true);
02421         m_volume->set_attr("npad", m_npad);
02422         m_volume->set_array_offsets(0,1,1);
02423 }
02424 
02425 void nn4_rectReconstructor::buildNormVolume() {
02426 
02427         if( params.has_key("weight") ) {
02428                 m_wptr = params["weight"];
02429                 m_delete_weight = false;
02430         } else {
02431                 m_wptr = new EMData();
02432                 m_delete_weight = true;
02433         }
02434 
02435         if( m_wptr->get_xsize() != m_vnxc+1 &&
02436                 m_wptr->get_ysize() != m_vnyp &&
02437                 m_wptr->get_zsize() != m_vnzp ) {
02438                 m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02439                 m_wptr->to_zero();
02440         }
02441 
02442         m_wptr->set_array_offsets(0,1,1);
02443 }
02444 
02445 
02446 
02447 int nn4_rectReconstructor::insert_slice(const EMData* const slice, const Transform& t, const float weight) {
02448         // sanity checks
02449 
02450 
02451         //m_count=m_count+1;
02452         if (!slice) {
02453                 LOGERR("try to insert NULL slice");
02454                 return 1;
02455         }
02456 
02457         int padffted= slice->get_attr_default( "padffted", 0 );
02458         if( m_ndim==3 ) {
02459                 if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_sizeofprojection)  ) {
02460                         
02461                         // FIXME: Why doesn't this throw an exception?
02462                         LOGERR("Tried to insert a slice that is the wrong size.");
02463                         return 1;
02464                 }
02465         } 
02466        if (m_ndim==2) {
02467                 Assert( m_ndim==2 );
02468                 if( slice->get_ysize() !=1 ) {
02469                         LOGERR( "for 2D reconstruction, a line is excepted" );
02470                         return 1;
02471                 }
02472         }
02473 
02474         EMData* padfft = NULL;
02475 
02476         if( padffted != 0 ) padfft = new EMData(*slice);
02477         else                padfft = padfft_slice( slice, t,  m_npad );
02478 
02479         int mult= slice->get_attr_default( "mult", 1 );
02480         Assert( mult > 0 );
02481 
02482         if( m_ndim==3 ) {
02483                 insert_padfft_slice( padfft, t, mult );         
02484                 
02485         } else {
02486                 float ellipse_length,ellipse_step,cos_alpha,sin_alpha;
02487                 int ellipse_length_int;
02488                 float alpha = padfft->get_attr( "alpha" );
02489                 alpha = alpha/180.0f*M_PI;
02490                 int loop_range;
02491                 float temp1,temp2;
02492                 temp1=m_xratio*cos(alpha)*float(m_sizeofprojection*m_npad)/2;
02493                 temp2=m_yratio*sin(alpha)*float(m_sizeofprojection*m_npad)/2;
02494                 ellipse_length=sqrt(temp1*temp1+temp2*temp2);
02495                 ellipse_length_int=int(ellipse_length);
02496                 ellipse_step=0.5*(m_sizeofprojection*m_npad)/float(ellipse_length_int);
02497                 loop_range=ellipse_length_int;
02498                 cos_alpha=temp1/ellipse_length;
02499                 sin_alpha=temp2/ellipse_length;
02500                 if(m_count%100==0)
02501                 {
02502                         std::cout<<"#############################################################"<<std::endl;
02503                         std::cout<<"line insert start=="<<m_count<<std::endl;
02504                         std::cout<<"ellipse lenth=="<<ellipse_length_int<<"ellips step=="<<ellipse_step<<std::endl;
02505                         std::cout<<"loop_range"<<loop_range<<std::endl;
02506                         std::cout<<"x and y ratio=="<<m_xratio<<"  "<<m_yratio<<std::endl;
02507                         std::cout<<"cos sin of alpha=="<<cos(alpha)<<"   "<<sin(alpha)<<std::endl;
02508                         std::cout<<"cos sin of alpha_new==="<<cos_alpha<<sin_alpha<<std::endl;
02509                         std::cout<<"alpah dig==="<<cos_alpha<<sin_alpha<<std::endl;
02510                         std::cout<<"prjection maximum==="<<loop_range*ellipse_step<<"ideal maximum"<<m_sizeofprojection*m_npad/2<<std::endl;
02511                         std::cout<<"x_size=="<<m_volume->get_xsize()<<"y_size=="<<m_volume->get_ysize()<<std::endl;
02512                         std::cout<<"#############################################################"<<std::endl;
02513 
02514 
02515                         
02516 
02517                 }
02518                 for(int i=0; i <=loop_range; ++i ) {
02519                         float xnew = i*cos_alpha;
02520                         float ynew = -i*sin_alpha;
02521                         if(m_count%100==0&&i==loop_range)
02522                                 std::cout<<"x_new=="<<xnew<<"Y_new=="<<ynew<<std::endl;
02523                         float btqr=0,btqi=0;
02524                         float xprj=i*ellipse_step;
02525                         float t=xprj-int(xprj);
02526                         btqr = (1-t)*padfft->get_value_at( 2*int(xprj), 0, 0 )+t*padfft->get_value_at( 2*(1+int(xprj)), 0, 0 );
02527                         btqi = (1-t)*padfft->get_value_at( 2*int(xprj)+1, 0, 0 )+t*padfft->get_value_at( 2*(1+int(xprj))+1, 0, 0 );
02528                         if( xnew < 0.0 ) {
02529                                 xnew *= -1;
02530                                 ynew *= -1;
02531                                 btqi *= -1;
02532                         }
02533 
02534                         int ixn = int(xnew+0.5+m_vnxp) - m_vnxp;
02535                         int iyn = int(ynew+0.5+m_vnyp) - m_vnyp;
02536 
02537                         if(iyn < 0 ) iyn += m_vnyp;
02538                         if(m_count%100==0&&i==loop_range)
02539                                 std::cout<<"xnn=="<<ixn<<"ynn=="<<iyn<<std::endl;
02540                         (*m_volume)( 2*ixn, iyn+1, 1 ) += btqr *float(mult);
02541                         (*m_volume)( 2*ixn+1, iyn+1, 1 ) += btqi * float(mult);
02542                         (*m_wptr)(ixn,iyn+1, 1) += float(mult);
02543                 }
02544 
02545 
02546         }
02547         checked_delete( padfft );
02548         return 0;
02549 }
02550 
02551 
02552 
02553 
02554 int nn4_rectReconstructor::insert_padfft_slice( EMData* padded, const Transform& t, int mult )
02555 {
02556         Assert( padfft != NULL );
02557         
02558 
02559         for( int isym=0; isym < m_nsym; isym++) {
02560                 Transform tsym = t.get_sym( m_symmetry, isym );
02561                  m_volume->insert_rect_slice(m_wptr, padded, t, m_sizeofprojection, m_xratio, m_yratio, m_npad, mult);
02562                 }
02563 
02564         return 0;
02565 
02566 }
02567 
02568 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02569 void circumf_rect( EMData* win , int npad)
02570 {
02571         float *tw = win->get_data();
02572         //  correct for the fall-off
02573         //  mask and subtract circumference average
02574         int ix = win->get_xsize();
02575         int iy = win->get_ysize();
02576         int iz = win->get_zsize();
02577 
02578         int IP = ix/2+1;
02579         int JP = iy/2+1;
02580         int KP = iz/2+1;
02581         
02582         //  sinc functions tabulated for fall-off
02583         float* sincx = new float[IP+1];
02584         float* sincy = new float[JP+1];
02585         float* sincz = new float[KP+1];
02586 
02587         sincx[0] = 1.0f;
02588         sincy[0] = 1.0f;
02589         sincz[0] = 1.0f;
02590 
02591         float cdf = M_PI/float(npad*2*ix);
02592         for (int i = 1; i <= IP; ++i)  sincx[i] = sin(i*cdf)/(i*cdf);
02593         cdf = M_PI/float(npad*2*iy);
02594         for (int i = 1; i <= JP; ++i)  sincy[i] = sin(i*cdf)/(i*cdf);
02595         cdf = M_PI/float(npad*2*iz);
02596         for (int i = 1; i <= KP; ++i)  sincz[i] = sin(i*cdf)/(i*cdf);
02597         for (int k = 1; k <= iz; ++k) {
02598                 int kkp = abs(k-KP);
02599                 for (int j = 1; j <= iy; ++j) {
02600                         cdf = sincy[abs(j- JP)]*sincz[kkp];
02601                         for (int i = 1; i <= ix; ++i)  tw(i,j,k) /= (sincx[abs(i-IP)]*cdf);
02602                 }
02603         }
02604 
02605         delete[] sincx;
02606         delete[] sincy;
02607         delete[] sincz;
02608         
02609         
02610         
02611         float dxx = 1.0/float(0.25*ix*ix);
02612         float dyy = 1.0/float(0.25*iy*iy);
02613         
02614         
02615         
02616         float LR2=(float(ix)/2-1)*(float(ix)/2-1)*dxx;
02617 
02618         float  TNR = 0.0f;
02619         size_t m = 0;
02620         for (int k = 1; k <= iz; ++k) {
02621                 for (int j = 1; j <= iy; ++j) {
02622                         for (int i = 1; i <= ix; ++i) {
02623                                 float LR = (j-JP)*(j-JP)*dyy+(i-IP)*(i-IP)*dxx;
02624                                 if (LR<=1.0f && LR >= LR2) {
02625                                         TNR += tw(i,j,k);
02626                                         ++m;
02627                                 }
02628                         }
02629                 }
02630         }
02631 
02632         TNR /=float(m);
02633         
02634 
02635         for (int k = 1; k <= iz; ++k) {
02636                 for (int j = 1; j <= iy; ++j) {
02637                         for (int i = 1; i <= ix; ++i) {
02638                                 float LR = (j-JP)*(j-JP)*dyy+(i-IP)*(i-IP)*dxx;
02639                                 if (LR<=1.0f)  tw(i,j,k)=tw(i,j,k)-TNR;
02640                                 else            tw(i,j,k) = 0.0f;       
02641                         }
02642                 }
02643         }
02644 
02645 }
02646 #undef tw 
02647 
02648 
02649 
02650 EMData* nn4_rectReconstructor::finish(bool doift)
02651 {
02652         
02653         if( m_ndim==3 ) {
02654                 m_volume->symplane0_rect(m_wptr);
02655         } else {
02656                 for( int i=1; i <= m_vnyp; ++i ) {
02657 
02658                         if( (*m_wptr)(0, i, 1)==0.0 ) {
02659                                 int j = m_vnyp + 1 - i;
02660                                 (*m_wptr)(0, i, 1) = (*m_wptr)(0, j, 1);
02661                                 (*m_volume)(0, i, 1) = (*m_volume)(0, j, 1);
02662                                 (*m_volume)(1, i, 1) = (*m_volume)(1, j, 1);
02663                         }
02664                 }
02665         }
02666 
02667 
02668         int box = 7;
02669         int kc = (box-1)/2;
02670         vector< float > pow_a( m_ndim*kc+1, 1.0 );
02671         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
02672         pow_a.back()=0.0;
02673 
02674         float alpha = 0.0;
02675         if( m_ndim==3) {
02676                 int vol = box*box*box;
02677                 float max = max3d( kc, pow_a );
02678                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
02679         } else {
02680                 int ara = box*box;
02681                 float max = max2d( kc, pow_a );
02682                 alpha = ( 1.0f - 1.0f/(float)ara ) / max;
02683         }
02684 
02685         int ix,iy,iz;
02686         for (iz = 1; iz <= m_vnzp; iz++) {
02687                 for (iy = 1; iy <= m_vnyp; iy++) {
02688                         for (ix = 0; ix <= m_vnxc; ix++) {
02689                                 if ( (*m_wptr)(ix,iy,iz) > 0) {//(*v) should be treated as complex!!
02690                                         float tmp;
02691                                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+m_osnr);
02692                                         
02693                                         if( m_weighting == ESTIMATE ) {
02694                                                 int cx = ix;
02695                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
02696                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
02697                                                 float sum = 0.0;
02698                                                 for( int ii = -kc; ii <= kc; ++ii ) {
02699                                                         int nbrcx = cx + ii;
02700                                                         if( nbrcx >= m_vnxc ) continue;
02701                                                         for( int jj= -kc; jj <= kc; ++jj ) {
02702                                                                 int nbrcy = cy + jj;
02703                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
02704 
02705                                                                 int kcz = (m_ndim==3) ? kc : 0;
02706                                                                 for( int kk = -kcz; kk <= kcz; ++kk ) {
02707                                                                         int nbrcz = cz + kk;
02708                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
02709                                                                         if( nbrcx < 0 ) {
02710                                                                                 nbrcx = -nbrcx;
02711                                                                                 nbrcy = -nbrcy;
02712                                                                                 nbrcz = -nbrcz;
02713                                                                         }
02714                                                                         int nbrix = nbrcx;
02715                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
02716                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
02717                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
02718                                                                                 int c = m_ndim*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
02719                                                                                 sum = sum + pow_a[c];
02720                                                                         }
02721                                                                 }
02722                                                         }
02723                                                 }
02724                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
02725                                                 tmp = tmp * wght;
02726                                         }
02727                                         (*m_volume)(2*ix,iy,iz)   *= tmp;
02728                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
02729                                 }
02730                         }
02731                 }
02732         }
02733 
02734         //if(m_ndim==2) printImage( m_volume );
02735 
02736         // back fft
02737         m_volume->do_ift_inplace();
02738 
02739         
02740         int npad = m_volume->get_attr("npad");
02741         m_volume->depad();
02742         circumf_rect( m_volume, npad );
02743         //circumf_rect_new( m_volume, npad,m_xratio,m_yratio);
02744         m_volume->set_array_offsets( 0, 0, 0 );
02745 
02746         m_result = m_volume->copy();
02747         return m_result;
02748 }
02749 
02750 
02751 // Added By Zhengfan Yang on 03/16/07
02752 // Beginning of the addition
02753 // --------------------------------------------------------------------------------
02754 
02755 nnSSNR_Reconstructor::nnSSNR_Reconstructor()
02756 {
02757         m_volume = NULL;
02758         m_wptr   = NULL;
02759         m_wptr2  = NULL;
02760         m_result = NULL;
02761 }
02762 
02763 nnSSNR_Reconstructor::nnSSNR_Reconstructor( const string& symmetry, int size, int npad)
02764 {
02765         m_volume = NULL;
02766         m_wptr   = NULL;
02767         m_wptr2  = NULL;
02768         m_result = NULL;
02769 
02770         setup( symmetry, size, npad );
02771 }
02772 
02773 nnSSNR_Reconstructor::~nnSSNR_Reconstructor()
02774 {
02775         if( m_delete_volume ) checked_delete(m_volume);
02776 
02777         if( m_delete_weight ) checked_delete( m_wptr );
02778 
02779         if( m_delete_weight2 ) checked_delete( m_wptr2 );
02780 
02781         checked_delete( m_result );
02782 }
02783 
02784 void nnSSNR_Reconstructor::setup()
02785 {
02786         int size = params["size"];
02787         int npad = params["npad"];
02788 
02789         string symmetry;
02790         if( params.has_key("symmetry") ) symmetry = params["symmetry"].to_str();
02791         else                             symmetry = "c1";
02792 
02793         setup( symmetry, size, npad );
02794 }
02795 
02796 void nnSSNR_Reconstructor::setup( const string& symmetry, int size, int npad )
02797 {
02798 
02799         m_weighting = ESTIMATE;
02800         m_wghta = 0.2f;
02801         m_wghtb = 0.004f;
02802 
02803         m_symmetry = symmetry;
02804         m_npad = npad;
02805         m_nsym = Transform::get_nsym(m_symmetry);
02806 
02807         m_vnx = size;
02808         m_vny = size;
02809         m_vnz = size;
02810 
02811         m_vnxp = size*npad;
02812         m_vnyp = size*npad;
02813         m_vnzp = size*npad;
02814 
02815         m_vnxc = m_vnxp/2;
02816         m_vnyc = m_vnyp/2;
02817         m_vnzc = m_vnzp/2;
02818 
02819         buildFFTVolume();
02820         buildNormVolume();
02821         buildNorm2Volume();
02822 
02823 }
02824 
02825 void nnSSNR_Reconstructor::buildFFTVolume() {
02826 
02827         if( params.has_key("fftvol") ) {
02828                 m_volume = params["fftvol"]; /* volume should be defined in python when PMI is turned on*/
02829                 m_delete_volume = false;
02830         } else {
02831                 m_volume = new EMData();
02832                 m_delete_volume = true;
02833         }
02834         m_volume->set_size(m_vnxp+ 2 - m_vnxp%2,m_vnyp,m_vnzp);
02835         m_volume->to_zero();
02836         if ( m_vnxp % 2 == 0 ) m_volume->set_fftodd(0);
02837         else                   m_volume->set_fftodd(1);
02838 
02839         m_volume->set_nxc(m_vnxc);
02840         m_volume->set_complex(true);
02841         m_volume->set_ri(true);
02842         m_volume->set_fftpad(true);
02843         m_volume->set_attr("npad", m_npad);
02844         m_volume->set_array_offsets(0,1,1);
02845 }
02846 
02847 void nnSSNR_Reconstructor::buildNormVolume() {
02848         if( params.has_key("weight") ) {
02849                 m_wptr          = params["weight"];
02850                 m_delete_weight = false;
02851         } else {
02852                 m_wptr = new EMData();
02853                 m_delete_weight = true;
02854         }
02855 
02856         m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02857         m_wptr->to_zero();
02858 
02859         m_wptr->set_array_offsets(0,1,1);
02860 }
02861 
02862 void nnSSNR_Reconstructor::buildNorm2Volume() {
02863 
02864         if( params.has_key("weight2") ) {
02865                 m_wptr2          = params["weight2"];
02866                 m_delete_weight2 = false;
02867         } else {
02868                 m_wptr2 = new EMData();
02869                 m_delete_weight2 = true;
02870         }
02871         m_wptr2->set_size(m_vnxc+1,m_vnyp,m_vnzp);
02872         m_wptr2->to_zero();
02873         m_wptr2->set_array_offsets(0,1,1);
02874 }
02875 
02876 
02877 int nnSSNR_Reconstructor::insert_slice(const EMData* const slice, const Transform& t, const float weight) {
02878         // sanity checks
02879         if (!slice) {
02880                 LOGERR("try to insert NULL slice");
02881                 return 1;
02882         }
02883 
02884         int padffted=slice->get_attr_default( "padffted", 0 );
02885 
02886         if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  ) {
02887                 // FIXME: Why doesn't this throw an exception?
02888                 LOGERR("Tried to insert a slice that has wrong size.");
02889                 return 1;
02890         }
02891 
02892         EMData* padfft = NULL;
02893 
02894         if( padffted != 0 ) padfft = new EMData(*slice);
02895         else                padfft = padfft_slice( slice, t, m_npad );
02896 
02897         int mult = slice->get_attr_default("mult", 1);
02898 
02899         Assert( mult > 0 );
02900         insert_padfft_slice( padfft, t, mult );
02901 
02902         checked_delete( padfft );
02903         return 0;
02904 }
02905 
02906 int nnSSNR_Reconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
02907 {
02908         Assert( padfft != NULL );
02909         // insert slice for all symmetry related positions
02910         for (int isym=0; isym < m_nsym; isym++) {
02911                 Transform tsym = t.get_sym(m_symmetry, isym);
02912                 m_volume->nn_SSNR( m_wptr, m_wptr2, padfft, tsym, mult);
02913         }
02914         return 0;
02915 }
02916 
02917 
02918 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
02919 EMData* nnSSNR_Reconstructor::finish(bool doift)
02920 {
02921 /*
02922   I changed the code on 05/15 so it only returns variance.
02923   Lines commented out are marked by //#
02924   The version prior to the currect changes is r1.190
02925   PAP
02926 */
02927         int kz, ky;
02928         //#int iix, iiy, iiz;
02929         int box = 7;
02930         int kc = (box-1)/2;
02931         float alpha = 0.0;
02932         float argx, argy, argz;
02933         vector< float > pow_a( 3*kc+1, 1.0 );
02934         float w = params["w"];
02935         EMData* SSNR = params["SSNR"];
02936         //#EMData* vol_ssnr = new EMData();
02937         //#vol_ssnr->set_size(m_vnxp, m_vnyp, m_vnzp);
02938         //#vol_ssnr->to_zero();
02939         //#  new line follow
02940         EMData* vol_ssnr = new EMData();
02941         vol_ssnr->set_size(m_vnxp+ 2 - m_vnxp%2, m_vnyp ,m_vnzp);
02942         vol_ssnr->to_zero();
02943         if ( m_vnxp % 2 == 0 ) vol_ssnr->set_fftodd(0);
02944         else                   vol_ssnr->set_fftodd(1);
02945         vol_ssnr->set_nxc(m_vnxc);
02946         vol_ssnr->set_complex(true);
02947         vol_ssnr->set_ri(true);
02948         vol_ssnr->set_fftpad(false);
02949         //#
02950 
02951         float dx2 = 1.0f/float(m_vnxc)/float(m_vnxc);
02952         float dy2 = 1.0f/float(m_vnyc)/float(m_vnyc);
02953 #ifdef _WIN32
02954         float dz2 = 1.0f/_cpp_max(float(m_vnzc),1.0f)/_cpp_max(float(m_vnzc),1.0f);
02955         int  inc = Util::round(float(_cpp_max(_cpp_max(m_vnxc,m_vnyc),m_vnzc))/w);
02956 #else
02957         float dz2 = 1.0f/std::max(float(m_vnzc),1.0f)/std::max(float(m_vnzc),1.0f);
02958         int  inc = Util::round(float(std::max(std::max(m_vnxc,m_vnyc),m_vnzc))/w);
02959 #endif  //_WIN32
02960         SSNR->set_size(inc+1,4,1);
02961 
02962         float *nom    = new float[inc+1];
02963         float *denom  = new float[inc+1];
02964         int  *nn     = new int[inc+1];
02965         int  *ka     = new int[inc+1];
02966         float wght = 1.0f;
02967         for (int i = 0; i <= inc; i++) {
02968                 nom[i] = 0.0f;
02969                 denom[i] = 0.0f;
02970                 nn[i] = 0;
02971                 ka[i] = 0;
02972         }
02973 
02974         m_volume->symplane1(m_wptr, m_wptr2);
02975 
02976         if ( m_weighting == ESTIMATE ) {
02977                 int vol = box*box*box;
02978                 for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
02979                 pow_a[3*kc] = 0.0;
02980                 float max = max3d( kc, pow_a );
02981                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
02982         }
02983 
02984         for (int iz = 1; iz <= m_vnzp; iz++) {
02985                 if ( iz-1 > m_vnzc ) kz = iz-1-m_vnzp; else kz = iz-1;
02986                 argz = float(kz*kz)*dz2;
02987                 for (int iy = 1; iy <= m_vnyp; iy++) {
02988                         if ( iy-1 > m_vnyc ) ky = iy-1-m_vnyp; else ky = iy-1;
02989                         argy = argz + float(ky*ky)*dy2;
02990                         for (int ix = 0; ix <= m_vnxc; ix++) {
02991                                 float Kn = (*m_wptr)(ix,iy,iz);
02992                                 argx = std::sqrt(argy + float(ix*ix)*dx2);
02993                                 int r = Util::round(float(inc)*argx);
02994                                 if ( r >= 0 && Kn > 4.5f ) {
02995                                         if ( m_weighting == ESTIMATE ) {
02996                                                 int cx = ix;
02997                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
02998                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
02999 
03000                                                 float sum = 0.0;
03001                                                 for( int ii = -kc; ii <= kc; ++ii ) {
03002                                                         int nbrcx = cx + ii;
03003                                                         if( nbrcx >= m_vnxc ) continue;
03004                                                     for ( int jj= -kc; jj <= kc; ++jj ) {
03005                                                                 int nbrcy = cy + jj;
03006                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
03007                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
03008                                                                         int nbrcz = cz + jj;
03009                                                                         if ( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
03010                                                                         if( nbrcx < 0 ) {
03011                                                                                 nbrcx = -nbrcx;
03012                                                                                 nbrcy = -nbrcy;
03013                                                                                 nbrcz = -nbrcz;
03014                                                                         }
03015                                                                         int nbrix = nbrcx;
03016                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
03017                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
03018                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
03019                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
03020                                                                                 sum = sum + pow_a[c];
03021                                                                         }
03022                                                                 }
03023                                                         }
03024                                                 }
03025                                                 wght = 1.0f / ( 1.0f - alpha * sum );
03026                                         } // end of ( m_weighting == ESTIMATE )
03027                                         float nominator = std::norm(m_volume->cmplx(ix,iy,iz))/Kn;
03028                                         float denominator = ((*m_wptr2)(ix,iy,iz)-nominator)/(Kn-1.0f);
03029                                         // Skip Friedel related values
03030                                         if( (ix>0 || (kz>=0 && (ky>=0 || kz!=0)))) {
03031                                                 if ( r <= inc ) {
03032                                                         nom[r]   += nominator*wght;
03033                                                         denom[r] += denominator/Kn*wght;
03034                                                         nn[r]    += 2;
03035                                                         ka[r]    += int(Kn);
03036                                                 }
03037 /*
03038 #ifdef  _WIN32
03039                                                 //#float  tmp = _cpp_max(nominator/denominator/Kn-1.0f,0.0f);
03040 #else
03041                                                 //#float  tmp = std::max(nominator/denominator/Kn-1.0f,0.0f);
03042 #endif  //_WIN32
03043                                                 //  Create SSNR as a 3D array (-n/2:n/2+n%2-1)
03044                                                 iix = m_vnxc + ix; iiy = m_vnyc + ky; iiz = m_vnzc + kz;
03045                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
03046                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
03047                                                 // Friedel part
03048                                                 iix = m_vnxc - ix; iiy = m_vnyc - ky; iiz = m_vnzc - kz;
03049                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
03050                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
03051 */
03052 
03053                                         }
03054                                         (*vol_ssnr)(2*ix, iy-1, iz-1) = denominator*wght;
03055                                         //(*vol_ssnr)(2*ix, iy-1, iz-1) =  real(m_volume->cmplx(ix,iy,iz))*wght/Kn;
03056                                         //(*vol_ssnr)(2*ix+1, iy-1, iz-1) = imag(m_volume->cmplx(ix,iy,iz))*wght/Kn;
03057                                 } // end of Kn>4.5
03058                         }
03059                 }
03060         }
03061 
03062         for (int i = 0; i <= inc; i++)  {
03063                 (*SSNR)(i,0,0) = nom[i];  
03064                 (*SSNR)(i,1,0) = denom[i];    // variance
03065                 (*SSNR)(i,2,0) = static_cast<float>(nn[i]);
03066                 (*SSNR)(i,3,0) = static_cast<float>(ka[i]);
03067         }
03068         vol_ssnr->update();
03069         return vol_ssnr;
03070 }
03071 #undef  tw
03072 
03073 // -----------------------------------------------------------------------------------
03074 // End of this addition
03075 
03076 //####################################################################################
03077 //** nn4 ctf reconstructor
03078 
03079 nn4_ctfReconstructor::nn4_ctfReconstructor()
03080 {
03081         m_volume  = NULL;
03082         m_wptr    = NULL;
03083         m_result  = NULL;
03084 }
03085 
03086 nn4_ctfReconstructor::nn4_ctfReconstructor( const string& symmetry, int size, int npad, float snr, int sign )
03087 {
03088         setup( symmetry, size, npad, snr, sign );
03089 }
03090 
03091 nn4_ctfReconstructor::~nn4_ctfReconstructor()
03092 {
03093         if( m_delete_volume ) checked_delete(m_volume);
03094 
03095         if( m_delete_weight ) checked_delete( m_wptr );
03096 
03097         checked_delete( m_result );
03098 }
03099 
03100 void nn4_ctfReconstructor::setup()
03101 {
03102         if( ! params.has_key("size") ) throw std::logic_error("Error: image size is not given");
03103 
03104         int size = params["size"];
03105         int npad = params.has_key("npad") ? int(params["npad"]) : 4;
03106         // int sign = params.has_key("sign") ? int(params["sign"]) : 1;
03107         int sign = 1;
03108         string symmetry = params.has_key("symmetry")? params["symmetry"].to_str() : "c1";
03109 
03110         float snr = params["snr"];
03111 
03112         m_varsnr = params.has_key("varsnr") ? int(params["varsnr"]) : 0;
03113         setup( symmetry, size, npad, snr, sign );
03114 
03115 }
03116 
03117 void nn4_ctfReconstructor::setup( const string& symmetry, int size, int npad, float snr, int sign )
03118 {
03119         m_weighting = ESTIMATE;
03120         if( params.has_key("weighting") ) {
03121                 int tmp = int( params["weighting"] );
03122                 if( tmp==0 ) m_weighting = NONE;
03123         }
03124 
03125 
03126 
03127         m_wghta = 0.2f;
03128         m_wghtb = 0.004f;
03129 
03130         m_symmetry = symmetry;
03131         m_npad = npad;
03132         m_sign = sign;
03133         m_nsym = Transform::get_nsym(m_symmetry);
03134 
03135         m_snr = snr;
03136 
03137         m_vnx = size;
03138         m_vny = size;
03139         m_vnz = size;
03140 
03141         m_vnxp = size*npad;
03142         m_vnyp = size*npad;
03143         m_vnzp = size*npad;
03144 
03145         m_vnxc = m_vnxp/2;
03146         m_vnyc = m_vnyp/2;
03147         m_vnzc = m_vnzp/2;
03148 
03149         buildFFTVolume();
03150         buildNormVolume();
03151 }
03152 
03153 void nn4_ctfReconstructor::buildFFTVolume() {
03154         int offset = 2 - m_vnxp%2;
03155         if( params.has_key("fftvol") ) {
03156                 m_volume = params["fftvol"];
03157                 m_delete_volume = false;
03158         } else {
03159                 m_volume = new EMData();
03160                 m_delete_volume = true;
03161         }
03162 
03163         if( m_volume->get_xsize() != m_vnxp+offset && m_volume->get_ysize() != m_vnyp && m_volume->get_zsize() != m_vnzp ) {
03164                 m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
03165                 m_volume->to_zero();
03166         }
03167 
03168         m_volume->set_nxc(m_vnxp/2);
03169         m_volume->set_complex(true);
03170         m_volume->set_ri(true);
03171         m_volume->set_fftpad(true);
03172         m_volume->set_attr("npad", m_npad);
03173         m_volume->set_array_offsets(0,1,1);
03174 }
03175 
03176 void nn4_ctfReconstructor::buildNormVolume()
03177 {
03178         if( params.has_key("weight") ) {
03179                 m_wptr = params["weight"];
03180                 m_delete_weight = false;
03181         } else {
03182                 m_wptr = new EMData();
03183                 m_delete_weight = true;
03184         }
03185 
03186         if( m_wptr->get_xsize() != m_vnxc+1 && m_wptr->get_ysize() != m_vnyp && m_wptr->get_zsize() != m_vnzp ) {
03187                m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03188                m_wptr->to_zero();
03189         }
03190 
03191         m_wptr->set_array_offsets(0,1,1);
03192 
03193 }
03194 
03195 int nn4_ctfReconstructor::insert_slice(const EMData* const slice, const Transform& t, const float weight)
03196 {
03197         // sanity checks
03198         if (!slice) {
03199                 LOGERR("try to insert NULL slice");
03200                 return 1;
03201         }
03202 
03203         int buffed = slice->get_attr_default( "buffed", 0 );
03204         if( buffed > 0 ) {
03205                 int mult = slice->get_attr_default( "mult", 1 );
03206                 insert_buffed_slice( slice, mult );
03207                 return 0;
03208         }
03209 
03210         int padffted= slice->get_attr_default("padffted", 0);
03211         if( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  )
03212         {
03213                 // FIXME: Why doesn't this throw an exception?
03214                 LOGERR("Tried to insert a slice that is the wrong size.");
03215                 return 1;
03216         }
03217 
03218         EMData* padfft = NULL;
03219 
03220         if( padffted != 0 ) padfft = new EMData(*slice);
03221         else                padfft = padfft_slice( slice, t, m_npad );
03222 
03223         int mult= slice->get_attr_default("mult", 1);
03224 
03225         Assert( mult > 0 );
03226         insert_padfft_slice( padfft, t, mult );
03227 
03228         checked_delete( padfft );
03229 
03230         return 0;
03231 }
03232 
03233 int nn4_ctfReconstructor::insert_buffed_slice( const EMData* buffed, int mult )
03234 {
03235         const float* bufdata = buffed->get_data();
03236         float* cdata = m_volume->get_data();
03237         float* wdata = m_wptr->get_data();
03238 
03239         int npoint = buffed->get_xsize()/4;
03240         for( int i=0; i < npoint; ++i ) {
03241 
03242                 int pos2 = int( bufdata[4*i] );
03243                 int pos1 = pos2 * 2;
03244                 cdata[pos1  ] += bufdata[4*i+1]*mult;
03245                 cdata[pos1+1] += bufdata[4*i+2]*mult;
03246                 wdata[pos2  ] += bufdata[4*i+3]*mult;
03247 /*
03248         std::cout << "pos1, pos2, ctfv1, ctfv2, ctf2: ";
03249         std::cout << pos1 << " " << bufdata[5*i+1] << " " << bufdata[5*i+2] << " ";
03250         std::cout << pos2 << " " << bufdata[5*i+4] << std::endl;
03251  */
03252         }
03253         return 0;
03254 }
03255 
03256 int nn4_ctfReconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
03257 {
03258         Assert( padfft != NULL );
03259         float tmp = padfft->get_attr("ctf_applied");
03260         int   ctf_applied = (int) tmp;
03261 
03262         for( int isym=0; isym < m_nsym; isym++) {
03263                 Transform tsym = t.get_sym( m_symmetry, isym );
03264 
03265                 if(ctf_applied) m_volume->nn_ctf_applied(m_wptr, padfft, tsym, mult);
03266                                 
03267                 else            m_volume->nn_ctf(m_wptr, padfft, tsym, mult);
03268         }
03269 
03270         return 0;
03271 
03272 }
03273 
03274 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
03275 EMData* nn4_ctfReconstructor::finish(bool doift)
03276 {
03277         m_volume->set_array_offsets(0, 1, 1);
03278         m_wptr->set_array_offsets(0, 1, 1);
03279         m_volume->symplane0_ctf(m_wptr);
03280 
03281         int box = 7;
03282         int vol = box*box*box;
03283         int kc = (box-1)/2;
03284         vector< float > pow_a( 3*kc+1, 1.0 );
03285         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
03286         pow_a[3*kc]=0.0;
03287 
03288 
03289         float max = max3d( kc, pow_a );
03290         float alpha = ( 1.0f - 1.0f/(float)vol ) / max;
03291         float osnr = 1.0f/m_snr;
03292 
03293         // normalize
03294         int ix,iy,iz;
03295         for (iz = 1; iz <= m_vnzp; iz++) {
03296                 for (iy = 1; iy <= m_vnyp; iy++) {
03297                         for (ix = 0; ix <= m_vnxc; ix++) {
03298                                 if ( (*m_wptr)(ix,iy,iz) > 0.0f) {//(*v) should be treated as complex!!
03299                     int iyp = (iy<=m_vnyc) ? iy - 1 : iy-m_vnyp-1;
03300                     int izp = (iz<=m_vnzc) ? iz - 1 : iz-m_vnzp-1;
03301                     float tmp=0.0;
03302                     if( m_varsnr )
03303                     {
03304                                             float freq = sqrt( (float)(ix*ix+iyp*iyp+izp*izp) );
03305                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+freq*osnr)*m_sign;
03306                     }
03307                     else
03308                     {
03309                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+osnr)*m_sign;
03310                     }
03311 
03312                                         if( m_weighting == ESTIMATE ) {
03313                                                 int cx = ix;
03314                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
03315                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
03316                                                 float sum = 0.0;
03317                                                 for( int ii = -kc; ii <= kc; ++ii ) {
03318                                                         int nbrcx = cx + ii;
03319                                                         if( nbrcx >= m_vnxc ) continue;
03320                                                         for( int jj= -kc; jj <= kc; ++jj ) {
03321                                                                 int nbrcy = cy + jj;
03322                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
03323                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
03324                                                                         int nbrcz = cz + jj;
03325                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
03326                                                                         if( nbrcx < 0 ) {
03327                                                                                 nbrcx = -nbrcx;
03328                                                                                 nbrcy = -nbrcy;
03329                                                                                 nbrcz = -nbrcz;
03330                                                                         }
03331 
03332                                                                         int nbrix = nbrcx;
03333                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
03334                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
03335                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0.0 ) {
03336                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
03337                                                                                 sum = sum + pow_a[c];
03338                                                                                   // if(ix%20==0 && iy%20==0 && iz%20==0)
03339                                                                                  //   std::cout << boost::format( "%4d %4d %4d %4d %10.3f" ) % nbrix % nbriy % nbriz % c % sum << std::endl;
03340                                                                         }
03341                                                                 }
03342                                                         }
03343                                                 }
03344                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
03345 /*
03346                         if(ix%10==0 && iy%10==0)
03347                         {
03348                             std::cout << boost::format( "%4d %4d %4d " ) % ix % iy %iz;
03349                             std::cout << boost::format( "%10.3f %10.3f %10.3f " )  % tmp % wght % sum;
03350                             std::  << boost::format( "%10.3f %10.3e " ) % pow_b[r] % alpha;
03351                             std::cout << std::endl;
03352                         }
03353  */
03354                                                 tmp = tmp * wght;
03355                                         }
03356                                         (*m_volume)(2*ix,iy,iz) *= tmp;
03357                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
03358                                 }
03359                         }
03360                 }
03361         }
03362 
03363         // back fft
03364         m_volume->do_ift_inplace();
03365         int npad = m_volume->get_attr("npad");
03366         m_volume->depad();
03367         circumf( m_volume, npad );
03368         m_volume->set_array_offsets( 0, 0, 0 );
03369         m_result = m_volume->copy();
03370         return m_result;
03371 }
03372 #undef  tw
03373 
03374 
03375 
03376 //####################################################################################
03377 //** nn4 ctf rect reconstructor
03378 
03379 nn4_ctf_rectReconstructor::nn4_ctf_rectReconstructor()
03380 {
03381         m_volume  = NULL;
03382         m_wptr    = NULL;
03383         m_result  = NULL;
03384 }
03385 
03386 nn4_ctf_rectReconstructor::nn4_ctf_rectReconstructor( const string& symmetry, int size, int npad, float snr, int sign )
03387 {
03388         setup( symmetry, size, npad, snr, sign );
03389 }
03390 
03391 nn4_ctf_rectReconstructor::~nn4_ctf_rectReconstructor()
03392 {
03393         if( m_delete_volume ) checked_delete(m_volume);
03394 
03395         if( m_delete_weight ) checked_delete( m_wptr );
03396 
03397         checked_delete( m_result );
03398 }
03399 
03400 void nn4_ctf_rectReconstructor::setup()
03401 {
03402         if( ! params.has_key("sizeprojection") ) throw std::logic_error("Error: projection size is not given");
03403         m_sizeofprojection = params["sizeprojection"];
03404         int npad = params.has_key("npad") ? int(params["npad"]) : 4;
03405         // int sign = params.has_key("sign") ? int(params["sign"]) : 1;
03406         int sign = 1;
03407         string symmetry = params.has_key("symmetry")? params["symmetry"].to_str() : "c1";
03408 
03409         float snr = params["snr"];
03410 
03411         m_varsnr = params.has_key("varsnr") ? int(params["varsnr"]) : 0;
03412         setup( symmetry, m_sizeofprojection, npad, snr, sign );
03413 
03414 }
03415 
03416 void nn4_ctf_rectReconstructor::setup( const string& symmetry, int sizeprojection, int npad, float snr, int sign )
03417 {
03418         m_weighting = ESTIMATE;
03419         if( params.has_key("weighting") ) {
03420                 int tmp = int( params["weighting"] );
03421                 if( tmp==0 ) m_weighting = NONE;
03422         }
03423 
03424 
03425 
03426         m_wghta = 0.2f;
03427         m_wghtb = 0.004f;
03428 
03429         m_symmetry = symmetry;
03430         m_npad = npad;
03431         m_sign = sign;
03432         m_nsym = Transform::get_nsym(m_symmetry);
03433 
03434         m_snr = snr;
03435         if( params.has_key("sizex") )  m_vnx = params["sizex"];
03436         else if(params.has_key("xratio")) 
03437                 {
03438                 float temp=params["xratio"];
03439                 m_vnx=int(float(sizeprojection)*temp);
03440                 }
03441         else                           m_vnx=sizeprojection;
03442 
03443         if( params.has_key("sizey") )  m_vny = params["sizey"];
03444         else if (params.has_key("yratio"))  
03445                {
03446                 float temp=params["yratio"];
03447                  m_vny=int(float(sizeprojection)*temp);
03448                 }
03449         else m_vny=sizeprojection;
03450 
03451         if( params.has_key("sizez") ) 
03452                 m_vnz = params["sizez"];
03453         else                          
03454                 m_vnz =sizeprojection;
03455         
03456         m_xratio=float(m_vnx)/float(sizeprojection);    
03457         m_yratio=float(m_vny)/float(sizeprojection);
03458 
03459         //std::cout<<"xratio=="<<m_xratio<<"yratio=="<<m_yratio<<std::endl;
03460         //std::cout<<"sx=="<<m_vnx<<"sy=="<<m_vny<<"sz=="<<m_vnz<<std::endl;
03461 
03462         m_vnxp = m_vnx*npad;
03463         m_vnyp = m_vny*npad;
03464         m_vnzp = m_vnz*npad;
03465 
03466         m_vnxc = m_vnxp/2;
03467         m_vnyc = m_vnyp/2;
03468         m_vnzc = m_vnzp/2;
03469 
03470         buildFFTVolume();
03471         buildNormVolume();
03472 }
03473 
03474 void nn4_ctf_rectReconstructor::buildFFTVolume() {
03475         int offset = 2 - m_vnxp%2;
03476         if( params.has_key("fftvol") ) {
03477                 m_volume = params["fftvol"];
03478                 m_delete_volume = false;
03479         } else {
03480                 m_volume = new EMData();
03481                 m_delete_volume = true;
03482         }
03483 
03484         if( m_volume->get_xsize() != m_vnxp+offset && m_volume->get_ysize() != m_vnyp && m_volume->get_zsize() != m_vnzp ) {
03485                 m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
03486                 m_volume->to_zero();
03487         }
03488 
03489         m_volume->set_nxc(m_vnxp/2);
03490         m_volume->set_complex(true);
03491         m_volume->set_ri(true);
03492         m_volume->set_fftpad(true);
03493         m_volume->set_attr("npad", m_npad);
03494         m_volume->set_array_offsets(0,1,1);
03495 }
03496 
03497 void nn4_ctf_rectReconstructor::buildNormVolume()
03498 {
03499         if( params.has_key("weight") ) {
03500                 m_wptr = params["weight"];
03501                 m_delete_weight = false;
03502         } else {
03503                 m_wptr = new EMData();
03504                 m_delete_weight = true;
03505         }
03506 
03507         if( m_wptr->get_xsize() != m_vnxc+1 && m_wptr->get_ysize() != m_vnyp && m_wptr->get_zsize() != m_vnzp ) {
03508                m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03509                m_wptr->to_zero();
03510         }
03511 
03512         m_wptr->set_array_offsets(0,1,1);
03513 
03514 }
03515 
03516 int nn4_ctf_rectReconstructor::insert_slice(const EMData* const slice, const Transform& t, const float weight)
03517 {
03518         // sanity checks
03519         if (!slice) {
03520                 LOGERR("try to insert NULL slice");
03521                 return 1;
03522         }
03523 
03524         int buffed = slice->get_attr_default( "buffed", 0 );
03525         if( buffed > 0 ) {
03526                 int mult = slice->get_attr_default( "mult", 1 );
03527                 insert_buffed_slice( slice, mult );
03528                 return 0;
03529         }
03530 
03531         int padffted= slice->get_attr_default("padffted", 0);
03532         //if( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  )
03533         if( padffted==0 && (slice->get_xsize()!=slice->get_ysize())  )
03534         {
03535                 // FIXME: Why doesn't this throw an exception?
03536                 LOGERR("Tried to insert a slice that is the wrong size.");
03537                 return 1;
03538         }
03539 
03540         EMData* padfft = NULL;
03541 
03542         if( padffted != 0 ) padfft = new EMData(*slice);
03543         else                padfft = padfft_slice( slice, t, m_npad );
03544 
03545         int mult= slice->get_attr_default("mult", 1);
03546 
03547         Assert( mult > 0 );
03548         insert_padfft_slice( padfft, t, mult );
03549 
03550         checked_delete( padfft );
03551 
03552         return 0;
03553 }
03554 
03555 int nn4_ctf_rectReconstructor::insert_buffed_slice( const EMData* buffed, int mult )
03556 {
03557         const float* bufdata = buffed->get_data();
03558         float* cdata = m_volume->get_data();
03559         float* wdata = m_wptr->get_data();
03560 
03561         int npoint = buffed->get_xsize()/4;
03562         for( int i=0; i < npoint; ++i ) {
03563 
03564                 int pos2 = int( bufdata[4*i] );
03565                 int pos1 = pos2 * 2;
03566                 cdata[pos1  ] += bufdata[4*i+1]*mult;
03567                 cdata[pos1+1] += bufdata[4*i+2]*mult;
03568                 wdata[pos2  ] += bufdata[4*i+3]*mult;
03569 /*
03570         std::cout << "pos1, pos2, ctfv1, ctfv2, ctf2: ";
03571         std::cout << pos1 << " " << bufdata[5*i+1] << " " << bufdata[5*i+2] << " ";
03572         std::cout << pos2 << " " << bufdata[5*i+4] << std::endl;
03573  */
03574         }
03575         return 0;
03576 }
03577 
03578 
03579 int nn4_ctf_rectReconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
03580 {
03581         Assert( padfft != NULL );
03582         float tmp = padfft->get_attr("ctf_applied");
03583         int   ctf_applied = (int) tmp;
03584 
03585         if (ctf_applied)        m_volume->insert_rect_slice_ctf_applied(m_wptr, padfft, t, m_sizeofprojection, m_xratio,m_yratio, m_npad, mult);
03586         else                    m_volume->insert_rect_slice_ctf(m_wptr, padfft, t, m_sizeofprojection, m_xratio, m_yratio, m_npad, mult);
03587 
03588         
03589 
03590         return 0;
03591 
03592 }
03593 
03594 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
03595 EMData* nn4_ctf_rectReconstructor::finish(bool doift)
03596 {
03597         m_volume->set_array_offsets(0, 1, 1);
03598         m_wptr->set_array_offsets(0, 1, 1);
03599         m_volume->symplane0_rect(m_wptr);
03600 
03601         int box = 7;
03602         int vol = box*box*box;
03603         int kc = (box-1)/2;
03604         vector< float > pow_a( 3*kc+1, 1.0 );
03605         for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
03606         pow_a[3*kc]=0.0;
03607 
03608 
03609         float max = max3d( kc, pow_a );
03610         float alpha = ( 1.0f - 1.0f/(float)vol ) / max;
03611         float osnr = 1.0f/m_snr;
03612 
03613         // normalize
03614         int ix,iy,iz;
03615         for (iz = 1; iz <= m_vnzp; iz++) {
03616                 for (iy = 1; iy <= m_vnyp; iy++) {
03617                         for (ix = 0; ix <= m_vnxc; ix++) {
03618                                 if ( (*m_wptr)(ix,iy,iz) > 0.0f) {//(*v) should be treated as complex!!
03619                     int iyp = (iy<=m_vnyc) ? iy - 1 : iy-m_vnyp-1;
03620                     int izp = (iz<=m_vnzc) ? iz - 1 : iz-m_vnzp-1;
03621                     float tmp=0.0;
03622                     if( m_varsnr )
03623                     {
03624                         float freq = sqrt( (float)(ix*ix/(m_xratio*m_xratio)+iyp*iyp/(m_zratio*m_yratio)+izp*izp) );
03625                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+freq*osnr)*m_sign;
03626                     }
03627                     else
03628                     {
03629                         tmp = (-2*((ix+iy+iz)%2)+1)/((*m_wptr)(ix,iy,iz)+osnr)*m_sign;
03630                     }
03631 
03632                                         if( m_weighting == ESTIMATE ) {
03633                                                 int cx = ix;
03634                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
03635                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
03636                                                 float sum = 0.0;
03637                                                 for( int ii = -kc; ii <= kc; ++ii ) {
03638                                                         int nbrcx = cx + ii;
03639                                                         if( nbrcx >= m_vnxc ) continue;
03640                                                         for( int jj= -kc; jj <= kc; ++jj ) {
03641                                                                 int nbrcy = cy + jj;
03642                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
03643                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
03644                                                                         int nbrcz = cz + jj;
03645                                                                         if( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
03646                                                                         if( nbrcx < 0 ) {
03647                                                                                 nbrcx = -nbrcx;
03648                                                                                 nbrcy = -nbrcy;
03649                                                                                 nbrcz = -nbrcz;
03650                                                                         }
03651 
03652                                                                         int nbrix = nbrcx;
03653                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
03654                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
03655                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0.0 ) {
03656                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
03657                                                                                 sum = sum + pow_a[c];
03658                                                                                   // if(ix%20==0 && iy%20==0 && iz%20==0)
03659                                                                                  //   std::cout << boost::format( "%4d %4d %4d %4d %10.3f" ) % nbrix % nbriy % nbriz % c % sum << std::endl;
03660                                                                         }
03661                                                                 }
03662                                                         }
03663                                                 }
03664                                                 float wght = 1.0f / ( 1.0f - alpha * sum );
03665 /*
03666                         if(ix%10==0 && iy%10==0)
03667                         {
03668                             std::cout << boost::format( "%4d %4d %4d " ) % ix % iy %iz;
03669                             std::cout << boost::format( "%10.3f %10.3f %10.3f " )  % tmp % wght % sum;
03670                             std::  << boost::format( "%10.3f %10.3e " ) % pow_b[r] % alpha;
03671                             std::cout << std::endl;
03672                         }
03673  */
03674                                                 tmp = tmp * wght;
03675                                         }
03676                                         (*m_volume)(2*ix,iy,iz) *= tmp;
03677                                         (*m_volume)(2*ix+1,iy,iz) *= tmp;
03678                                 }
03679                         }
03680                 }
03681         }
03682 
03683         // back fft
03684         m_volume->do_ift_inplace();
03685         int npad = m_volume->get_attr("npad");
03686         m_volume->depad();
03687         circumf_rect( m_volume, npad );
03688         m_volume->set_array_offsets( 0, 0, 0 );
03689         m_result = m_volume->copy();
03690         return m_result;
03691 }
03692 #undef  tw
03693 
03694 
03695 
03696 // Added By Zhengfan Yang on 04/11/07
03697 // Beginning of the addition
03698 // --------------------------------------------------------------------------------
03699 
03700 nnSSNR_ctfReconstructor::nnSSNR_ctfReconstructor()
03701 {
03702         m_volume  = NULL;
03703         m_wptr    = NULL;
03704         m_wptr2   = NULL;
03705         m_wptr3   = NULL;
03706         m_result  = NULL;
03707 }
03708 
03709 nnSSNR_ctfReconstructor::nnSSNR_ctfReconstructor( const string& symmetry, int size, int npad, float snr, int sign)
03710 {
03711         m_volume  = NULL;
03712         m_wptr    = NULL;
03713         m_wptr2   = NULL;
03714         m_wptr3   = NULL;
03715         m_result  = NULL;
03716 
03717         setup( symmetry, size, npad, snr, sign );
03718 }
03719 
03720 nnSSNR_ctfReconstructor::~nnSSNR_ctfReconstructor()
03721 {
03722 
03723         if( m_delete_volume )  checked_delete(m_volume);
03724         if( m_delete_weight )  checked_delete( m_wptr );
03725         if( m_delete_weight2 ) checked_delete( m_wptr2 );
03726         if( m_delete_weight3 ) checked_delete( m_wptr3 );
03727         checked_delete( m_result );
03728 }
03729 
03730 void nnSSNR_ctfReconstructor::setup()
03731 {
03732         int  size = params["size"];
03733         int  npad = params["npad"];
03734         int  sign = params["sign"];
03735         float snr = params["snr"];
03736         string symmetry;
03737         if( params.has_key("symmetry") )  symmetry = params["symmetry"].to_str();
03738         else                              symmetry = "c1";
03739 
03740         setup( symmetry, size, npad, snr, sign );
03741 }
03742 void nnSSNR_ctfReconstructor::setup( const string& symmetry, int size, int npad, float snr, int sign )
03743 {
03744 
03745         m_weighting = ESTIMATE;
03746         m_wghta     = 0.2f;
03747         m_wghtb     = 0.004f;
03748         wiener      = 1;
03749 
03750         m_symmetry  = symmetry;
03751         m_npad      = npad;
03752         m_nsym      = Transform::get_nsym(m_symmetry);
03753 
03754         m_sign      = sign;
03755         m_snr       = snr;
03756 
03757         m_vnx       = size;
03758         m_vny       = size;
03759         m_vnz       = size;
03760 
03761         m_vnxp      = size*npad;
03762         m_vnyp      = size*npad;
03763         m_vnzp      = size*npad;
03764 
03765         m_vnxc      = m_vnxp/2;
03766         m_vnyc      = m_vnyp/2;
03767         m_vnzc      = m_vnzp/2;
03768 
03769         buildFFTVolume();
03770         buildNormVolume();
03771         buildNorm2Volume();
03772         buildNorm3Volume();
03773 }
03774 
03775 void nnSSNR_ctfReconstructor::buildFFTVolume() {
03776 
03777         int offset = 2 - m_vnxp%2;
03778         if( params.has_key("fftvol") ) {
03779                 m_volume = params["fftvol"]; /* volume should be defined in python when PMI is turned on*/
03780                 m_delete_volume = false;
03781         } else {
03782                 m_volume = new EMData();
03783                 m_delete_volume = true;
03784         }
03785 
03786         m_volume->set_size(m_vnxp+offset,m_vnyp,m_vnzp);
03787         m_volume->to_zero();
03788 
03789         m_volume->set_fftodd(m_vnxp % 2);
03790 
03791         m_volume->set_nxc(m_vnxc);
03792         m_volume->set_complex(true);
03793         m_volume->set_ri(true); //(real, imaginary) instead of polar coordinate
03794         m_volume->set_fftpad(true);
03795         m_volume->set_attr("npad", m_npad);
03796         m_volume->set_array_offsets(0,1,1);
03797 }
03798 
03799 
03800 void nnSSNR_ctfReconstructor::buildNormVolume()
03801 {
03802         if( params.has_key("weight") ) {
03803                  m_wptr          = params["weight"];
03804                  m_delete_weight = false;
03805         } else {
03806                 m_wptr = new EMData();
03807                 m_delete_weight = true;
03808         }
03809         m_wptr->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03810         m_wptr->to_zero();
03811         m_wptr->set_array_offsets(0,1,1);
03812 }
03813 
03814 void nnSSNR_ctfReconstructor::buildNorm2Volume() {
03815 
03816         if( params.has_key("weight2") ) {
03817                 m_wptr2          = params["weight2"];
03818                 m_delete_weight2 = false;
03819         } else {
03820                 m_wptr2 = new EMData();
03821                 m_delete_weight2 = true;
03822         }
03823         m_wptr2->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03824         m_wptr2->to_zero();
03825         m_wptr2->set_array_offsets(0,1,1);
03826 }
03827 
03828 void nnSSNR_ctfReconstructor::buildNorm3Volume() {
03829 
03830         if( params.has_key("weight3") ) {
03831                 m_wptr3          = params["weight3"];
03832                 m_delete_weight3 = false;
03833         } else {
03834                 m_wptr3 = new EMData();
03835                 m_delete_weight3 = true;
03836         }
03837         m_wptr3->set_size(m_vnxc+1,m_vnyp,m_vnzp);
03838         m_wptr3->to_zero();
03839         m_wptr3->set_array_offsets(0,1,1);
03840 }
03841 
03842 int nnSSNR_ctfReconstructor::insert_slice(const EMData *const  slice, const Transform& t, const float weight) {
03843         // sanity checks
03844         if (!slice) {
03845                 LOGERR("try to insert NULL slice");
03846                 return 1;
03847         }
03848         int padffted= slice->get_attr_default("padffted", 0);
03849         if ( padffted==0 && (slice->get_xsize()!=slice->get_ysize() || slice->get_xsize()!=m_vnx)  ) {
03850                 // FIXME: Why doesn't this throw an exception?
03851                 LOGERR("Tried to insert a slice that is the wrong size.");
03852                 return 1;
03853         }
03854         EMData* padfft = NULL;
03855 
03856         if( padffted != 0 ) padfft = new EMData(*slice);
03857         else                 padfft = padfft_slice( slice, t, m_npad );
03858 
03859         int mult= slice->get_attr_default("mult", 1);
03860 
03861         Assert( mult > 0 );
03862         insert_padfft_slice( padfft, t, mult );
03863 
03864         checked_delete( padfft );
03865         return 0;
03866 }
03867 int nnSSNR_ctfReconstructor::insert_padfft_slice( EMData* padfft, const Transform& t, int mult )
03868 {
03869         Assert( padfft != NULL );
03870 
03871         // insert slice for all symmetry related positions
03872         for (int isym=0; isym < m_nsym; isym++) {
03873                 Transform tsym = t.get_sym(m_symmetry, isym);
03874                 m_volume->nn_SSNR_ctf(m_wptr, m_wptr2, m_wptr3, padfft, tsym, mult);
03875         }
03876 
03877         return 0;
03878 }
03879 
03880 #define  tw(i,j,k)      tw[ i-1 + (j-1+(k-1)*iy)*ix ]
03881 EMData* nnSSNR_ctfReconstructor::finish(bool doift)
03882 {
03883 /*
03884   I changed the code on 05/15 so it only returns variance.
03885   Lines commented out are marked by //#
03886   The version prior to the currect changes is r1.190
03887   PAP
03888 */
03889         /***
03890             m_volume ctf*(P^2D->3D(F^3D))
03891             m_wptr   ctf^2
03892             m_wptr2  |P^2D->3D(F^3D)|^2
03893             m_wptr3  Kn
03894             nominator = sum_rot [ wght*signal ]
03895             denominator  = sum_rot[ wght*variance ]
03896                                                       ***/
03897         int kz, ky;
03898         int box = 7;
03899         int kc  = (box-1)/2;
03900         float alpha = 0.0;
03901         float argx, argy, argz;
03902         vector< float > pow_a( 3*kc+1, 1.0 );
03903         float w = params["w"];
03904         float dx2 = 1.0f/float(m_vnxc)/float(m_vnxc);
03905         float dy2 = 1.0f/float(m_vnyc)/float(m_vnyc);
03906 #ifdef  _WIN32
03907         float dz2 = 1.0f/_cpp_max(float(m_vnzc),1.0f)/_cpp_max(float(m_vnzc),1.0f);
03908         int inc = Util::round(float(_cpp_max(_cpp_max(m_vnxc,m_vnyc),m_vnzc))/w);
03909 #else
03910         float dz2 = 1.0f/std::max(float(m_vnzc),1.0f)/std::max(float(m_vnzc),1.0f);
03911         int inc = Util::round(float(std::max(std::max(m_vnxc,m_vnyc),m_vnzc))/w);
03912 #endif  //_WIN32
03913 
03914         EMData* SSNR = params["SSNR"];
03915         SSNR->set_size(inc+1,4,1);
03916         //#EMData* vol_ssnr = new EMData();
03917         //#vol_ssnr->set_size(m_vnxp, m_vnyp, m_vnzp);
03918         //#vol_ssnr->to_zero();
03919         //#  new linea follow
03920         EMData* vol_ssnr = new EMData();
03921         vol_ssnr->set_size(m_vnxp+ 2 - m_vnxp%2, m_vnyp ,m_vnzp);
03922         vol_ssnr->to_zero();
03923         if ( m_vnxp % 2 == 0 ) vol_ssnr->set_fftodd(0);
03924         else                   vol_ssnr->set_fftodd(1);
03925         vol_ssnr->set_nxc(m_vnxc);
03926         vol_ssnr->set_complex(true);
03927         vol_ssnr->set_ri(true);
03928         vol_ssnr->set_fftpad(false);
03929         //#
03930         float *nom    = new float[inc+1];
03931         float *denom  = new float[inc+1];
03932         int  *ka     = new int[inc+1];
03933         int  *nn     = new int[inc+1];
03934         float wght = 1.f;
03935         for (int i = 0; i <= inc; i++) {
03936                 nom[i]   = 0.0f;
03937                 denom[i] = 0.0f;
03938                 nn[i]    = 0;
03939                 ka[i]    = 0;
03940         }
03941         m_volume->symplane2(m_wptr, m_wptr2, m_wptr3);
03942         if ( m_weighting == ESTIMATE ) {
03943                 int vol = box*box*box;
03944                 for( unsigned int i=1; i < pow_a.size(); ++i ) pow_a[i] = pow_a[i-1] * exp(m_wghta);
03945                 pow_a[3*kc] = 0.0;
03946                 float max = max3d( kc, pow_a );
03947                 alpha = ( 1.0f - 1.0f/(float)vol ) / max;
03948         }
03949         for (int iz = 1; iz <= m_vnzp; iz++) {
03950                 if ( iz-1 > m_vnzc ) kz = iz-1-m_vnzp; else kz = iz-1;
03951                 argz = float(kz*kz)*dz2;
03952                 for (int iy = 1; iy <= m_vnyp; iy++) {
03953                         if ( iy-1 > m_vnyc ) ky = iy-1-m_vnyp; else ky = iy-1;
03954                         argy = argz + float(ky*ky)*dy2;
03955                         for (int ix = 0; ix <= m_vnxc; ix++) {
03956                                 float Kn = (*m_wptr3)(ix,iy,iz);
03957                                 argx = std::sqrt(argy + float(ix*ix)*dx2);
03958                                 int r = Util::round(float(inc)*argx);
03959                                 if ( r >= 0 && Kn > 4.5f ) {
03960                                         if ( m_weighting == ESTIMATE ) {
03961                                                 int cx = ix;
03962                                                 int cy = (iy<=m_vnyc) ? iy - 1 : iy - 1 - m_vnyp;
03963                                                 int cz = (iz<=m_vnzc) ? iz - 1 : iz - 1 - m_vnzp;
03964                                                 float sum = 0.0;
03965                                                 for( int ii = -kc; ii <= kc; ++ii ) {
03966                                                         int nbrcx = cx + ii;
03967                                                         if( nbrcx >= m_vnxc ) continue;
03968                                                         for ( int jj= -kc; jj <= kc; ++jj ) {
03969                                                                 int nbrcy = cy + jj;
03970                                                                 if( nbrcy <= -m_vnyc || nbrcy >= m_vnyc ) continue;
03971                                                                 for( int kk = -kc; kk <= kc; ++kk ) {
03972                                                                         int nbrcz = cz + jj;
03973                                                                         if ( nbrcz <= -m_vnyc || nbrcz >= m_vnyc ) continue;
03974                                                                         if( nbrcx < 0 ) {
03975                                                                                 nbrcx = -nbrcx;
03976                                                                                 nbrcy = -nbrcy;
03977                                                                                 nbrcz = -nbrcz;
03978                                                                         }
03979                                                                         int nbrix = nbrcx;
03980                                                                         int nbriy = nbrcy >= 0 ? nbrcy + 1 : nbrcy + 1 + m_vnyp;
03981                                                                         int nbriz = nbrcz >= 0 ? nbrcz + 1 : nbrcz + 1 + m_vnzp;
03982                                                                         if( (*m_wptr)( nbrix, nbriy, nbriz ) == 0 ) {
03983                                                                                 int c = 3*kc+1 - std::abs(ii) - std::abs(jj) - std::abs(kk);
03984                                                                                 sum = sum + pow_a[c];
03985                                                                         }
03986                                                                 }
03987                                                         }
03988                                                 }
03989 //                                              int r = std::abs(cx) + std::abs(cy) + std::abs(cz);
03990                                                 wght = 1.0f / ( 1.0f - alpha * sum );
03991                                         } // end of ( m_weighting == ESTIMATE )
03992                                         float nominator   = std::norm(m_volume->cmplx(ix,iy,iz))/(*m_wptr)(ix,iy,iz);
03993                                         float denominator = ((*m_wptr2)(ix,iy,iz)-std::norm(m_volume->cmplx(ix,iy,iz))/(*m_wptr)(ix,iy,iz))/(Kn-1.0f);
03994                                         // Skip Friedel related values
03995                                         if( (ix>0 || (kz>=0 && (ky>=0 || kz!=0)))) {
03996                                                 if ( r <= inc ) {
03997                                                         nom[r]   += nominator*wght;
03998                                                         denom[r] += denominator/(*m_wptr)(ix,iy,iz)*wght;
03999                                                         nn[r]    += 2;
04000                                                         ka[r]    += int(Kn);
04001                                                 }
04002 /*
04003 #ifdef  _WIN32
04004                                                 float  tmp = _cpp_max(nominator/denominator/(*m_wptr)(ix,iy,iz)-1.0f,0.0f);
04005 #else
04006                                                 float  tmp = std::max(nominator/denominator/(*m_wptr)(ix,iy,iz)-1.0f,0.0f);
04007 #endif  //_WIN32
04008                                                 //  Create SSNR as a 3D array (-n/2:n/2+n%2-1)
04009                                                 int iix = m_vnxc + ix; int iiy = m_vnyc + ky; int iiz = m_vnzc + kz;
04010                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
04011                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
04012                                                 // Friedel part
04013                                                 iix = m_vnxc - ix; iiy = m_vnyc - ky; iiz = m_vnzc - kz;
04014                                                 if( iix >= 0 && iix < m_vnxp && iiy >= 0 && iiy < m_vnyp && iiz >= 0 && iiz < m_vnzp )
04015                                                         (*vol_ssnr)(iix, iiy, iiz) = tmp;
04016 */
04017                                         }
04018                                         (*vol_ssnr)(2*ix, iy-1, iz-1) = denominator*wght;
04019                                 } // end of Kn>4.5 or whatever
04020                         }
04021                 }
04022         }
04023         for (int i = 0; i <= inc; i++) {
04024                 (*SSNR)(i,0,0) = nom[i];
04025                 (*SSNR)(i,1,0) = denom[i];
04026                 (*SSNR)(i,2,0) = static_cast<float>(nn[i]);
04027                 (*SSNR)(i,3,0) = static_cast<float>(ka[i]);
04028         }
04029         vol_ssnr->update();
04030         return vol_ssnr;
04031 //      }
04032 }
04033 #undef  tw
04034 // -----------------------------------------------------------------------------------
04035 // End of this addition
04036 
04037 
04038 void EMAN::dump_reconstructors()
04039 {
04040         dump_factory < Reconstructor > ();
04041 }
04042 
04043 map<string, vector<string> > EMAN::dump_reconstructors_list()
04044 {
04045         return dump_factory_list < Reconstructor > ();
04046 }
04047 
04048 
04049 
04050 
04051 
04052 using std::ofstream;
04053 using std::ifstream;
04054 
04055 
04056 newfile_store::newfile_store( const string& filename, int npad, bool ctf )
04057     : m_bin_file( filename + ".bin" ),
04058       m_txt_file( filename + ".txt" )
04059 {
04060         m_npad = npad;
04061         m_ctf = ctf;
04062 }
04063 
04064 newfile_store::~newfile_store( )
04065 {
04066 }
04067 
04068 void newfile_store::add_image( EMData* emdata, const Transform& tf )
04069 {
04070         if( m_bin_of == NULL ) {
04071             m_bin_of = shared_ptr<ofstream>( new ofstream(m_bin_file.c_str(), std::ios::out|std::ios::binary) );
04072             m_txt_of = shared_ptr<ofstream>( new ofstream(m_txt_file.c_str()) );
04073         }
04074 
04075 
04076         EMData* padfft = padfft_slice( emdata, tf, m_npad );
04077 
04078         int nx = padfft->get_xsize();
04079         int ny = padfft->get_ysize();
04080         int n2 = ny / 2;
04081         int n = ny;
04082 
04083         float voltage=0.0f, pixel=0.0f, Cs=0.0f, ampcont=0.0f, bfactor=0.0f, defocus=0.0f;
04084 
04085         if( m_ctf ) {
04086                 Ctf* ctf = emdata->get_attr( "ctf" );
04087                 Dict params = ctf->to_dict();
04088                 voltage = params["voltage"];
04089                 pixel   = params["apix"];
04090                 Cs      = params["cs"];
04091                 ampcont = params["ampcont"];
04092                 bfactor = params["bfactor"];
04093                 defocus = params["defocus"];
04094                 if(ctf) {delete ctf; ctf=0;}
04095         }
04096 
04097         vector<point_t> points;
04098         for( int j=-ny/2+1; j <= ny/2; j++ ) {
04099                 int jp = (j>=0) ? j+1 : ny+j+1;
04100                 for( int i=0; i <= n2; ++i ) {
04101                         int r2 = i*i + j*j;
04102                         if( (r2<ny*ny/4) && !( (i==0) && (j<0) ) ) {
04103                                 float ctf;
04104                                 if( m_ctf ) {
04105                                         float ak = std::sqrt( r2/float(ny*ny) )/pixel;
04106                                         ctf = Util::tf( defocus, ak, voltage, Cs, ampcont, bfactor, 1);
04107                                 } else {
04108                                         ctf = 1.0;
04109                                 }
04110 
04111                                 float xnew = i*tf[0][0] + j*tf[1][0];
04112                                 float ynew = i*tf[0][1] + j*tf[1][1];
04113                                 float znew = i*tf[0][2] + j*tf[1][2];
04114                                 std::complex<float> btq;
04115                                 if (xnew < 0.) {
04116                                         xnew = -xnew;
04117                                         ynew = -ynew;
04118                                         znew = -znew;
04119                                         btq = conj(padfft->cmplx(i,jp-1));
04120                                 } else {
04121                                         btq = padfft->cmplx(i,jp-1);
04122                                 }
04123 
04124                                 int ixn = int(xnew + 0.5 + n) - n;
04125                                 int iyn = int(ynew + 0.5 + n) - n;
04126                                 int izn = int(znew + 0.5 + n) - n;
04127                                 if ((ixn <= n2) && (iyn >= -n2) && (iyn <= n2) && (izn >= -n2) && (izn <= n2)) {
04128                                         int ixf, iyf, izf;
04129                                         if (ixn >= 0) {
04130                                                 int iza, iya;
04131                                                 if (izn >= 0)
04132                                                     iza = izn + 1;
04133                                                 else
04134                                                     iza = n + izn + 1;
04135 
04136                                                 if (iyn >= 0)
04137                                                     iya = iyn + 1;
04138                                                 else
04139                                                     iya = n + iyn + 1;
04140 
04141                                                 ixf = ixn;
04142                                                 iyf = iya;
04143                                                 izf = iza;
04144                                         } else {
04145                                                 int izt, iyt;
04146                                                 if (izn > 0)
04147                                                     izt = n - izn + 1;
04148                                                 else
04149                                                     izt = -izn + 1;
04150 
04151                                                 if (iyn > 0)
04152                                                     iyt = n - iyn + 1;
04153                                                 else
04154                                                     iyt = -iyn + 1;
04155 
04156                                                 ixf = -ixn;
04157                                                 iyf = iyt;
04158                                                 izf = izt;
04159                                         }
04160 
04161 
04162                                         int pos2 = ixf + (iyf-1)*nx/2 + (izf-1)*ny*nx/2;
04163                                         float ctfv1 = btq.real() * ctf;
04164                                         float ctfv2 = btq.imag() * ctf;
04165                                         float ctf2 = ctf*ctf;
04166 
04167                                         point_t p;
04168                                         p.pos2 = pos2;
04169                                         p.real = ctfv1;
04170                                         p.imag = ctfv2;
04171                                         p.ctf2 = ctf2;
04172 
04173                                         points.push_back( p );
04174                                 }
04175                         }
04176                 }
04177         }
04178 
04179 
04180         int npoint = points.size();
04181         std::istream::off_type offset = (m_offsets.size()==0) ? 0 : m_offsets.back();
04182         offset += npoint*sizeof(point_t);
04183         m_offsets.push_back( offset );
04184 
04185         *m_txt_of << m_offsets.back() << std::endl;
04186         m_bin_of->write( (char*)(&points[0]), sizeof(point_t)*npoint );
04187         checked_delete( padfft );
04188 }
04189 
04190 void newfile_store::get_image( int id, EMData* buf )
04191 {
04192         if( m_offsets.size()==0 ) {
04193                 ifstream is( m_txt_file.c_str() );
04194                 std::istream::off_type off;
04195                 while( is >> off ) {
04196                     m_offsets.push_back( off );
04197                 }
04198 
04199                 m_bin_if = shared_ptr<std::ifstream>( new ifstream(m_bin_file.c_str(), std::ios::in|std::ios::binary) );
04200         }
04201 
04202         Assert( m_bin_if != NULL );
04203 
04204         std::istream::off_type offset = (id==0) ? 0 : m_offsets[id-1];
04205         Assert( offset >= 0 );
04206         m_bin_if->seekg( offset, std::ios::beg );
04207 
04208 
04209         if( m_bin_if->bad() || m_bin_if->fail() || m_bin_if->eof() ) {
04210                 std::cout << "bad or fail or eof while fetching id, offset: " << id << " " << offset << std::endl;
04211                 throw std::logic_error( "bad happen" );
04212         }
04213 
04214         int bufsize = (m_offsets[id] - offset)/sizeof(float);
04215         if( buf->get_xsize() != bufsize ) {
04216                 buf->set_size( bufsize, 1, 1 );
04217         }
04218 
04219         char* data = (char*)(buf->get_data());
04220         m_bin_if->read( data, sizeof(float)*bufsize );
04221         buf->update();
04222 }
04223 
04224 void newfile_store::read( int nprj )
04225 {
04226         if( m_offsets.size()==0 ) {
04227             ifstream is( m_txt_file.c_str() );
04228             std::istream::off_type off;
04229             while( is >> off ) {
04230                 m_offsets.push_back( off );
04231             }
04232         }
04233 
04234         if( m_bin_if==NULL ) {
04235             m_bin_if = shared_ptr< ifstream>( new ifstream(m_bin_file.c_str(), std::ios::in|std::ios::binary) );
04236         }
04237 
04238 
04239         int npoint = m_offsets[0]/sizeof(point_t);
04240         std::ios::off_type prjsize = m_offsets[0];
04241 
04242         try {
04243             m_points.resize(nprj * npoint);
04244         }
04245         catch( std::exception& e ) {
04246             std::cout << "Error: " << e.what() << std::endl;
04247         }
04248 
04249         int ip = 0;
04250         for( int i=0; i < nprj; ++i ) {
04251                 m_bin_if->read( (char*)(&m_points[ip]), prjsize );
04252                 if( m_bin_if->bad() || m_bin_if->fail() || m_bin_if->eof() )  {
04253                         std::cout << "Error: file hander bad or fail or eof" << std::endl;
04254                         return;
04255                 }
04256                 ip += npoint;
04257         }
04258 }
04259 
04260 void newfile_store::add_tovol( EMData* fftvol, EMData* wgtvol, const vector<int>& mults, int pbegin, int pend )
04261 {
04262         float* vdata = fftvol->get_data();
04263         float* wdata = wgtvol->get_data();
04264 
04265         int npoint = m_offsets[0]/sizeof(point_t);
04266 //    Assert( int(mults.size())==nprj );
04267         Assert( int(m_points.size())== (pend - pbegin)*npoint );
04268 
04269         for( int iprj=pbegin; iprj < pend; ++iprj ) {
04270                 int m = mults[iprj];
04271                 if( m==0 ) continue;
04272 
04273                 int ipt = (iprj-pbegin)*npoint;
04274                 for( int i=0; i < npoint; ++i )  {
04275                     int pos2 = m_points[ipt].pos2;
04276                     int pos1 = pos2*2;
04277 
04278                     wdata[pos2]   += m_points[ipt].ctf2*m;
04279                     vdata[pos1]   += m_points[ipt].real*m;
04280                     vdata[pos1+1] += m_points[ipt].imag*m;
04281                     ++ipt;
04282                 }
04283         }
04284 }
04285 
04286 void newfile_store::restart()
04287 {
04288     m_bin_if = shared_ptr< ifstream>( new ifstream(m_bin_file.c_str(), std::ios::in|std::ios::binary) );
04289 }
04290 
04291 file_store::file_store(const string& filename, int npad, int write, bool ctf)
04292     : m_bin_file(filename + ".bin"),
04293       m_txt_file(filename + ".txt")
04294 {
04295     m_ctf = ctf;
04296     m_prev = -1;
04297     m_npad = npad;
04298     m_write = write;
04299 }
04300 
04301 file_store::~file_store()
04302 {
04303 }
04304 
04305 void file_store::add_image( EMData* emdata, const Transform& tf )
04306 {
04307 
04308     EMData* padfft = padfft_slice( emdata, tf, m_npad );
04309 
04310     float* data = padfft->get_data();
04311 
04312     if( m_write && m_bin_ohandle == NULL )
04313     {
04314         m_bin_ohandle = shared_ptr< ofstream >( new ofstream(m_bin_file.c_str(), std::ios::out | std::ios::binary) );
04315         m_txt_ohandle = shared_ptr< ofstream >( new ofstream(m_txt_file.c_str() ) );
04316         if( m_ctf )
04317                  *m_txt_ohandle << "Cs pixel voltage ctf_applied amp_contrast defocus ";
04318 
04319         *m_txt_ohandle << "phi theta psi" << std::endl;
04320     }
04321 
04322     m_x_out = padfft->get_xsize();
04323     m_y_out = padfft->get_ysize();
04324     m_z_out = padfft->get_zsize();
04325     m_totsize = m_x_out*m_y_out*m_z_out;
04326 
04327     if( m_ctf )
04328     {
04329         Ctf* ctf = padfft->get_attr( "ctf" );
04330         Dict ctf_params = ctf->to_dict();
04331 
04332         m_ctf_applied = padfft->get_attr( "ctf_applied" );
04333 
04334         m_Cs = ctf_params["cs"];
04335         m_pixel = ctf_params["apix"];
04336         m_voltage = ctf_params["voltage"];
04337         m_amp_contrast = ctf_params["ampcont"];
04338         m_defocuses.push_back( ctf_params["defocus"] );
04339         if(ctf) {delete ctf; ctf=0;}
04340     }
04341 
04342     Dict params = tf.get_rotation( "spider" );
04343     float phi = params.get( "phi" );
04344     float tht = params.get( "theta" );
04345     float psi = params.get( "psi" );
04346 
04347 
04348     m_phis.push_back( phi );
04349     m_thetas.push_back( tht );
04350     m_psis.push_back( psi );
04351 
04352     if( m_write )
04353     {
04354         m_bin_ohandle->write( (char*)data, sizeof(float)*m_totsize );
04355 
04356         if( m_ctf )
04357         {
04358             *m_txt_ohandle << m_Cs << " ";
04359             *m_txt_ohandle << m_pixel << " ";
04360             *m_txt_ohandle << m_voltage << " ";
04361             *m_txt_ohandle << m_ctf_applied << " ";
04362             *m_txt_ohandle << m_amp_contrast << " ";
04363             *m_txt_ohandle << m_defocuses.back() << " ";
04364         }
04365         *m_txt_ohandle << m_phis.back() << " ";
04366         *m_txt_ohandle << m_thetas.back() << " ";
04367         *m_txt_ohandle << m_psis.back() << " ";
04368         *m_txt_ohandle << m_x_out << " ";
04369         *m_txt_ohandle << m_y_out << " ";
04370         *m_txt_ohandle << m_z_out << " ";
04371         *m_txt_ohandle << m_totsize << std::endl;
04372     }
04373 
04374     checked_delete(padfft);
04375 
04376 }
04377 
04378 void file_store::get_image( int id, EMData* padfft )
04379 {
04380 
04381     if( m_phis.size() == 0 ) {
04382         ifstream m_txt_ifs( m_txt_file.c_str() );
04383 
04384         if( !m_txt_ifs )
04385         {
04386             std::cerr << "Error: file " << m_txt_file << " does not exist" << std::endl;
04387         }
04388 
04389         string line;
04390         std::getline( m_txt_ifs, line );
04391 
04392         float first, defocus, phi, theta, psi;
04393 
04394 
04395 
04396         while( m_txt_ifs >> first ) {
04397 
04398             if( m_ctf )
04399             {
04400                 m_Cs = first;
04401                 m_txt_ifs >> m_pixel >> m_voltage;
04402                 m_txt_ifs >> m_ctf_applied >> m_amp_contrast;
04403                 m_txt_ifs >> defocus >> phi >> theta >> psi;
04404                 m_defocuses.push_back( defocus );
04405             }
04406             else
04407             {
04408                 phi = first;
04409                 m_txt_ifs >> theta >> psi;
04410             }
04411 
04412             m_txt_ifs >> m_x_out >> m_y_out >> m_z_out >> m_totsize;
04413             m_phis.push_back( phi );
04414             m_thetas.push_back( theta );
04415             m_psis.push_back( psi );
04416         }
04417     }
04418 
04419     Assert( m_ihandle != NULL );
04420 
04421     std::istream::off_type offset = id*sizeof(float)*m_totsize;
04422     Assert( offset >= 0 );
04423 
04424     if( offset > 0 )
04425     {
04426         m_ihandle->seekg(offset, std::ios::beg);
04427     }
04428 
04429     if( m_ihandle->bad() )
04430     {
04431         std::cout << "bad while fetching id, offset: " << id << " " << offset << std::endl;
04432         throw std::logic_error( "bad happen" );
04433     }
04434 
04435     if( m_ihandle->fail() )
04436     {
04437         std::cout << "fail while fetching id, offset, curoff: " << id << " " << offset << std::endl;
04438         throw std::logic_error( "fail happen" );
04439     }
04440 
04441     if( m_ihandle->eof() )
04442     {
04443         std::cout << "eof while fetching id, offset: " << id << " " << offset << std::endl;
04444         throw std::logic_error( "eof happen" );
04445     }
04446 
04447     if( padfft->get_xsize() != m_x_out ||
04448         padfft->get_ysize() != m_y_out ||
04449         padfft->get_zsize() != m_z_out )
04450     {
04451         padfft->set_size(m_x_out, m_y_out, m_z_out);
04452     }
04453 
04454     char* data = (char*)(padfft->get_data());
04455     m_ihandle->read( data, sizeof(float)*m_totsize );
04456     padfft->update();
04457 
04458     if( m_ctf )
04459     {
04460         padfft->set_attr( "Cs", m_Cs );
04461         padfft->set_attr( "Pixel_size", m_pixel );
04462         padfft->set_attr( "voltage", m_voltage );
04463         padfft->set_attr( "ctf_applied", m_ctf_applied );
04464         padfft->set_attr( "amp_contrast", m_amp_contrast );
04465         padfft->set_attr( "defocus", m_defocuses[id] );
04466     }
04467 
04468     padfft->set_attr( "padffted", 1 );
04469     padfft->set_attr( "phi", m_phis[id] );
04470     padfft->set_attr( "theta", m_thetas[id] );
04471     padfft->set_attr( "psi", m_psis[id] );
04472 
04473 }
04474 
04475 void file_store::restart( )
04476 {
04477     if( m_ihandle == NULL )
04478     {
04479         m_ihandle = shared_ptr< ifstream >( new ifstream(m_bin_file.c_str(), std::ios::in | std::ios::binary) );
04480     }
04481 
04482     if( m_ihandle->bad() || m_ihandle->fail() || m_ihandle->eof() )
04483     {
04484         m_ihandle->open( m_bin_file.c_str(), std::ios::binary );
04485     }
04486 
04487     m_ihandle->seekg( 0, std::ios::beg );
04488 }
04489 
04490 /* vim: set ts=4 noet: */

Generated on Thu Dec 9 13:45:50 2010 for EMAN2 by  doxygen 1.3.9.1