EMAN2
Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | Protected Attributes | Private Member Functions | List of all members
EMAN::FourierReconstructor Class Reference

Fourier space 3D reconstruction The Fourier reconstructor is designed to work in an iterative fashion, where similarity ("quality") metrics are used to determine if a slice should be inserted into the 3D in each subsequent iteration. More...

#include <reconstructor.h>

Inheritance diagram for EMAN::FourierReconstructor:
Inheritance graph
[legend]
Collaboration diagram for EMAN::FourierReconstructor:
Collaboration graph
[legend]

Public Member Functions

 FourierReconstructor ()
 Default constructor calls load_default_settings() More...
 
virtual ~FourierReconstructor ()
 Deconstructor calls free_memory() More...
 
virtual void setup ()
 Setup the Fourier reconstructor. More...
 
virtual void setup_seed (EMData *seed, float seed_weight)
 Initialize the reconstructor with a seed volume. More...
 
virtual void setup_seedandweights (EMData *seed, EMData *weight)
 Initialize the reconstructor with a seed volume, as above. More...
 
virtual EMDatapreprocess_slice (const EMData *const slice, const Transform &t=Transform())
 Preprocess the slice prior to insertion into the 3D volume this Fourier tranforms the slice and make sure all the pixels are in the right position it always returns a copy of the provided slice, so it should be deleted by someone eventually. More...
 
virtual int insert_slice (const EMData *const slice, const Transform &euler, const float weight)
 Insert a slice into a 3D volume, in a given orientation. More...
 
virtual EMDataprojection (const Transform &euler, int ret_fourier)
 Generates a projection by extracting a slice in Fourier space. More...
 
virtual int determine_slice_agreement (EMData *slice, const Transform &euler, const float weight=1.0, bool sub=true)
 Compares a slice to the current reconstruction volume and computes a normalization factor and quality. More...
 
virtual EMDatafinish (bool doift=true)
 Get the reconstructed volume Normally will return the volume in real-space with the requested size. More...
 
virtual void clear ()
 clear the volume and tmp_data for use in Monte Carlo reconstructions More...
 
virtual string get_name () const
 Get the unique name of the reconstructor. More...
 
virtual string get_desc () const
 Get the one line description of the reconstructor. More...
 
virtual TypeDict get_param_types () const
 Get the parameter types of this object. More...
 
- Public Member Functions inherited from EMAN::Reconstructor
 Reconstructor ()
 
virtual ~Reconstructor ()
 
int insert_slice (const EMData *const slice, const Transform &euler)
 
void print_params () const
 Print the current parameters to std::out. More...
 
EMObjectoperator[] (const string &key)
 
- Public Member Functions inherited from EMAN::FactoryBase
 FactoryBase ()
 
virtual ~FactoryBase ()
 
Dict get_params () const
 get a copy of the parameters of this class More...
 
void set_params (const Dict &new_params)
 Set new parameters. More...
 
void set_param (const string key, const EMObject val)
 
void insert_params (const Dict &new_params)
 Insert parameters. More...
 
Dict copy_relevant_params (const FactoryBase *const that) const
 
- Public Member Functions inherited from EMAN::ReconstructorVolumeData
 ReconstructorVolumeData ()
 Only constructor All member variables are zeroed. More...
 
virtual ~ReconstructorVolumeData ()
 Destructor safely frees memory. More...
 
const EMDataget_emdata ()
 Get the main image pointer, probably redundant (not used) More...
 

Static Public Member Functions

static ReconstructorNEW ()
 Factory incorporation uses the pointer of this function. More...
 

Static Public Attributes

static const string NAME = "fourier"
 

Protected Member Functions

virtual void load_default_settings ()
 Load default settings. More...
 
virtual void free_memory ()
 Frees the memory owned by this object (but not parent objects) Deletes the FourierPixelInserter3D pointer. More...
 
virtual void load_inserter ()
 Load the pixel inserter based on the information in params. More...
 
virtual void do_insert_slice_work (const EMData *const input_slice, const Transform &euler, const float weight, const bool corners=false)
 A function to perform the nuts and bolts of inserting an image slice. More...
 
virtual void do_compare_slice_work (EMData *input_slice, const Transform &euler, float weight)
 A function to perform the nuts and bolts of comparing an image slice. More...
 
virtual bool pixel_at (const float &xx, const float &yy, const float &zz, float *dt)
 This is a mode-2 pixel extractor. More...
 
- Protected Member Functions inherited from EMAN::ReconstructorVolumeData
void free_memory ()
 Free allocated memorys The inherited class may have allocated image of tmp_data In either case you can safely call this function to delete either of those pointers, even if they bdb:refine_03::threed_00are NULL. More...
 
virtual void normalize_threed (const bool sqrt_damp=false, const bool wiener=false)
 Normalize on the assumption that image is a Fourier volume and that tmp_data is a volume of weights corresponding in size to this Fourier volume. More...
 
virtual void zero_memory ()
 Sends the pixels in tmp_data and image to zero Convenience only. More...
 

Protected Attributes

FourierPixelInserter3Dinserter
 A pixel inserter pointer which inserts pixels into the 3D volume using one of a variety of insertion methods. More...
 
- Protected Attributes inherited from EMAN::FactoryBase
Dict params
 This is the dictionary the stores the parameters of the object. More...
 
- Protected Attributes inherited from EMAN::ReconstructorVolumeData
EMDataimage
 Inheriting class allocates this, probably in setup(). More...
 
EMDatatmp_data
 Inheriting class may allocate this, probably in setup() More...
 
int nx
 
int nx2
 
int ny
 
int ny2
 
int nz
 
int nz2
 
int subnx
 
int subny
 
int subnz
 
int subx0
 
int suby0
 
int subz0
 

Private Member Functions

 FourierReconstructor (const FourierReconstructor &that)
 Disallow copy construction. More...
 
FourierReconstructoroperator= (const FourierReconstructor &)
 Disallow assignment. More...
 

Detailed Description

Fourier space 3D reconstruction The Fourier reconstructor is designed to work in an iterative fashion, where similarity ("quality") metrics are used to determine if a slice should be inserted into the 3D in each subsequent iteration.

The client creates a Fourier reconstructor to insert real images into a 3D volume. The return image is a real space image

This reconstructor is based on EMAN1's Fourier reconstructor with a handful of modifications including

  1. - Fourier ring correlation (FRC) as opposed to the mean phase residual is used to estimate slice quality. The FRC of the slice in the 3D volume is determined - but the slice is removed from the 3D volume before doing this so the score reflects the extent to which the slice agrees with the contribution of the other slices in the 3D volume. The FRC is converted to SNR using the relationship described by Penczek ( Three-dimensional spectral signal to noise ratio for a class of reconstruction algorithms, JSB 2002 138 (24-46) ) FRC = S/(sqrt(S+N1)sqrt(S+N2)) Where N1 is the noise in the slice of the 3D volume and N2 is the noise in the image slice being inserted. We make the assumption that the noise in the 3D volume is 0 (N1=0) to get FRC^2 = SNR/(1+SNR) which gives a spectral SNR plot - we then divide each SNR value by the number of particles in the class average (seeing as SNR should scale linearly with the number of particles) to get the estimated SNR per contributing particle in this class average. If the particles that have been averaged are not homogenous this score should be low etc. The scaled SNR curve is then converted back to a FRC curve and integrated. This integral is the similarity metric, and depends on how far information extends to in Fourier space - typical values range from 0.05 to 0.2, but can vary substantially depending on the data.

2 - Uses half of the memory used by EMAN1's equivalent reconstruction algorithm

r->setup();
for k in 0:num_iterations-1
// First do a round of slice quality (metric) determination - only possible if a 3D volume has
// already been generated (k>0)
if ( k > 0 )
// Determine the agreement of the slices with the previous reconstructed volume (in memory)
for i in 0:num_slices-1
r->determine_slice_agreement(image[i], image[i].euler_orientation);
// Insert the slices into the 3D volume
// Will decide not to insert the slice if the its "quality" is not good enough
for i in 0:num_slices-1
int failure = r->insert_slice(image[i], image[i].euler_orientation);
if ( failure ) cout << "Slice was not inserted due to poor quality" << endl;
// Get the resulting volume
EMData* result = r->finish();
result->write_image("threed.mrc");
Dict params
This is the dictionary the stores the parameters of the object.
Definition: emobject.h:953
static T * get(const string &instance_name)
Definition: emobject.h:781
EMData * image
Inheriting class allocates this, probably in setup().

Definition at line 388 of file reconstructor.h.

Constructor & Destructor Documentation

◆ FourierReconstructor() [1/2]

EMAN::FourierReconstructor::FourierReconstructor ( )
inline

Default constructor calls load_default_settings()

Definition at line 394 of file reconstructor.h.

virtual void load_default_settings()
Load default settings.

References load_default_settings().

Referenced by NEW().

◆ ~FourierReconstructor()

virtual EMAN::FourierReconstructor::~FourierReconstructor ( )
inlinevirtual

Deconstructor calls free_memory()

Definition at line 399 of file reconstructor.h.

399{ free_memory(); }
virtual void free_memory()
Frees the memory owned by this object (but not parent objects) Deletes the FourierPixelInserter3D poi...

References free_memory().

◆ FourierReconstructor() [2/2]

EMAN::FourierReconstructor::FourierReconstructor ( const FourierReconstructor that)
private

Disallow copy construction.

Member Function Documentation

◆ clear()

void FourierReconstructor::clear ( )
virtual

clear the volume and tmp_data for use in Monte Carlo reconstructions

Reimplemented from EMAN::Reconstructor.

Definition at line 999 of file reconstructor.cpp.

1000{
1001 bool zeroimage = true;
1002 bool zerotmpimg = true;
1003
1004#ifdef EMAN2_USING_CUDA
1005 if(EMData::usecuda == 1) {
1006 if(image->getcudarwdata()) {
1007 to_zero_cuda(image->getcudarwdata(),image->get_xsize(),image->get_ysize(),image->get_zsize());
1008 zeroimage = false;
1009 }
1010 if(tmp_data->getcudarwdata()) {
1011 //to_zero_cuda(tmp_data->getcudarwdata(),image->get_xsize(),image->get_ysize(),image->get_zsize());
1012 zerotmpimg = false;
1013 }
1014 }
1015#endif
1016
1017 if(zeroimage) image->to_zero();
1018 if(zerotmpimg) tmp_data->to_zero();
1019
1020}
EMData * tmp_data
Inheriting class may allocate this, probably in setup()
void to_zero_cuda(float *data, const int nx, const int ny, const int nz)

References EMAN::ReconstructorVolumeData::image, EMAN::ReconstructorVolumeData::tmp_data, and to_zero_cuda().

◆ determine_slice_agreement()

int FourierReconstructor::determine_slice_agreement ( EMData slice,
const Transform euler,
const float  weight = 1.0,
bool  sub = true 
)
virtual

Compares a slice to the current reconstruction volume and computes a normalization factor and quality.

Normalization and quality are returned via attributes set in the passed slice. You may freely mix calls to determine_slice_agreement with calls to insert_slice, but note that determine_slice_agreement can only use information from slices that have already been inserted. Attributes set in the slice are: reconstruct_norm the relative normalization factor which should be applied before inserting the slice reconstruct_qual a scaled quality factor (larger better) for this slice as compared to the existing reconstruction reconstruct_absqual the absolute (not scaled based on weight) quality factor comparing this slice to the existing reconstruction reconstruct_weight the summed weights from all voxels intersecting with the inserted slice, larger -> more overlap with other slices

Parameters
input_sliceThe EMData slice to be compared
eulerThe orientation of the slice as a Transform object
weightA weighting factor for this slice, generally the number of particles in a class-average. May be ignored by some reconstructors
subFlag indicating whether to subtract the slice from the volume before comparing. May be ignored by some reconstructors
Returns
0 if OK. 1 if error.
Exceptions
NullPointerExceptionif the input EMData pointer is null
ImageFormatExceptionif the image is complex as opposed to real

Reimplemented from EMAN::Reconstructor.

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 1212 of file reconstructor.cpp.

1213{
1214 // Are these exceptions really necessary? (d.woolford)
1215 if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
1216
1217#ifdef EMAN2_USING_CUDA
1218 if(EMData::usecuda == 1) {
1219 if(!input_slice->getcudarwdata()) input_slice->copy_to_cuda(); //copy slice to cuda using the const version
1220 }
1221#endif
1222
1223 Transform * rotation;
1224 rotation = new Transform(arg); // assignment operator
1225
1226 EMData *slice;
1227 if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
1228 else slice = preprocess_slice( input_slice, *rotation);
1229
1230
1231 // We must use only the rotational component of the transform, scaling, translation and mirroring
1232 // are not implemented in Fourier space, but are in preprocess_slice
1233 rotation->set_scale(1.0);
1234 rotation->set_mirror(false);
1235 rotation->set_trans(0,0,0);
1236 if (sub) do_insert_slice_work(slice, *rotation, -weight);
1237 // Remove the current slice first (not threadsafe, but otherwise performance would be awful)
1238
1239 // Compare
1240 do_compare_slice_work(slice, *rotation,weight);
1241
1242 input_slice->set_attr("reconstruct_norm",slice->get_attr("reconstruct_norm"));
1243 input_slice->set_attr("reconstruct_absqual",slice->get_attr("reconstruct_absqual"));
1244 input_slice->set_attr("reconstruct_absqual_lowres",slice->get_attr("reconstruct_absqual_lowres"));
1245// input_slice->set_attr("reconstruct_qual",slice->get_attr("reconstruct_qual"));
1246 input_slice->set_attr("reconstruct_weight",slice->get_attr("reconstruct_weight"));
1247
1248 // Now put the slice back
1249 if (sub) do_insert_slice_work(slice, *rotation, weight);
1250
1251 delete rotation;
1252 delete slice;
1253
1254// image->update();
1255 return 0;
1256
1257}
EMData stores an image's data and defines core image processing routines.
Definition: emdata.h:82
virtual void do_insert_slice_work(const EMData *const input_slice, const Transform &euler, const float weight, const bool corners=false)
A function to perform the nuts and bolts of inserting an image slice.
virtual void do_compare_slice_work(EMData *input_slice, const Transform &euler, float weight)
A function to perform the nuts and bolts of comparing an image slice.
virtual EMData * preprocess_slice(const EMData *const slice, const Transform &t=Transform())
Preprocess the slice prior to insertion into the 3D volume this Fourier tranforms the slice and make ...
A Transform object is a somewhat specialized object designed specifically for EMAN2/Sparx storage of ...
Definition: transform.h:75
void set_mirror(const bool x_mirror)
Set whether or not x_mirroring is occurring.
Definition: transform.cpp:1238
void set_scale(const float &scale)
Set the scale.
Definition: transform.cpp:1123
void set_trans(const float &x, const float &y, const float &z=0)
Set the post translation component.
Definition: transform.cpp:1036
void sub(float f)
subtract a float number to each pixel value of the image.
#define NullPointerException(desc)
Definition: exception.h:241

References do_compare_slice_work(), do_insert_slice_work(), NullPointerException, preprocess_slice(), EMAN::Transform::set_mirror(), EMAN::Transform::set_scale(), EMAN::Transform::set_trans(), and sub().

◆ do_compare_slice_work()

void FourierReconstructor::do_compare_slice_work ( EMData input_slice,
const Transform euler,
float  weight 
)
protectedvirtual

A function to perform the nuts and bolts of comparing an image slice.

Parameters
input_slicethe slice to insert into the 3D volume
eulera transform storing the slice euler angle

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 1259 of file reconstructor.cpp.

1260{
1261
1262 float dt[3]; // This stores the complex and weight from the volume
1263 float dt2[2]; // This stores the local image complex
1264 float *dat = input_slice->get_data();
1265 vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
1266
1267 float inx=(float)(input_slice->get_xsize()); // x/y dimensions of the input image
1268 float iny=(float)(input_slice->get_ysize());
1269 float apix=input_slice->get_attr("apix_x");
1270 float rmax=iny*apix/12.0; // radius at 12 A, use as cutoff for low res insertion quality
1271 if (rmax>iny/2.0-1.0) rmax=iny/2.0-1.0; // in case of large A/pix
1272 if (rmax<5.0) rmax=5.0; // can't imagine this will happen
1273
1274 double dotlow=0; // low resolution dot product
1275 double dlpow=0;
1276 double dlpow2=0;
1277
1278 double dot=0; // summed pixel*weight dot product
1279 double vweight=0; // sum of weights
1280 double power=0; // sum of inten*weight from volume
1281 double power2=0; // sum of inten*weight from image
1282// double amp=0,amp2=0; // used for normalization, weighted amplitude averages under specific conditions
1283 bool use_cpu = true;
1284
1285 int nval=0;
1286
1287#ifdef EMAN2_USING_CUDA
1288 if(EMData::usecuda == 1) {
1289 if(!input_slice->getcudarwdata()) input_slice->copy_to_cuda();
1290 if(!image->getcudarwdata()){
1291 image->copy_to_cuda();
1292 tmp_data->copy_to_cuda();
1293 }
1294 for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
1295 Transform t3d = arg*(*it);
1296 float * m = new float[12];
1298 float4 stats = determine_slice_agreement_cuda(m,input_slice->getcudarwdata(),image->getcudarwdata(),tmp_data->getcudarwdata(),inx,iny,image->get_xsize(),image->get_ysize(),image->get_zsize(), weight);
1299 dot = stats.x;
1300 vweight = stats.y;
1301 power = stats.z;
1302 power2 = stats.w;
1303 //cout << "CUDA stats " << stats.x << " " << stats.y << " " << stats.z << " " << stats.w << endl;
1304 use_cpu = false;
1305 }
1306 }
1307#endif
1308 if(use_cpu) {
1309 for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
1310 Transform t3d = arg*(*it);
1311 for (int y = -iny/2; y < iny/2; y++) {
1312 for (int x = 0; x <= inx/2; x++) {
1313 if (x==0 && y==0) continue; // We don't want to use the Fourier origin
1314
1315 float rx = (float) x/(inx-2); // coords relative to Nyquist=.5
1316 float ry = (float) y/iny;
1317
1318// if ((rx * rx + Util::square(ry - max_input_dim "xform.projection"/ 2)) > rl)
1319// continue;
1320
1321 Vec3f coord(rx,ry,0);
1322 coord = coord*t3d; // transpose multiplication
1323 float xx = coord[0]; // transformed coordinates in terms of Nyquist
1324 float yy = coord[1];
1325 float zz = coord[2];
1326
1327
1328 if (fabs(xx)>0.5 || fabs(yy)>=0.5 || fabs(zz)>=0.5) continue;
1329
1330 // Map back to actual pixel coordinates in output volume
1331 xx=xx*(nx-2);
1332 yy=yy*ny;
1333 zz=zz*nz;
1334
1335
1336 int idx = (int)(x * 2 + inx*(y<0?iny+y:y));
1337 dt2[0] = dat[idx];
1338 dt2[1] = dat[idx+1];
1339
1340 // value returned indirectly in dt
1341 if (!pixel_at(xx,yy,zz,dt) || dt[2]==0) continue;
1342
1343// printf("%f\t%f\t%f\t%f\t%f\n",dt[0],dt[1],dt[2],dt2[0],dt2[1]);
1344 float r=(float)Util::hypot_fast(x,y);
1345 if (r>3 && r<rmax) {
1346 dotlow+=(dt[0]*dt2[0]+dt[1]*dt2[1])*dt[2];
1347 dlpow+=(dt[0]*dt[0]+dt[1]*dt[1])*dt[2];
1348 dlpow2+=(dt2[0]*dt2[0]+dt2[1]*dt2[1])*dt[2];
1349 }
1350
1351
1352// if (r<6) continue;
1353 vweight+=dt[2];
1354 dot+=(dt[0]*dt2[0]+dt[1]*dt2[1])*dt[2];
1355 power+=(dt[0]*dt[0]+dt[1]*dt[1])*dt[2];
1356 power2+=(dt2[0]*dt2[0]+dt2[1]*dt2[1])*dt[2];
1357// printf("%d\t%d\t%f\t%f\t%f\n",x,y,dt[0],dt[1],dt[2]);
1358// if (r>2 && dt[2]>=0.5) {
1359// amp+=hypot(dt[0]*dt[0],dt[1]*dt[1])*dt[2];
1360// amp2+=hypot(dt2[0]*dt2[0],dt2[1]*dt2[1])*dt[2];
1361// }
1362 nval++;
1363 }
1364 }
1365 //cout << dot << " " << vweight << " " << power << " " << power2 << endl;
1366 }
1367 }
1368
1369 dot/=sqrt(power*power2); // normalize the dot product
1370 if (dlpow*dlpow2>0) dotlow/=sqrt(dlpow*dlpow2);
1371// input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)/(inx*iny)));
1372 input_slice->set_attr("reconstruct_norm",(float)(power2<=0?1.0:sqrt(power/power2)));
1373// input_slice->set_attr("reconstruct_norm",(float)(amp2<=0?1.0:amp/amp2));
1374 input_slice->set_attr("reconstruct_absqual",(float)dot);
1375 input_slice->set_attr("reconstruct_absqual_lowres",(float)dotlow);
1376 float rw=weight<=0?1.0f:1.0f/weight;
1377 input_slice->set_attr("reconstruct_qual",(float)(dot*rw/((rw-1.0)*dot+1.0))); // here weight is a proxy for SNR
1378 input_slice->set_attr("reconstruct_weight",(float)(vweight/(float)(nval)));
1379// printf("** %g\t%g\t%g\t%g ##\n",dot,vweight,power,power2);
1380 //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)));
1381}
virtual bool pixel_at(const float &xx, const float &yy, const float &zz, float *dt)
This is a mode-2 pixel extractor.
static vector< Transform > get_symmetries(const string &symmetry)
Definition: symmetry.cpp:1240
void copy_matrix_into_array(float *const) const
Definition: transform.cpp:158
static float hypot_fast(int x, int y)
Euclidean distance in 2D for integers computed fast using a cached lookup table.
Definition: util.cpp:742
float4 determine_slice_agreement_cuda(const float *const matrix, const float *const slice_data, float *vol, float *tmp_data, const int inx, const int iny, const int nx, const int ny, const int nz, const float weight)
EMData * power(int n) const
return a image to the power of n
EMData * sqrt() const
return square root of current image
double dot(const Vector3 &w, const Vector3 &v)
Definition: vecmath.h:305
#define y(i, j)
Definition: projector.cpp:1516
#define x(i)
Definition: projector.cpp:1517

References EMAN::Transform::copy_matrix_into_array(), determine_slice_agreement_cuda(), EMAN::dot(), EMAN::Symmetry3D::get_symmetries(), EMAN::Util::hypot_fast(), EMAN::ReconstructorVolumeData::image, EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::nz, EMAN::FactoryBase::params, pixel_at(), power(), sqrt(), EMAN::ReconstructorVolumeData::tmp_data, x, and y.

Referenced by determine_slice_agreement().

◆ do_insert_slice_work()

void FourierReconstructor::do_insert_slice_work ( const EMData *const  input_slice,
const Transform euler,
const float  weight,
const bool  corners = false 
)
protectedvirtual

A function to perform the nuts and bolts of inserting an image slice.

Parameters
input_slicethe slice to insert into the 3D volume
eulera transform storing the slice euler angle
weightweighting factor for this slice (usually number of particles in a class-average)

Definition at line 1122 of file reconstructor.cpp.

1123{
1124 // Reload the inserter if the mode has changed
1125// string mode = (string) params["mode"];
1126// if ( mode != inserter->get_name() ) load_inserter();
1127
1128// int y_in = input_slice->get_ysize();
1129// int x_in = input_slice->get_xsize();
1130// // Adjust the dimensions to account for odd and even ffts
1131// if (input_slice->is_fftodd()) x_in -= 1;
1132// else x_in -= 2;
1133
1134 vector<Transform> syms = Symmetry3D::get_symmetries((string)params["sym"]);
1135
1136 float inx=(float)(input_slice->get_xsize()); // x/y dimensions of the input image
1137 float iny=(float)(input_slice->get_ysize());
1138
1139 if (abs(inx-iny)>2 && weight<0) printf("WARNING: Fourier Reconstruction failure. SSNR flag set with asymmetric dimensions on input image\n");
1140
1141#ifdef EMAN2_USING_CUDA
1142 if(EMData::usecuda == 1) {
1143 if(!image->getcudarwdata()){
1144 image->copy_to_cuda();
1145 tmp_data->copy_to_cuda();
1146 }
1147 float * m = new float[12];
1148 for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
1149 Transform t3d = arg*(*it);
1151 //cout << "using CUDA " << image->getcudarwdata() << endl;
1152 insert_slice_cuda(m,input_slice->getcudarwdata(),image->getcudarwdata(),tmp_data->getcudarwdata(),inx,iny,image->get_xsize(),image->get_ysize(),image->get_zsize(), weight);
1153 }
1154 delete m;
1155 return;
1156 }
1157#endif
1158 vector<float> ssnr;
1159 float sscale = 1.0f;
1160 if (weight<0) {
1161 ssnr=input_slice->get_attr("class_ssnr");
1162 sscale=2.0*(ssnr.size()-1)/iny;
1163 }
1164
1165 float rweight=weight;
1166 for ( vector<Transform>::const_iterator it = syms.begin(); it != syms.end(); ++it ) {
1167 Transform t3d = arg*(*it);
1168 for (int y = -iny/2; y < iny/2; y++) {
1169 for (int x = 0; x < inx/2; x++) {
1170
1171 float rx = (float) x/(inx-2.0f); // coords relative to Nyquist=.5
1172 float ry = (float) y/iny;
1173 if (corners) {
1174 if (weight<0) {
1175 int r=Util::hypot_fast_int(x,y);
1176 rweight=Util::get_max(0.0f,ssnr[int(r*sscale)]);
1177 }
1178 }
1179 else {
1180 int r=Util::hypot_fast_int(x,y);
1181 if (r>iny/2 && abs(inx-iny)<3) continue; // no filling in Fourier corners...
1182
1183 if (weight<0) rweight=Util::get_max(0.0f,ssnr[int(r*sscale)]);
1184 }
1185// printf("%d\t%f\n",int(r*sscale),rweight);
1186
1187 Vec3f coord(rx,ry,0);
1188 coord = coord*t3d; // transpose multiplication
1189 float xx = coord[0]; // transformed coordinates in terms of Nyquist
1190 float yy = coord[1];
1191 float zz = coord[2];
1192
1193 // Map back to real pixel coordinates in output volume
1194 xx=xx*(nx-2);
1195 yy=yy*ny;
1196 zz=zz*nz;
1197
1198// 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",
1199// 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);
1200// if (x==0 && y==10 FourierReconstructor:) 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",
1201// 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));
1202
1203 //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);
1204// 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);
1205// 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);
1206 inserter->insert_pixel(xx,yy,zz,input_slice->get_complex_at(x,y),rweight);
1207 }
1208 }
1209 }
1210}
virtual bool insert_pixel(const float &xx, const float &yy, const float &zz, const std::complex< float > dt, const float &weight=1.0)=0
Insert a complex pixel [dt[0]+dt[1]i] at (float) coordinate [xx,yy,zz] with weighting into a discrete...
FourierPixelInserter3D * inserter
A pixel inserter pointer which inserts pixels into the 3D volume using one of a variety of insertion ...
static short hypot_fast_int(int x, int y)
Euclidean distance in 2D for integers computed fast using a cached lookup table.
Definition: util.cpp:764
static float get_max(float f1, float f2)
Get the maximum of 2 numbers.
Definition: util.h:998
void insert_slice_cuda(const float *const matrix, const float *const slice_data, float *vol, float *tmp_data, const int inx, const int iny, const int nx, const int ny, const int nz, const float weight)

References EMAN::Transform::copy_matrix_into_array(), EMAN::Util::get_max(), EMAN::Symmetry3D::get_symmetries(), EMAN::Util::hypot_fast_int(), EMAN::ReconstructorVolumeData::image, EMAN::FourierPixelInserter3D::insert_pixel(), insert_slice_cuda(), inserter, EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::nz, EMAN::FactoryBase::params, EMAN::ReconstructorVolumeData::tmp_data, x, and y.

Referenced by determine_slice_agreement(), and insert_slice().

◆ finish()

EMData * FourierReconstructor::finish ( bool  doift = true)
virtual

Get the reconstructed volume Normally will return the volume in real-space with the requested size.

The calling application is responsible for removing any padding.

Parameters
doiftA flag indicating whether the returned object should be guaranteed to be in real-space (true) or should be left in whatever space the reconstructor generated
Returns
The real space reconstructed volume

Reimplemented from EMAN::Reconstructor.

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 1552 of file reconstructor.cpp.

1553{
1554// float *norm = tmp_data->get_data();
1555// float *rdata = image->get_data();
1556#ifdef EMAN2_USING_CUDA
1557 if(EMData::usecuda == 1 && image->getcudarwdata()){
1558 cout << "copy back from CUDA" << endl;
1559 image->copy_from_device();
1560 tmp_data->copy_from_device();
1561 }
1562#endif
1563
1564 bool sqrtnorm=params.set_default("sqrtnorm",false);
1565 normalize_threed(sqrtnorm);
1566// printf("%f\t%f\t%f\n",tmp_data->get_value_at(67,19,1),image->get_value_at(135,19,1),image->get_value_at(134,19,1));
1567
1568// This compares single precision sum to double precision sum near the origin
1569#ifdef RECONDEBUG
1570 for (int k=0; k<5; k++) {
1571 for (int j=0; j<5; j++) {
1572 for (int i=0; i<5; i++) {
1573 int idx=i*2+j*10+k*50;
1574 std::complex <double> a(ddata[idx],ddata[idx+1]);
1575 double b=dnorm[idx];
1576 a/=b;
1577 printf("%d %d %d %1.4lg\t%1.4g %1.4lg\t%1.4g\n",i,j,k,a.real(),image->get_value_at(i*2,j,k),a.imag(),image->get_value_at(i*2+1,j,k));
1578 }
1579 }
1580 }
1581#endif
1582
1583// tmp_data->write_image("density.mrc");
1584
1585 // we may as well delete the tmp data now... it saves memory and the calling program might
1586 // need memory after it gets the return volume.
1587 // If this delete didn't happen now, it would happen when the deconstructor was called --david
1588 // no longer a good idea with the new iterative scheme -- steve
1589// if ( tmp_data != 0 )
1590// {
1591// delete tmp_data;
1592// tmp_data = 0;
1593// }
1594
1595/* image->process_inplace("xform.fourierorigin.tocorner");*/
1596
1597 if (doift) {
1598 image->do_ift_inplace();
1599 image->depad();
1600 image->process_inplace("xform.phaseorigin.tocenter");
1601 }
1602 // If the image was padded it should be the original size, as the client would expect
1603 // I blocked the rest, it is almost certainly incorrect PAP 07/31/08
1604 // No, it's not incorrect. You are wrong. You have the meaning of nx mixed up. DSAW 09/23/cd
1605 // This should now be handled in the calling program --steve 11/03/09
1606// bool is_fftodd = (nx % 2 == 1);
1607// if ( (nx-2*(!is_fftodd)) != output_x || ny != output_y || nz != output_z )
1608// {
1609// FloatPoint origin( (nx-output_x)/2, (ny-output_y)/2, (nz-output_z)/2 );
1610// FloatSize region_size( output_x, output_y, output_z);
1611// Region clip_region( origin, region_size );
1612// image->clip_inplace( clip_region );
1613// }
1614
1615 // Should be an "if (verbose)" here or something
1616 //print_stats(quality_scores);
1617
1618 image->update();
1619
1620
1621 if (params.has_key("normout")) {
1622// if (tmp_data->get_ysize()%2==0 && tmp_data->get_zsize()%2==0) tmp_data->process_inplace("xform.fourierorigin.tocenter");
1623 EMData *normout=(EMData*) params["normout"];
1624 normout->set_data(tmp_data->copy()->get_data());
1625 normout->update();
1626 }
1627
1628 if (params.has_key("savenorm") && strlen((const char *)params["savenorm"])>0) {
1629 if (tmp_data->get_ysize()%2==0 && tmp_data->get_zsize()%2==0) tmp_data->process_inplace("xform.fourierorigin.tocenter");
1630 tmp_data->write_image((const char *)params["savenorm"]);
1631 }
1632
1633 delete tmp_data;
1634 tmp_data=0;
1635 //Since we give up the ownership of the pointer to-be-returned, it's caller's responsibility to delete the returned image.
1636 //So we wrap this function with return_value_policy< manage_new_object >() in libpyReconstructor2.cpp to hand over ownership to Python.
1637 EMData *ret=image;
1638 image=0;
1639
1640 return ret;
1641}
type set_default(const string &key, type val)
Default setting behavior This can be achieved using a template - d.woolford Jan 2008 (before there wa...
Definition: emobject.h:569
bool has_key(const string &key) const
Ask the Dictionary if it as a particular key.
Definition: emobject.h:511
virtual void normalize_threed(const bool sqrt_damp=false, const bool wiener=false)
Normalize on the assumption that image is a Fourier volume and that tmp_data is a volume of weights c...

References EMAN::Dict::has_key(), EMAN::ReconstructorVolumeData::image, EMAN::ReconstructorVolumeData::normalize_threed(), EMAN::FactoryBase::params, EMAN::Dict::set_default(), and EMAN::ReconstructorVolumeData::tmp_data.

◆ free_memory()

void FourierReconstructor::free_memory ( )
protectedvirtual

Frees the memory owned by this object (but not parent objects) Deletes the FourierPixelInserter3D pointer.

Definition at line 693 of file reconstructor.cpp.

694{
695 if (image) { delete image; image=0; }
696 if (tmp_data) { delete tmp_data; tmp_data=0; }
697 if ( inserter != 0 )
698 {
699 delete inserter;
700 inserter = 0;
701 }
702}

References EMAN::ReconstructorVolumeData::image, inserter, and EMAN::ReconstructorVolumeData::tmp_data.

Referenced by ~FourierReconstructor().

◆ get_desc()

virtual string EMAN::FourierReconstructor::get_desc ( ) const
inlinevirtual

Get the one line description of the reconstructor.

Implements EMAN::FactoryBase.

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 485 of file reconstructor.h.

486 {
487 return "Reconstruction via direct Fourier methods using one of a variety of different kernels, most of which are Gaussian based";
488 }

◆ get_name()

virtual string EMAN::FourierReconstructor::get_name ( ) const
inlinevirtual

Get the unique name of the reconstructor.

Implements EMAN::FactoryBase.

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 478 of file reconstructor.h.

479 {
480 return NAME;
481 }
static const string NAME

References NAME.

◆ get_param_types()

virtual TypeDict EMAN::FourierReconstructor::get_param_types ( ) const
inlinevirtual

Get the parameter types of this object.

Returns
a TypeDict detailing all of the acceptable (and necessary) parameters

Implements EMAN::FactoryBase.

Definition at line 501 of file reconstructor.h.

502 {
503 TypeDict d;
504 d.put("size", EMObject::INTARRAY, "Required. The dimensions of the real-space output volume, including any padding (must be handled by the calling application). Assumed that apix x/y/z identical.");
505 d.put("sym", EMObject::STRING, "Required. The symmetry of the reconstructed volume, c?, d?, oct, tet, icos, h?. Default is c1, ie - an asymmetric object");
506 d.put("mode", EMObject::STRING, "Optional. Fourier pixel insertion mode name (nearest_neighbor, gauss_2, gauss_3, gauss_5, gauss_5_slow, gypergeom_5, experimental) gauss_2 is the default.");
507 d.put("corners", EMObject::BOOL, "Optional. If not set, then reconstruction will cover a spherical volume with a radius of nx/2. If set, the full Fourier volume will be reconstructed, but will be ~2x slower.");
508 d.put("sqrtnorm", EMObject::BOOL, "Optional. When normalizing, additionally divides by the sqrt of the normalization factor to damp exaggerated features. Is this justifyable ? No idea (yet). Default is false.");
509 d.put("usessnr", EMObject::BOOL, "Optional. Looks for and uses the class_ssnr header parameter from each slice to weight each voxel during insertion to the reconstruction.");
510 d.put("verbose", EMObject::BOOL, "Optional. Toggles writing useful information to standard out. Default is false.");
511 d.put("quiet", EMObject::BOOL, "Optional. If false, print verbose information.");
512 d.put("subvolume",EMObject::INTARRAY, "Optional. (xorigin,yorigin,zorigin,xsize,ysize,zsize) all in Fourier pixels. Useful for parallelism.");
513 d.put("savenorm",EMObject::STRING, "Debug. Will cause the normalization volume to be written directly to the specified file when finish() is called.");
514
515 d.put("normout",EMObject::EMDATA, "Will write the normalization volume to the given EMData object file when finish() is called.");
516 return d;
517 }

References EMAN::EMObject::BOOL, EMAN::EMObject::EMDATA, EMAN::EMObject::INTARRAY, EMAN::TypeDict::put(), and EMAN::EMObject::STRING.

◆ insert_slice()

int FourierReconstructor::insert_slice ( const EMData *const  slice,
const Transform euler,
const float  weight 
)
virtual

Insert a slice into a 3D volume, in a given orientation.

Returns
0 if successful, 1 otherwise
Parameters
slicethe image slice to be inserted into the 3D volume
eulerEuler angle of this image slice.
weightA weighting factor for this slice, generally the number of particles in a class-average. May be ignored by some reconstructors
Returns
0 if OK. 1 if error.
Exceptions
NullPointerExceptionif the input EMData pointer is null
ImageFormatExceptionif the image is complex as opposed to real

Reimplemented from EMAN::Reconstructor.

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 1064 of file reconstructor.cpp.

1065{
1066 // Are these exceptions really necessary? (d.woolford)
1067 if (!input_slice) throw NullPointerException("EMData pointer (input image) is NULL");
1068
1069
1070// image->set_attr("apix_x",input_slice->get_attr("apix_x"));
1071// image->set_attr("apix_y",input_slice->get_attr("apix_y"));
1072// image->set_attr("apix_z",input_slice->get_attr("apix_z"));
1073
1074#ifdef EMAN2_USING_CUDA
1075 if(EMData::usecuda == 1) {
1076 if(!input_slice->getcudarwdata()) input_slice->copy_to_cuda(); //copy slice to cuda using the const version
1077 }
1078#endif
1079
1080 bool usessnr=params.set_default("usessnr",false);
1081 bool corners=params.set_default("corners",false);
1082 float weight=oweight;
1083 if (usessnr) {
1084 if (input_slice->has_attr("class_ssnr")) weight=-1.0; // negative weight is a flag for using SSNR
1085 else weight=0;
1086 }
1087
1088 if (weight==0) return -1;
1089
1090Transform * rotation;
1091/* if ( input_slice->has_attr("xform.projection") ) {
1092 rotation = (Transform*) (input_slice->get_attr("xform.projection")); // assignment operator
1093 } else {*/
1094 rotation = new Transform(arg); // assignment operator
1095// }
1096
1097 EMData *slice;
1098 if (input_slice->get_attr_default("reconstruct_preproc",(int) 0)) slice=input_slice->copy();
1099 else slice = preprocess_slice( input_slice, *rotation);
1100
1101
1102 // We must use only the rotational component of the transform, scaling, translation and mirroring
1103 // are not implemented in Fourier space, but are in preprocess_slice
1104 rotation->set_scale(1.0);
1105 rotation->set_mirror(false);
1106 rotation->set_trans(0,0,0);
1107
1108 // Finally to the pixel wise slice insertion
1109 //slice->copy_to_cuda();
1110// EMData *s2=slice->do_ift();
1111// s2->write_image("is.hdf",-1);
1112 do_insert_slice_work(slice, *rotation, weight, corners);
1113
1114 delete rotation; rotation=0;
1115 delete slice;
1116
1117// image->update();
1118 return 0;
1119}

References do_insert_slice_work(), NullPointerException, EMAN::FactoryBase::params, preprocess_slice(), EMAN::Dict::set_default(), EMAN::Transform::set_mirror(), EMAN::Transform::set_scale(), and EMAN::Transform::set_trans().

◆ load_default_settings()

void FourierReconstructor::load_default_settings ( )
protectedvirtual

Load default settings.

Definition at line 686 of file reconstructor.cpp.

687{
688 inserter=0;
689 image=0;
690 tmp_data=0;
691}

References EMAN::ReconstructorVolumeData::image, inserter, and EMAN::ReconstructorVolumeData::tmp_data.

Referenced by FourierReconstructor().

◆ load_inserter()

void FourierReconstructor::load_inserter ( )
protectedvirtual

Load the pixel inserter based on the information in params.

Definition at line 706 of file reconstructor.cpp.

707{
708// ss
709// string mode = (string)params["mode"];
710 Dict parms;
711 parms["data"] = image;
712 parms["norm"] = tmp_data->get_data();
713 // These aren't necessary because we deal with them before calling the inserter
714// parms["subnx"] = nx;
715// parms["subny"] = ny;
716// parms["subnx"] = nz;
717// parms["subx0"] = x0;
718// parms["suby0"] = y0;
719// parms["subz0"] = z0;
720
721 if ( inserter != 0 )
722 {
723 delete inserter;
724 }
725
726 inserter = Factory<FourierPixelInserter3D>::get((string)params["mode"], parms);
727 inserter->init();
728}
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385

References EMAN::Factory< T >::get(), EMAN::ReconstructorVolumeData::image, EMAN::FourierPixelInserter3D::init(), inserter, EMAN::FactoryBase::params, and EMAN::ReconstructorVolumeData::tmp_data.

Referenced by setup(), setup_seed(), and setup_seedandweights().

◆ NEW()

static Reconstructor * EMAN::FourierReconstructor::NEW ( )
inlinestatic

Factory incorporation uses the pointer of this function.

Returns
a Reconstructor pointer to a newly allocated FourierReconstructor

Definition at line 493 of file reconstructor.h.

494 {
495 return new FourierReconstructor();
496 }
FourierReconstructor()
Default constructor calls load_default_settings()

References FourierReconstructor().

◆ operator=()

FourierReconstructor & EMAN::FourierReconstructor::operator= ( const FourierReconstructor )
private

Disallow assignment.

◆ pixel_at()

bool FourierReconstructor::pixel_at ( const float &  xx,
const float &  yy,
const float &  zz,
float *  dt 
)
protectedvirtual

This is a mode-2 pixel extractor.

Parameters
xx,yy,zzvoxel coordinates (need not be integers)
dtfloat pointer with 3 floats allocated for returned complex value and weight sum

Reimplemented in EMAN::WienerFourierReconstructor.

Definition at line 1448 of file reconstructor.cpp.

1449{
1450 int x0 = (int) Util::round(xx);
1451 int y0 = (int) Util::round(yy);
1452 int z0 = (int) Util::round(zz);
1453
1454 std::complex<float> val=image->get_complex_at(x0,y0,z0);
1455 size_t idx=image->get_complex_index_fast(x0,y0,z0)/2;
1456 float norm=tmp_data->get_value_at_index(idx);
1457 dt[0]=val.real()/norm;
1458 dt[1]=val.imag()/norm;
1459 dt[2]=norm;
1460// printf("%d %d %d %g %g %g\n",x0,y0,z0,dt[0],dt[1],dt[2]);
1461 return true;
1462
1463 //Trilinear interpolation version caused prominent interpolation artifacts due to high noise levels
1464 // between 1/2 Nyquist and Nyquist. While the nearest neighbor interpolation used above still has
1465 // artifacts, it seems better for this puprose.
1466
1467// int x0 = (int) floor(xx);
1468// int y0 = (int) floor(yy);
1469// int z0 = (int) floor(zz);
1470//
1471// float *rdata=image->get_data();
1472// float *norm=tmp_data->get_data();
1473// float normsum=0,normsum2=0;
1474//
1475// dt[0]=dt[1]=dt[2]=0.0;
1476//
1477// if (nx==subnx) { // normal full reconstruction
1478// if (x0<-nx2-1 || y0<-ny2-1 || z0<-nz2-1 || x0>nx2 || y0>ny2 || z0>nz2 ) return false;
1479//
1480//
1481//
1482// int x1=x0+1;
1483// int y1=y0+1;
1484// int z1=z0+1;
1485// if (x0<-nx2) x0=-nx2;
1486// if (x1>nx2) x1=nx2;
1487// if (y0<-ny2) y0=-ny2;
1488// if (y1>ny2) y1=ny2;
1489// if (z0<-nz2) z0=-nz2;
1490// if (z1>nz2) z1=nz2;
1491//
1492// size_t idx=0;
1493// float r, gg;
1494// for (int k = z0 ; k <= z1; k++) {
1495// for (int j = y0 ; j <= y1; j++) {
1496// for (int i = x0; i <= x1; i ++) {
1497// idx=image->get_complex_index_fast(i,j,k);
1498// // r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
1499// // gg = Util::fast_exp(-r / EMConsts::I2G);
1500// gg=(1.0-fabs(i-xx))*(1.0-fabs(j-yy))*(1.0-fabs(k-zz)); // Change from Gaussian to trilinear, 6/7/20
1501//
1502// dt[0]+=gg*rdata[idx];
1503// dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
1504// //dt[2]+=norm[idx/2]*gg;
1505// normsum2+=gg;
1506// normsum+=gg*norm[idx/2];
1507// if (i==0) {
1508// normsum2+=gg;
1509// normsum+=gg*norm[idx/2];
1510// }
1511// }
1512// }
1513// }
1514// if (normsum==0) return false;
1515// dt[0]/=normsum;
1516// dt[1]/=normsum;
1517// dt[2]=normsum/normsum2;
1518// #ifdef DEBUG_POINT
1519// if (z0==23 && y0==0 && x0==113) {
1520// std::complex<float> pv = image->get_complex_at(113,0,23);
1521// float pnv = tmp_data->get_value_at(113,0,23);
1522// printf("pixat: %1.4g\t%1.4g\t%1.4g\t%1.4g\t%1.4g\t%1.4g\n",pv.real()/pnv,pv.imag()/pnv,pnv,dt[0],dt[1],dt[2]);
1523// }
1524// #endif
1525// // 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]);
1526// return true;
1527// }
1528// else { // for subvolumes, not optimized yet
1529// size_t idx;
1530// float r, gg;
1531// for (int k = z0 ; k <= z0 + 1; k++) {
1532// for (int j = y0 ; j <= y0 + 1; j++) {
1533// for (int i = x0; i <= x0 + 1; i ++) {
1534// r = Util::hypot3sq((float) i - xx, j - yy, k - zz);
1535// idx=image->get_complex_index(i,j,k,subx0,suby0,subz0,nx,ny,nz);
1536// gg = Util::fast_exp(-r / EMConsts::I2G)*norm[idx/2];
1537//
1538// dt[0]+=gg*rdata[idx];
1539// dt[1]+=(i<0?-1.0f:1.0f)*gg*rdata[idx+1];
1540// dt[2]+=norm[idx/2];
1541// normsum+=gg;
1542// }
1543// }
1544// }
1545//
1546// if (normsum==0) return false;
1547// return true;
1548// }
1549}
static int round(float x)
Get ceiling round of a float number x.
Definition: util.h:465

References EMAN::ReconstructorVolumeData::image, EMAN::Util::round(), and EMAN::ReconstructorVolumeData::tmp_data.

Referenced by do_compare_slice_work(), and projection().

◆ preprocess_slice()

EMData * FourierReconstructor::preprocess_slice ( const EMData *const  slice,
const Transform t = Transform() 
)
virtual

Preprocess the slice prior to insertion into the 3D volume this Fourier tranforms the slice and make sure all the pixels are in the right position it always returns a copy of the provided slice, so it should be deleted by someone eventually.

Returns
the processed slice
Parameters
slicethe slice to be prepocessed
ttransform to be used for insertion
Exceptions
InvalidValueExceptionwhen the specified padding value is less than the size of the images

Reimplemented from EMAN::Reconstructor.

Definition at line 1022 of file reconstructor.cpp.

1023{
1024#ifdef EMAN2_USING_CUDA
1025 if(EMData::usecuda == 1) {
1026 if(!slice->getcudarwdata()) slice->copy_to_cuda(); //copy slice to cuda using the const version
1027 }
1028#endif
1029 // Shift the image pixels so the real space origin is now located at the phase origin (at the bottom left of the image)
1030 EMData* return_slice = 0;
1031 Transform tmp(t);
1032 tmp.set_rotation(Dict("type","eman")); // resets the rotation to 0 implicitly, this way we only do 2d translation,scaling and mirroring
1033
1034 if (tmp.is_identity()) return_slice=slice->copy();
1035 else return_slice = slice->process("xform",Dict("transform",&tmp));
1036
1037 return_slice->process_inplace("xform.phaseorigin.tocorner");
1038
1039// printf("@@@ %d\n",(int)return_slice->get_attr("nx"));
1040 // Fourier transform the slice
1041
1042#ifdef EMAN2_USING_CUDA
1043 if(EMData::usecuda == 1 && return_slice->getcudarwdata()) {
1044 return_slice->do_fft_inplace_cuda(); //a CUDA FFT inplace is quite slow as there is a lot of mem copying.
1045 }else{
1046 return_slice->do_fft_inplace();
1047 }
1048#else
1049 return_slice->do_fft_inplace();
1050#endif
1051
1052// printf("%d\n",(int)return_slice->get_attr("nx"));
1053
1054 return_slice->mult((float)sqrt(1.0f/(return_slice->get_ysize())*return_slice->get_xsize()));
1055
1056 // Shift the Fourier transform so that it's origin is in the center (bottom) of the image.
1057// return_slice->process_inplace("xform.fourierorigin.tocenter");
1058
1059 return_slice->set_attr("reconstruct_preproc",(int)1);
1060 return return_slice;
1061}

References EMAN::Transform::is_identity(), EMAN::Transform::set_rotation(), and sqrt().

Referenced by determine_slice_agreement(), EMAN::WienerFourierReconstructor::determine_slice_agreement(), insert_slice(), and EMAN::WienerFourierReconstructor::insert_slice().

◆ projection()

EMData * FourierReconstructor::projection ( const Transform euler,
int  ret_fourier 
)
virtual

Generates a projection by extracting a slice in Fourier space.

Parameters
eulerThe orientation of the slice as a Transform object
ret_fourierIf true, will return the Fourier transform of the projection

Reimplemented from EMAN::Reconstructor.

Definition at line 1383 of file reconstructor.cpp.

1383 {
1384
1385 if (subx0!=0 || suby0!=0 || subz0!=0 || subnx!=nx || subny!=ny ||subnz!=nz)
1386 throw ImageDimensionException("ERROR: Reconstructor->projection() does not work with subvolumes");
1387
1388 EMData *ret = new EMData(nx,ny,1);
1389 ret->set_complex(1);
1390 ret->set_ri(1);
1391 ret->set_attr("apix_x",image->get_attr("apix_x"));
1392 ret->set_attr("apix_y",image->get_attr("apix_y"));
1393 ret->set_attr("apix_z",image->get_attr("apix_z"));
1394
1395 // We must use only the rotational component of the transform, scaling, translation and mirroring
1396 // are not implemented in Fourier space, but are in preprocess_slice
1397 Transform rotation(euler);
1398 rotation.set_scale(1.0);
1399 rotation.set_mirror(false);
1400 rotation.set_trans(0,0,0);
1401
1402 float dt[3]; // This stores the complex and weight from the volume
1403
1404// float apix=input_slice->get_attr("apix_x");
1405// float rmax=iny*apix/12.0; // radius at 12 A, use as cutoff for low res insertion quality
1406
1407 for (int y = -ny/2; y < ny/2; y++) {
1408 for (int x = 0; x <= nx/2; x++) {
1409
1410 float rx = (float) x/(nx-2); // coords relative to Nyquist=.5
1411 float ry = (float) y/ny;
1412
1413
1414 Vec3f coord(rx,ry,0);
1415 coord = coord*rotation; // transpose multiplication
1416 float xx = coord[0]; // transformed coordinates in terms of Nyquist
1417 float yy = coord[1];
1418 float zz = coord[2];
1419
1420
1421 if (fabs(xx)>0.5 || fabs(yy)>=0.5 || fabs(zz)>=0.5) continue;
1422
1423 // Map back to actual pixel coordinates in output volume
1424 xx=xx*(nx-2);
1425 yy=yy*ny;
1426 zz=zz*nz;
1427
1428 if (!pixel_at(xx,yy,zz,dt) || dt[2]<0.005) continue;
1429// if (x==0) printf("%d %d %g %g %g\n",x,y,dt[0],dt[1],dt[2]);
1430 if ((x==0 ||x==nx/2) && (y!=0 && y!=-ny/2)) { dt[0]/=2; dt[1]/=2; }
1431 ret->set_complex_at(x,y,std::complex<float>(dt[0],dt[1])); // division by dt[2] already handled in pixel_at
1432 }
1433 }
1434
1435 Transform translation;
1436 translation.set_trans(euler.get_trans());
1437 ret->process_inplace("xform",Dict("transform",&translation));
1438 if (!ret_fourier) {
1439 ret->process_inplace("xform.phaseorigin.tocenter");
1440 EMData *tmp=ret->do_ift();
1441 delete ret;
1442 ret=tmp;
1443 }
1444 return ret;
1445}
Vec3f get_trans() const
Get the post trans as a vec3f.
Definition: transform.cpp:1046
#define ImageDimensionException(desc)
Definition: exception.h:166

References EMAN::Transform::get_trans(), EMAN::ReconstructorVolumeData::image, ImageDimensionException, EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::nz, pixel_at(), EMAN::Transform::set_mirror(), EMAN::Transform::set_scale(), EMAN::Transform::set_trans(), EMAN::ReconstructorVolumeData::subnx, EMAN::ReconstructorVolumeData::subny, EMAN::ReconstructorVolumeData::subnz, EMAN::ReconstructorVolumeData::subx0, EMAN::ReconstructorVolumeData::suby0, EMAN::ReconstructorVolumeData::subz0, x, and y.

◆ setup()

void FourierReconstructor::setup ( )
virtual

Setup the Fourier reconstructor.

Exceptions
InvalidValueExceptionWhen one of the input parameters is invalid

Implements EMAN::Reconstructor.

Definition at line 730 of file reconstructor.cpp.

731{
732 // default setting behavior - does not override if the parameter is already set
733 params.set_default("mode","gauss_2");
734 params.set_default("verbose",(int)0);
735
736 vector<int> size=params["size"];
737
738 nx = size[0];
739 ny = size[1];
740 nz = size[2];
741 nx2=nx/2-1;
742 ny2=ny/2;
743 nz2=nz/2;
744
745#ifdef RECONDEBUG
746 ddata=(double *)malloc(sizeof(double)*250);
747 dnorm=(double *)malloc(sizeof(double)*250);
748 for (int i=0; i<250; i++) ddata[i]=dnorm[i]=0.0;
749#endif
750
751 // Adjust nx if for Fourier transform even odd issues
752 bool is_fftodd = (nx % 2 == 1);
753 // The Fourier transform requires one extra pixel in the x direction,
754 // which is two spaces in memory, one each for the complex and the
755 // real components
756 nx += 2-is_fftodd;
757
758 if (params.has_key("subvolume")) {
759 vector<int> sub=params["subvolume"];
760 subx0=sub[0];
761 suby0=sub[1];
762 subz0=sub[2];
763 subnx=sub[3];
764 subny=sub[4];
765 subnz=sub[5];
766
767 if (subx0<0 || suby0<0 || subz0<0 || subx0+subnx>nx || suby0+subny>ny || subz0+subnz>nz)
768 throw ImageDimensionException("The subvolume cannot extend outside the reconstructed volume");
769
770 }
771 else {
772 subx0=suby0=subz0=0;
773 subnx=nx;
774 subny=ny;
775 subnz=nz;
776 }
777
778
779 // Odd dimension support is here atm, but not above.
780 if (image) delete image;
781 image = new EMData();
782 image->set_size(subnx, subny, subnz);
783 image->set_complex(true);
784 image->set_fftodd(is_fftodd);
785 image->set_ri(true);
786// printf("%d %d %d\n\n",subnx,subny,subnz);
787 image->to_zero();
788
789 if (params.has_key("subvolume")) {
790 image->set_attr("subvolume_x0",subx0);
791 image->set_attr("subvolume_y0",suby0);
792 image->set_attr("subvolume_z0",subz0);
793 image->set_attr("subvolume_full_nx",nx);
794 image->set_attr("subvolume_full_ny",ny);
795 image->set_attr("subvolume_full_nz",nz);
796 }
797
798 if (tmp_data) delete tmp_data;
799 tmp_data = new EMData();
800 tmp_data->set_size(subnx/2, subny, subnz);
801 tmp_data->to_zero();
802 tmp_data->update();
803
805
806#ifdef RECONDEBUG
807 printf("copied\n");
808 inserter->ddata=ddata;
809 inserter->dnorm=dnorm;
810#endif
811
812 if ( (bool) params["verbose"] )
813 {
814 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
815 cout << "3D Fourier subvolume is " << subnx << " " << subny << " " << subnz << endl;
816 printf ("You will require approximately %1.3g GB of memory to reconstruct this volume\n",((float)subnx*subny*subnz*sizeof(float)*1.5)/1000000000.0);
817 }
818}
virtual void load_inserter()
Load the pixel inserter based on the information in params.
bool is_fftodd() const
Does this image correspond to a (real-space) odd nx?

References EMAN::Dict::has_key(), EMAN::ReconstructorVolumeData::image, ImageDimensionException, inserter, is_fftodd(), load_inserter(), EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::nx2, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::ny2, EMAN::ReconstructorVolumeData::nz, EMAN::ReconstructorVolumeData::nz2, EMAN::FactoryBase::params, EMAN::Dict::set_default(), sub(), EMAN::ReconstructorVolumeData::subnx, EMAN::ReconstructorVolumeData::subny, EMAN::ReconstructorVolumeData::subnz, EMAN::ReconstructorVolumeData::subx0, EMAN::ReconstructorVolumeData::suby0, EMAN::ReconstructorVolumeData::subz0, and EMAN::ReconstructorVolumeData::tmp_data.

◆ setup_seed()

void FourierReconstructor::setup_seed ( EMData seed,
float  seed_weight 
)
virtual

Initialize the reconstructor with a seed volume.

This can be used to provide some 'default' value when there is missing data in Fourier space. The passed 'seed' must be of the appropriate padded size, must be in Fourier space, and the same EMData* object will be returned by finish(), meaning the Reconstructor is implicitly taking ownership of the object. However, in Python, this means the seed may be passed in without copying, as the same EMData will be coming back out at the end. The seed_weight determines how 'strong' the seed volume should be as compared to other inserted slices in Fourier space.

Exceptions
InvalidValueExceptionWhen one of the input parameters is invalid

Reimplemented from EMAN::Reconstructor.

Definition at line 820 of file reconstructor.cpp.

820 {
821 // default setting behavior - does not override if the parameter is already set
822 params.set_default("mode","gauss_2");
823
824 vector<int> size=params["size"];
825
826 nx = size[0];
827 ny = size[1];
828 nz = size[2];
829 nx2=nx/2-1;
830 ny2=ny/2;
831 nz2=nz/2;
832
833
834 // Adjust nx if for Fourier transform even odd issues
835 bool is_fftodd = (nx % 2 == 1);
836 // The Fourier transform requires one extra pixel in the x direction,
837 // which is two spaces in memory, one each for the complex and the
838 // real components
839 nx += 2-is_fftodd;
840
841 if (params.has_key("subvolume")) {
842 vector<int> sub=params["subvolume"];
843 subx0=sub[0];
844 suby0=sub[1];
845 subz0=sub[2];
846 subnx=sub[3];
847 subny=sub[4];
848 subnz=sub[5];
849
850 if (subx0<0 || suby0<0 || subz0<0 || subx0+subnx>nx || suby0+subny>ny || subz0+subnz>nz)
851 throw ImageDimensionException("The subvolume cannot extend outside the reconstructed volume");
852
853 }
854 else {
855 subx0=suby0=subz0=0;
856 subnx=nx;
857 subny=ny;
858 subnz=nz;
859 }
860
861 if (seed->get_xsize()!=subnx || seed->get_ysize()!=subny || seed->get_zsize()!=subnz || !seed->is_complex())
862 throw ImageDimensionException("The dimensions of the seed volume do not match the reconstruction size");
863
864 // Odd dimension support is here atm, but not above.
865 image = seed->copy();
866 image->mult(seed_weight); // The lack of this line was what was causing all of the strange normalization issues
867
868
869
870 if (params.has_key("subvolume")) {
871 image->set_attr("subvolume_x0",subx0);
872 image->set_attr("subvolume_y0",suby0);
873 image->set_attr("subvolume_z0",subz0);
874 image->set_attr("subvolume_full_nx",nx);
875 image->set_attr("subvolume_full_ny",ny);
876 image->set_attr("subvolume_full_nz",nz);
877 }
878
879 if (tmp_data) delete tmp_data;
880 tmp_data = new EMData();
881 tmp_data->set_size(subnx/2, subny, subnz);
882 tmp_data->to_value(seed_weight);
883
884 // The values at x=0 and x=nyquist are added twice in the map normally, but the normalization is only added once
885 // This is compensated in the final normalization. In the seed volume we accomodate this by reducing the seed
886 // alternatively we could double the actual values. Impact is similar, if not 100% identical
887 if (subx0==0) {
888 for (int k=0; k<subnz; k++) {
889 for (int j=0; j<subny; j++) {
890 tmp_data->set_value_at(0,j,k,seed_weight/2.0);
891 }
892 }
893 tmp_data->set_value_at(0,subny/2,0,seed_weight);
894 tmp_data->set_value_at(0,0,subnz/2,seed_weight);
895 }
896 if (subnx+subx0==nx) {
897 for (int k=0; k<subnz; k++) {
898 for (int j=0; j<subny; j++) {
899 tmp_data->set_value_at(subnx/2-1,j,k,seed_weight/2.0);
900 }
901 }
902 tmp_data->set_value_at(subnx/2-1,subny/2,0,seed_weight);
903 tmp_data->set_value_at(subnx/2-1,0,subnz/2,seed_weight);
904 }
905
906
907
909
910#ifdef DEBUG_POINT
911 std::complex<float> pv = image->get_complex_at(113,0,23);
912 float pnv = tmp_data->get_value_at(113,0,23);
913 printf("seed: %1.4g\t%1.4g\t%1.4g\n",pv.real()/pnv,pv.imag()/pnv,pnv);
914#endif
915
916
917 if ( (bool) params["quiet"] == false )
918 {
919 cout << "Seeded direct Fourier inversion";
920 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
921 cout << "3D Fourier subvolume is " << subnx << " " << subny << " " << subnz << endl;
922 cout << "You will require approximately " << setprecision(3) << (subnx*subny*subnz*sizeof(float)*1.5)/1000000000.0 << "GB of memory to reconstruct this volume" << endl;
923 }
924}

References EMAN::Dict::has_key(), EMAN::ReconstructorVolumeData::image, ImageDimensionException, is_fftodd(), load_inserter(), EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::nx2, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::ny2, EMAN::ReconstructorVolumeData::nz, EMAN::ReconstructorVolumeData::nz2, EMAN::FactoryBase::params, EMAN::Dict::set_default(), sub(), EMAN::ReconstructorVolumeData::subnx, EMAN::ReconstructorVolumeData::subny, EMAN::ReconstructorVolumeData::subnz, EMAN::ReconstructorVolumeData::subx0, EMAN::ReconstructorVolumeData::suby0, EMAN::ReconstructorVolumeData::subz0, and EMAN::ReconstructorVolumeData::tmp_data.

◆ setup_seedandweights()

void FourierReconstructor::setup_seedandweights ( EMData seed,
EMData weight 
)
virtual

Initialize the reconstructor with a seed volume, as above.

In this case the initial weight map is also provided explicitly, rather than a single weight value.

Reimplemented from EMAN::Reconstructor.

Definition at line 926 of file reconstructor.cpp.

926 {
927 // default setting behavior - does not override if the parameter is already set
928
929 // WARNING - when seed_weight is provided it must already be compensated at x=0 and x=nx-1 (should be 1/2 the actual value)
930 params.set_default("mode","gauss_2");
931
932 vector<int> size=params["size"];
933
934 nx = size[0];
935 ny = size[1];
936 nz = size[2];
937 nx2=nx/2-1;
938 ny2=ny/2;
939 nz2=nz/2;
940
941
942 // Adjust nx if for Fourier transform even odd issues
943 bool is_fftodd = (nx % 2 == 1);
944 // The Fourier transform requires one extra pixel in the x direction,
945 // which is two spaces in memory, one each for the complex and the
946 // real components
947 nx += 2-is_fftodd;
948
949 if (params.has_key("subvolume")) {
950 vector<int> sub=params["subvolume"];
951 subx0=sub[0];
952 suby0=sub[1];
953 subz0=sub[2];
954 subnx=sub[3];
955 subny=sub[4];
956 subnz=sub[5];
957
958 if (subx0<0 || suby0<0 || subz0<0 || subx0+subnx>nx || suby0+subny>ny || subz0+subnz>nz)
959 throw ImageDimensionException("The subvolume cannot extend outside the reconstructed volume");
960
961 }
962 else {
963 subx0=suby0=subz0=0;
964 subnx=nx;
965 subny=ny;
966 subnz=nz;
967 }
968
969 if (seed->get_xsize()!=subnx || seed->get_ysize()!=subny || seed->get_zsize()!=subnz || !seed->is_complex())
970 throw ImageDimensionException("The dimensions of the seed volume do not match the reconstruction size");
971
972 // Odd dimension support is here atm, but not above.
973 image = seed->copy(); // note that if the provided seed has not been 'premultiplied' by the weights, bad things may result!
974
975 if (params.has_key("subvolume")) {
976 image->set_attr("subvolume_x0",subx0);
977 image->set_attr("subvolume_y0",suby0);
978 image->set_attr("subvolume_z0",subz0);
979 image->set_attr("subvolume_full_nx",nx);
980 image->set_attr("subvolume_full_ny",ny);
981 image->set_attr("subvolume_full_nz",nz);
982 }
983
984 if (tmp_data) delete tmp_data;
985 tmp_data=seed_weight->copy();
986
988
989 if ( (bool) params["quiet"] == false )
990 {
991 cout << "Seeded direct Fourier inversion";
992 cout << "3D Fourier dimensions are " << nx << " " << ny << " " << nz << endl;
993 cout << "3D Fourier subvolume is " << subnx << " " << subny << " " << subnz << endl;
994 cout << "You will require approximately " << setprecision(3) << (subnx*subny*subnz*sizeof(float)*1.5)/1000000000.0 << "GB of memory to reconstruct this volume" << endl;
995 }
996}

References EMAN::Dict::has_key(), EMAN::ReconstructorVolumeData::image, ImageDimensionException, is_fftodd(), load_inserter(), EMAN::ReconstructorVolumeData::nx, EMAN::ReconstructorVolumeData::nx2, EMAN::ReconstructorVolumeData::ny, EMAN::ReconstructorVolumeData::ny2, EMAN::ReconstructorVolumeData::nz, EMAN::ReconstructorVolumeData::nz2, EMAN::FactoryBase::params, EMAN::Dict::set_default(), sub(), EMAN::ReconstructorVolumeData::subnx, EMAN::ReconstructorVolumeData::subny, EMAN::ReconstructorVolumeData::subnz, EMAN::ReconstructorVolumeData::subx0, EMAN::ReconstructorVolumeData::suby0, EMAN::ReconstructorVolumeData::subz0, and EMAN::ReconstructorVolumeData::tmp_data.

Member Data Documentation

◆ inserter

FourierPixelInserter3D* EMAN::FourierReconstructor::inserter
protected

A pixel inserter pointer which inserts pixels into the 3D volume using one of a variety of insertion methods.

Definition at line 555 of file reconstructor.h.

Referenced by EMAN::WienerFourierReconstructor::do_insert_slice_work(), do_insert_slice_work(), free_memory(), load_default_settings(), load_inserter(), and setup().

◆ NAME

const string FourierReconstructor::NAME = "fourier"
static

Definition at line 519 of file reconstructor.h.

Referenced by get_name().


The documentation for this class was generated from the following files: