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

3D rotational and translational alignment using a hierarchical method with gradually decreasing downsampling in Fourier space. More...

#include <aligner.h>

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

Public Member Functions

virtual EMDataalign (EMData *this_img, EMData *to_img, const string &cmp_name="sqeuclidean", const Dict &cmp_params=Dict()) const
 See Aligner comments for more details. More...
 
virtual EMDataalign (EMData *this_img, EMData *to_img) const
 See Aligner comments for more details. More...
 
virtual vector< Dictxform_align_nbest (EMData *this_img, EMData *to_img, const unsigned int nsoln, const string &cmp_name, const Dict &cmp_params) const
 See Aligner comments for more details. More...
 
virtual string get_name () const
 Get the Aligner's name. More...
 
virtual string get_desc () const
 
virtual TypeDict get_param_types () const
 
- Public Member Functions inherited from EMAN::Aligner
virtual ~Aligner ()
 
virtual Dict get_params () const
 Get the Aligner parameters in a key/value dictionary. More...
 
virtual void set_params (const Dict &new_params)
 Set the Aligner parameters using a key/value dictionary. More...
 

Static Public Member Functions

static AlignerNEW ()
 

Static Public Attributes

static const string NAME = "rotate_translate_3d_local_tree"
 

Private Member Functions

bool testort (EMData *small_this, EMData *small_to, EMData *small_mask, EMData *small_thissq, vector< float > &sigmathisv, vector< float > &sigmatov, vector< float > &s_score, vector< float > &s_coverage, vector< Transform > &s_xform, int i, Dict &upd, Transform initxf, int maxshift) const
 

Additional Inherited Members

- Protected Attributes inherited from EMAN::Aligner
Dict params
 

Detailed Description

3D rotational and translational alignment using a hierarchical method with gradually decreasing downsampling in Fourier space.

In theory, very fast, and without need for a "refine" aligner. Comparator is ignored. Uses an inbuilt comparison. This variant uses something like FLCF (local cross correlation) for translational alignment, and should work better when the reference is masked but doing this slows things down.

Parameters
symThe symmtery to use as the basis of the spherical sampling
verboseTurn this on to have useful information printed to standard out
Author
Steve Ludtke
Date
April 2015

Definition at line 1959 of file aligner.h.

Member Function Documentation

◆ align() [1/2]

virtual EMData * EMAN::RT3DLocalTreeAligner::align ( EMData this_img,
EMData to_img 
) const
inlinevirtual

See Aligner comments for more details.

Implements EMAN::Aligner.

Definition at line 1968 of file aligner.h.

1969 {
1970 return align(this_img, to_img, "sqeuclidean", Dict());
1971 }
virtual EMData * align(EMData *this_img, EMData *to_img, const string &cmp_name="sqeuclidean", const Dict &cmp_params=Dict()) const
See Aligner comments for more details.

References align().

◆ align() [2/2]

virtual EMData * EMAN::RT3DLocalTreeAligner::align ( EMData this_img,
EMData to_img,
const string &  cmp_name = "sqeuclidean",
const Dict cmp_params = Dict() 
) const
virtual

See Aligner comments for more details.

Implements EMAN::Aligner.

Referenced by align().

◆ get_desc()

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

Implements EMAN::Aligner.

Definition at line 1983 of file aligner.h.

1984 {
1985 return "EXPERIMENATAL - 3D rotational and translational alignment using a hierarchical approach in Fourier space. Should be very fast and not require 'refine' alignment. This variant performs a locally normalized CCF for translational alignment and should thus work better when the reference is masked, but will be slower.";
1986 }

◆ get_name()

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

Get the Aligner's name.

Each Aligner is identified by a unique name.

Returns
The Aligner's name.

Implements EMAN::Aligner.

Definition at line 1978 of file aligner.h.

1979 {
1980 return NAME;
1981 }
static const string NAME
Definition: aligner.h:2012

References NAME.

◆ get_param_types()

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

Implements EMAN::Aligner.

Definition at line 1993 of file aligner.h.

1994 {
1995 TypeDict d;
1996 d.put("maxshift", EMObject::INT,"maximum shift allowed");
1997 d.put("sym", EMObject::STRING,"The symmtery to use as the basis of the spherical sampling. Default is c1 (no symmetry)");
1998 d.put("sigmathis", EMObject::FLOAT,"Only Fourier voxels larger than sigma times this value will be considered");
1999 d.put("sigmato", EMObject::FLOAT,"Only Fourier voxels larger than sigma times this value will be considered");
2000 d.put("maxres", EMObject::FLOAT,"maximum resolution to compare");
2001 d.put("minres", EMObject::FLOAT,"minimum resolution to compare");
2002 d.put("maxang", EMObject::FLOAT,"maximum angle from initial rotation.");
2003 d.put("initxform", EMObject::TRANSFORMARRAY,"An array of Transforms storing the starting positions.");
2004
2005// d.put("initxform", EMObject::TRANSFORM,"The Transform storing the starting position. If unspecified the identity matrix is used");
2006 d.put("randphi", EMObject::BOOL,"Ignore phi constraint for refine search");
2007 d.put("rand180", EMObject::BOOL,"Ignore 180 rotation for refine search");
2008 d.put("verbose", EMObject::BOOL,"Turn this on to have useful information printed to standard out.");
2009 return d;
2010 }

References EMAN::EMObject::BOOL, EMAN::EMObject::FLOAT, EMAN::EMObject::INT, EMAN::TypeDict::put(), EMAN::EMObject::STRING, and EMAN::EMObject::TRANSFORMARRAY.

◆ NEW()

static Aligner * EMAN::RT3DLocalTreeAligner::NEW ( )
inlinestatic

Definition at line 1988 of file aligner.h.

1989 {
1990 return new RT3DLocalTreeAligner();
1991 }

◆ testort()

bool RT3DLocalTreeAligner::testort ( EMData small_this,
EMData small_to,
EMData small_mask,
EMData small_thissq,
vector< float > &  sigmathisv,
vector< float > &  sigmatov,
vector< float > &  s_score,
vector< float > &  s_coverage,
vector< Transform > &  s_xform,
int  i,
Dict upd,
Transform  initxf,
int  maxshift 
) const
private

Definition at line 4296 of file aligner.cpp.

4296 {
4297 Transform t;
4298 Dict aap=s_xform[i].get_params("eman");
4299 aap["tx"]=0;
4300 aap["ty"]=0;
4301 aap["tz"]=0;
4302 for (Dict::const_iterator p=upd.begin(); p!=upd.end(); p++) {
4303 aap[p->first]=(float)aap[p->first]+(float)p->second;
4304 }
4305
4306 t.set_params(aap);
4307 float maxang=params.set_default("maxang",-1.0);
4308 bool randphi=params.set_default("randphi",false);
4309 bool rand180=params.set_default("rand180",false);
4310
4311 if (maxang>0){
4312
4313 Transform tmp=initxf * t.inverse();
4314
4315 if (randphi){
4316 Dict td=t.get_params("eman");
4317 Dict ti=initxf.get_params("eman");
4318 td["phi"]=ti["phi"];
4319 Transform tmp1=Transform(td);
4320 tmp=initxf * tmp1.inverse();
4321 }
4322
4323 float r=tmp.get_params("spin")["omega"];
4324 if (rand180){
4325 r=r>90?(180-r):r;
4326 }
4327 if(r>maxang)
4328 return false;
4329
4330 }
4331
4332 int ny=small_this->get_ysize();
4333 if (params.has_key("initxform")){
4334 // when doing refinement, search around the given position
4335 t.set_trans(initxf.get_trans()*ny/(float)params["boxsize"]);
4336 aap=t.get_params("eman");
4337 }
4338
4339 // rotate in Fourier space then use a CCF to find translation
4340 EMData *stt=small_this->process("xform",Dict("transform",EMObject(&t),"zerocorners",1));
4341 EMData *sttsq=small_thissq->process("xform",Dict("transform",EMObject(&t),"zerocorners",1));
4342// EMData *ccf=small_to->calc_ccf(stt);
4343 EMData *ccf=small_to->calc_ccf_masked(stt,sttsq,small_mask);
4344 IntPoint ml=ccf->calc_max_location_wrap(maxshift, maxshift, maxshift);
4345
4346
4347 aap["tx"]=int(aap["tx"])+(int)ml[0];
4348 aap["ty"]=int(aap["ty"])+(int)ml[1];
4349 aap["tz"]=int(aap["tz"])+(int)ml[2];
4350 t.set_params(aap);
4351 EMData *st2=small_this->process("xform",Dict("transform",EMObject(&t),"zerocorners",1)); // we have to do 1 slow transform here now that we have the translation
4352
4353// float maxres = params.set_default("maxres",0.0f);
4354// float minres = params.set_default("minres",0.0f);
4355
4356 float sim=st2->cmp("fsc.tomo.auto",small_to,Dict("sigmaimg",sigmathisv,"sigmawith",sigmatov, "pmin", 4, "pmax",ny/3));
4357// float sim=st2->cmp("ccc.tomo.thresh",small_to,Dict("sigmaimg",sigmathis,"sigmawith",sigmato));
4358// printf("\nTESTORT %6.1f %6.1f %6.1f\t%4d %4d %4d\t%1.5g\t%1.5g %d (%d)",
4359// float(aap["az"]),float(aap["alt"]),float(aap["phi"]),int(aap["tx"]),int(aap["ty"]),int(aap["tz"]),sim,s_score[i],int(sim<s_score[i]),ccf->get_ysize());
4360
4361 delete ccf;
4362 // If the score is better than before, we update this particular best value
4363 if (sim<s_score[i]) {
4364 s_score[i]=sim;
4365 s_coverage[i]=st2->get_attr("fft_overlap");
4366 s_xform[i]=t;
4367 delete stt;
4368 delete sttsq;
4369 delete st2;
4370 return true;
4371 }
4372 delete stt;
4373 delete sttsq;
4374 delete st2;
4375 return false;
4376}
Dict params
Definition: aligner.h:147
Const iterator support for the Dict object This is just a wrapper, everything is inherited from the m...
Definition: emobject.h:674
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
iterator end()
Definition: emobject.cpp:1061
iterator begin()
Definition: emobject.cpp:1045
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
EMData stores an image's data and defines core image processing routines.
Definition: emdata.h:82
EMData * calc_ccf_masked(EMData *with, EMData *withsq=0, EMData *mask=0)
Calculate cross correlation between this and with where this is assumed to have had a mask applied to...
Definition: emdata.cpp:1600
EMObject is a wrapper class for types including int, float, double, etc as defined in ObjectType.
Definition: emobject.h:123
IntPoint defines an integer-coordinate point in a 1D/2D/3D space.
Definition: geometry.h:192
A Transform object is a somewhat specialized object designed specifically for EMAN2/Sparx storage of ...
Definition: transform.h:75
Dict get_params(const string &euler_type) const
Get the parameters of the entire transform, using a specific euler convention.
Definition: transform.cpp:479
Vec3f get_trans() const
Get the post trans as a vec3f.
Definition: transform.cpp:1046
void set_params(const Dict &d)
Set the parameters of the entire transform.
Definition: transform.cpp:254
Transform inverse() const
Get the inverse of this transformation matrix.
Definition: transform.cpp:1327
void set_trans(const float &x, const float &y, const float &z=0)
Set the post translation component.
Definition: transform.cpp:1036

References EMAN::Dict::begin(), EMAN::EMData::calc_ccf_masked(), EMAN::Dict::end(), EMAN::Transform::get_params(), EMAN::Transform::get_trans(), EMAN::Dict::has_key(), EMAN::Transform::inverse(), EMAN::Aligner::params, EMAN::Dict::set_default(), EMAN::Transform::set_params(), and EMAN::Transform::set_trans().

Referenced by xform_align_nbest().

◆ xform_align_nbest()

vector< Dict > RT3DLocalTreeAligner::xform_align_nbest ( EMData this_img,
EMData to_img,
const unsigned int  nsoln,
const string &  cmp_name,
const Dict cmp_params 
) const
virtual

See Aligner comments for more details.

Reimplemented from EMAN::Aligner.

Definition at line 3908 of file aligner.cpp.

3908 {
3909 if (nrsoln == 0) throw InvalidParameterException("ERROR (RT3DTreeAligner): nsoln must be >0"); // What was the user thinking?
3910
3911 int nsoln = nrsoln*2;
3912 if (nrsoln<32) nsoln=64; // we start with at least 32 solutions, but then gradually decrease with increasing scale
3913
3914 // !!!!!! IMPORTANT NOTE - we are inverting the order of this and to here to match convention in other aligners, to compensate
3915 // the Transform is inverted before being returned
3916 EMData *base_this;
3917 EMData *base_to;
3918 EMData *base_thissq;
3919 EMData *base_mask;
3920
3921 if (this_img->is_complex()) {
3922 base_to=this_img->copy();
3923 EMData *tmp = base_to->do_ift();
3924 tmp->process_inplace("threshold.notzero");
3925 base_mask=tmp->do_fft();
3926 delete tmp;
3927 }
3928 else {
3929 base_to=this_img->do_fft();
3930 base_to->process_inplace("xform.phaseorigin.tocorner");
3931 EMData *tmp = this_img->process("threshold.notzero");
3932 base_mask=tmp->do_fft();
3933 delete tmp;
3934 }
3935
3936 if (to->is_complex()) {
3937 base_this=to->copy();
3938 EMData *tmp = base_this->do_ift();
3939 tmp->process_inplace("math.squared");
3940 base_thissq = tmp->do_fft();
3941 delete tmp;
3942 }
3943 else {
3944 base_this=to->do_fft();
3945 base_this->process_inplace("xform.phaseorigin.tocorner");
3946 EMData *tmp = base_this->process("math.squared");
3947 base_thissq = tmp->do_fft();
3948 delete tmp;
3949 }
3950
3951 float sigmathis = params.set_default("sigmathis",0.01f);
3952 float sigmato = params.set_default("sigmato",0.01f);
3953 int verbose = params.set_default("verbose",0);
3954 float maxres = params.set_default("maxres",-1.0f);
3955
3956 if (base_this->get_xsize()!=base_this->get_ysize()+2 || base_this->get_ysize()!=base_this->get_zsize()
3957 || base_to->get_xsize()!=base_to->get_ysize()+2 || base_to->get_ysize()!=base_to->get_zsize()) throw InvalidCallException("ERROR (RT3DTreeAligner): requires cubic images with even numbered box sizes");
3958
3959// base_this->process_inplace("mask.wedgefill", Dict("thresh_sigma", sigmathis));
3960// base_to->process_inplace("mask.wedgefill", Dict("thresh_sigma", sigmato));
3961
3962
3963 base_this->process_inplace("xform.fourierorigin.tocenter"); // easier to chop out Fourier subvolumes
3964 base_to->process_inplace("xform.fourierorigin.tocenter");
3965 base_thissq->process_inplace("xform.fourierorigin.tocenter");
3966 base_mask->process_inplace("xform.fourierorigin.tocenter");
3967
3968 float apix=(float)this_img->get_attr("apix_x");
3969 int ny=this_img->get_ysize();
3970 params["boxsize"]=ny;
3971 int maxshift00=(int)params.set_default("maxshift",ny/4);
3972
3973 int maxny=ny;
3974 if (0)//maxres>0)
3975 maxny=4*int(ny*apix/maxres/2+1);
3976 if (verbose>0)
3977 printf("\n\n*******\nmax resolution %1.2f, box size %d\n", maxres, maxny);
3978
3979 float maxang=params.set_default("maxang",-1.0);
3980 Transform initxf;
3981
3982// int downsample=floor(ny/20); // Minimum shrunken box size is 20^3
3983
3984 vector<float> s_score(nsoln,0.0f);
3985 vector<float> s_coverage(nsoln,0.0f);
3986 vector<float> s_step(nsoln*3,7.5f);
3987 vector<Transform> s_xform(nsoln);
3988 if (verbose>0) printf("%d solutions\n",nsoln);
3989
3990
3991 int curiter=-1;
3992 int sexp_start=4;
3993 if (params.has_key("initxform")){
3994 const vector< Transform > xfs=params["initxform"];
3995 nsoln=xfs.size();
3996 initxf.set_params(xfs[0].get_params("eman"));
3997 for (unsigned int i=0; i<nsoln; i++){
3998 s_xform[i].set_params(xfs[i].get_params("eman"));
3999 }
4000 sexp_start=5;
4001 curiter=0;
4002// for (int i=0; i<nsoln*3; i++) {
4003// s_step[i]=.5;
4004// }
4005 }
4006
4007
4008// float dstep[3] = {7.5,7.5,7.5}; // we take steps for each of the 3 angles, may be positive or negative
4009 string axname[] = {"az","alt","phi"};
4010 int lastss=24;
4011 // We start with 32^3, 64^3 ...
4012 for (int sexp=sexp_start; sexp<10; sexp++) {
4013 curiter++;
4014// for (int sexp=4; sexp<5; sexp++) {
4015 int ss=pow(2.0,sexp);
4016 if (ss>maxny) ss=maxny;
4017 if (ss<24) ss=24; // 16 may be too small, but 32 takes too long...
4018 else if (ss<48) ss=48; // 16 may be too small, but 32 takes too long...
4019 if (verbose>0) printf("\nSize %d\n",ss);
4020
4021 int maxshift=maxshift00*ss/ny;
4022 if (maxshift00<0) maxshift=-1;
4023
4024 //ss=good_size(ny/ds);
4025 EMData *small_this=base_this->get_clip(Region(0,(ny-ss)/2,(ny-ss)/2,ss+2,ss,ss));
4026 EMData *small_to= base_to-> get_clip(Region(0,(ny-ss)/2,(ny-ss)/2,ss+2,ss,ss));
4027 EMData *small_thissq=base_thissq->get_clip(Region(0,(ny-ss)/2,(ny-ss)/2,ss+2,ss,ss));
4028 EMData *small_mask= base_mask-> get_clip(Region(0,(ny-ss)/2,(ny-ss)/2,ss+2,ss,ss));
4029 small_this->process_inplace("xform.fourierorigin.tocorner");
4030 small_this->process_inplace("filter.highpass.gauss",Dict("cutoff_pixels",4));
4031 small_to->process_inplace("xform.fourierorigin.tocorner");
4032 small_to->process_inplace("filter.highpass.gauss",Dict("cutoff_pixels",4));
4033 small_mask->process_inplace("xform.fourierorigin.tocorner");
4034 small_mask->process_inplace("filter.highpass.gauss",Dict("cutoff_pixels",4));
4035 small_thissq->process_inplace("xform.fourierorigin.tocorner");
4036 small_thissq->process_inplace("filter.highpass.gauss",Dict("cutoff_pixels",4));
4037
4038 if (ss<maxny){
4039 // skip lp filter at full sampling seems to help..
4040 small_this->process_inplace("filter.lowpass.gauss",Dict("cutoff_abs",0.33f));
4041 small_to->process_inplace("filter.lowpass.gauss",Dict("cutoff_abs",0.33f));
4042 }
4043
4044 // these are cached for speed in the comparator
4045 vector<float>sigmathisv=small_this->calc_radial_dist(ss/2,0,1,4);
4046 vector<float>sigmatov=small_to->calc_radial_dist(ss/2,0,1,4);
4047 for (int i=0; i<ss/2; i++) {
4048 sigmathisv[i]*=sigmathisv[i]*sigmathis;
4049 sigmatov[i]*=sigmatov[i]*sigmato;
4050 }
4051
4052 // This is a solid estimate for very complete searching, 2.5 is a bit arbitrary
4053 // make sure the altitude step hits 90 degrees, not absolutely necessary for this, but can't hurt
4054// float astep = 89.999/floor(pi/(2.5*2.0*atan(2.0/ss)));
4055 float astep = 89.999/floor(pi/(1.5*2.0*atan(2.0/ss)));
4056
4057 // This is drawn from single particle analysis testing, which in that case insures that enough sampling to
4058 // reasonably fill Fourier space is achieved, but doesn't perfectly apply to SPT
4059// float astep = (float)(89.99/ceil(90.0*9.0/(8.0*sqrt((float)(4300.0/ss))))); // 8 is (3+speed) from SPA with speed=5
4060
4061 // This insures we make at least one real effort at each level
4062 for (int i=0; i<s_score.size(); i++) {
4063 s_score[i]=1.0e24; // reset the scores since the different scales will not match
4064 if (fabs(s_step[i*3+0])<astep/4.0) s_step[i*3+0]*=2.0;
4065 if (fabs(s_step[i*3+1])<astep/4.0) s_step[i*3+1]*=2.0;
4066 if (fabs(s_step[i*3+2])<astep/4.0) s_step[i*3+2]*=2.0;
4067 }
4068
4069 // This is for the first loop, we do a full search in a heavily downsampled space
4070 if (curiter==0){ //s_coverage[0]==0.0f) {
4071 // Genrate points on a sphere in an asymmetric unit
4072 if (verbose>1) printf("stage 1 - ang step %1.2f\n",astep);
4073 Dict d;
4074 d["inc_mirror"] = true;
4075 d["delta"] = astep;
4076 Symmetry3D* sym = Factory<Symmetry3D>::get((string)params.set_default("sym","c1"));
4077 // We don't generate for phi, since this can produce a very large number of orientations
4078 vector<Transform> transforms = sym->gen_orientations((string)params.set_default("orientgen","eman"),d);
4079 if (verbose>0) printf("%d orientations to test (%lu)\n",(int)(transforms.size()*(360.0/astep)),transforms.size());
4080 if (transforms.size()<30) continue; // for very high symmetries we will go up to 32 instead of 24
4081
4082 // We iterate over all orientations in an asym triangle (alt & az) then deal with phi ourselves
4083// for (std::vector<Transform>::iterator t = transforms.begin(); t!=transforms.end(); ++t) { // iterator form was causing all sorts of problems
4084 for (unsigned int it=0; it<transforms.size(); it++) {
4085
4086 if (verbose>2) {
4087 printf(" %d/%lu \r",it,transforms.size());
4088 fflush(stdout);
4089 }
4090 for (float phi=0; phi<360.0; phi+=astep) {
4091 Transform t = transforms[it];
4092 Dict aap=t.get_params("eman");
4093 aap["phi"]=phi;
4094 aap["tx"]=0;
4095 aap["ty"]=0;
4096 aap["tz"]=0;
4097 t.set_params(aap);
4098 t.invert();
4099 aap=t.get_params("eman");
4100
4101 // somewhat strangely, rotations are actually much more expensive than FFTs, so we use a CCF for translation
4102 EMData *stt=small_this->process("xform",Dict("transform",EMObject(&t),"zerocorners",1));
4103 EMData *sttsq=small_thissq->process("xform",Dict("transform",EMObject(&t),"zerocorners",1));
4104// EMData *ccf=small_to->calc_ccf(stt);
4105 EMData *ccf=small_to->calc_ccf_masked(stt,sttsq,small_mask);
4106 IntPoint ml=ccf->calc_max_location_wrap();
4107
4108 aap["tx"]=(int)ml[0];
4109 aap["ty"]=(int)ml[1];
4110 aap["tz"]=(int)ml[2];
4111 t.set_params(aap);
4112 delete stt;
4113 delete sttsq;
4114 delete ccf;
4115 stt=small_this->process("xform",Dict("transform",EMObject(&t),"zerocorners",1)); // we have to do 1 slow transform here now that we have the translation
4116
4117// float sim=stt->cmp("ccc.tomo.thresh",small_to,Dict("sigmaimg",sigmathis,"sigmawith",sigmato));
4118 float sim=stt->cmp("ccc.tomo.thresh",small_to);
4119
4120// float sim=stt->cmp("fsc.tomo.auto",small_to,Dict("sigmaimg",sigmathisv,"sigmawith",sigmatov));
4121// float sim=stt->cmp("fsc.tomo.auto",small_to);
4122
4123 // We want to make sure our starting points are somewhat separated from each other, so we replace any angles too close to an existing angle
4124 // If we find an existing 'best' angle within range, then we either replace it or skip
4125 int worst=-1;
4126 float worstv=1.0e20;
4127 for (int i=0; i<nsoln; i++) {
4128 if (s_coverage[i]==0.0) continue; // hasn't been set yet
4129 Transform tdif=s_xform[i].inverse();
4130 tdif=tdif*t;
4131 float adif=tdif.get_rotation("spin")["omega"];
4132 if (adif<astep*2.5) {
4133 worst=i;
4134// printf("= %1.3f\n",adif);
4135 }
4136 }
4137
4138 // if we weren't close to an existing angle, then we find the lowest current score and use that
4139 if (worst==-1) {
4140 // First we find the worst solution in the list of possible best solutions, or the first
4141 // solution which is currently "empty"
4142 for (int i=0; i<nsoln; i++) {
4143 if (s_coverage[i]==0.0) { worst=i; break; }
4144 if (s_score[i]<worstv) {worst=i; worstv=s_score[i];}
4145 }
4146 }
4147
4148 // If the current solution is better than the 'worst' of the previous solutions, then we
4149 // displace it. Note that there is no sorting performed here
4150 if (sim<s_score[worst]) {
4151 s_score[worst]=sim;
4152 s_coverage[worst]=stt->get_attr("fft_overlap");
4153 s_xform[worst]=t;
4154 //printf("%f\t%f\t%d\n",s_score[worst],s_coverage[worst],worst);
4155 }
4156 delete stt;
4157 }
4158 }
4159 if (verbose>2) printf("\n");
4160// for (int i=0; i<nsoln; i++) {
4161// Dict d=s_xform[i].get_params("eman");
4162// printf("%d, %f, %f, %f, %f\n",i,(float)d["alt"], (float)d["az"], (float)d["phi"], s_score[i]);
4163// }
4164
4165 }
4166 // Once we have our initial list of best locations, we just refine each possibility individually
4167 else {
4168 // We generate a search pattern around each existing solution
4169 float res=float(ny)/float(ss)*apix*2;
4170 if (verbose>1) printf("stage 2 - maxres %1.2f, astep %1.2f\n",res, astep);
4171 if (ss>=maxny && params.has_key("initxform")){
4172 // last iteration, add back the initial transform so we do not do worse than the last run
4173 s_xform[nsoln]=initxf;
4174 nsoln+=1;
4175 }
4176
4177 for (int i=0; i<nsoln; i++) {
4178
4179 if (verbose>2) {
4180 printf(" %d\t%d\r",i,nsoln);
4181 fflush(stdout);
4182 }
4183 // We work an axis at a time until we get where we want to be. Somewhat like a simplex
4184 int changed=1;
4185 Dict upd;
4186 testort(small_this,small_to,small_mask,small_thissq,sigmathisv,sigmatov,s_score,s_coverage,s_xform,i,upd, initxf, maxshift);
4187 while (changed) {
4188 changed=0;
4189 for (int axis=0; axis<3; axis++) {
4190 if (fabs(s_step[i*3+axis])<astep/4.0) continue; // skip axes where we already have enough precision on this axis
4191 upd[axname[axis]]=s_step[i*3+axis];
4192 // when moving az, we move phi in the opposite direction by the same amount since the two are singular at alt=0
4193 // phi continues to move independently. I believe this should produce a more monotonic energy surface
4194 if (axis==0) upd[axname[2]]=-s_step[i*3+axis];
4195
4196 int r=testort(small_this,small_to,small_mask,small_thissq,sigmathisv,sigmatov,s_score,s_coverage,s_xform,i,upd, initxf, maxshift);
4197
4198 // If we fail, we reverse direction with a slightly smaller step and try that
4199 // Whether this fails or not, we move on to the next axis
4200 if (r) changed=1;
4201 else {
4202 s_step[i*3+axis]*=-0.75;
4203 upd[axname[axis]]=s_step[i*3+axis];
4204 r=testort(small_this,small_to,small_mask,small_thissq,sigmathisv,sigmatov,s_score,s_coverage,s_xform,i,upd, initxf, maxshift);
4205 if (r) changed=1;
4206 }
4207 if (verbose>4) printf("\nX %1.3f\t%1.3f\t%1.3f\t%d\t",s_step[i*3],s_step[i*3+1],s_step[i*3+2],changed);
4208 }
4209 if (verbose>3) {
4210 Dict aap=s_xform[i].get_params("eman");
4211 printf("\n%1.3f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\t%1.3f\t(%1.3f)",s_step[i*3],s_step[i*3+1],s_step[i*3+2],float(aap["az"]),float(aap["alt"]),float(aap["phi"]),s_score[i]);
4212 }
4213
4214 if (!changed) {
4215// for (int j=0; j<3; j++) s_step[i*3+j]*-0.75;
4216 changed=1;
4217 }
4218 if (fabs(s_step[i*3])<astep/4 && fabs(s_step[i*3+1])<astep/4 && fabs(s_step[i*3+2])<astep/4) changed=0;
4219 }
4220
4221 // Ouch, exhaustive (local) search
4222// for (int daz=-1; daz<=1; daz++) {
4223// for (int dalt=-1; dalt<=1; dalt++) {
4224// for (int dphi=-1; dphi<=1; dphi++) {
4225// Dict upd;
4226// upd["az"]=daz*astep;
4227// upd["alt"]=dalt*astep;
4228// upd["phi"]=dphi*astep;
4229// int r=testort(small_this,small_to,s_score,s_coverage,s_xform,i,upd);
4230// }
4231// }
4232// }
4233 }
4234 }
4235 // lazy earlier in defining s_ vectors, so lazy here too and inefficiently sorting
4236 // We are sorting inside the outermost loop so we can decrease the number of solutions
4237 // before we get to the finest precision
4238 for (unsigned int i=0; i<nsoln-1; i++) {
4239 for (unsigned int j=i+1; j<nsoln; j++) {
4240 if (s_score[i]>s_score[j]) {
4241 float t=s_score[i]; s_score[i]=s_score[j]; s_score[j]=t;
4242 t=s_coverage[i]; s_coverage[i]=s_coverage[j]; s_coverage[j]=t;
4243 Transform tt=s_xform[i]; s_xform[i]=s_xform[j]; s_xform[j]=tt;
4244 }
4245 }
4246 }
4247
4248 // At each level of sampling we (potentially) decrease the number of answers we check in detail
4249 // assuming we are gradually homing in on the best solution
4250 nsoln/=2;
4251 if (nsoln<nrsoln) nsoln=nrsoln;
4252
4253
4254 delete small_this;
4255 delete small_to;
4256 delete small_thissq;
4257 delete small_mask;
4258
4259 lastss=ss;
4260 if (ss>=maxny && curiter>0) break;
4261 }
4262
4263 delete base_this;
4264 delete base_to;
4265 delete base_thissq;
4266 delete base_mask;
4267
4268 // note the translations are wrong when the alignment stops before ss==ny
4269 if (lastss<ny){
4270 for (unsigned int i = 0; i < nrsoln; ++i ) {
4271 Transform tt=s_xform[i];
4272 Vec3f v=tt.get_trans();
4273 v=v*ny/lastss;
4274 tt.set_trans(v);
4275 s_xform[i]=tt;
4276
4277 }
4278 }
4279
4280 // initialize results
4281 vector<Dict> solns;
4282 for (unsigned int i = 0; i < nrsoln; ++i ) {
4283 Dict d;
4284 d["score"] = s_score[i];
4285 d["coverage"] = s_coverage[i];
4286 s_xform[i].invert(); // this is because we inverted the order of the input images above to match convention
4287 d["xform.align3d"] = &s_xform[i];
4288 solns.push_back(d);
4289 }
4290
4291 return solns;
4292}
virtual Dict get_params() const
Get the Aligner parameters in a key/value dictionary.
Definition: aligner.h:112
size_t size() const
Ask the Dictionary for its size.
Definition: emobject.h:519
EMData * get_clip(const Region &area, const float fill=0) const
Get an inclusive clip.
Definition: emdata.cpp:592
vector< float > calc_radial_dist(int n, float x0, float dx, int inten)
calculates radial distribution.
Definition: emdata.cpp:2781
static T * get(const string &instance_name)
Definition: emobject.h:781
bool testort(EMData *small_this, EMData *small_to, EMData *small_mask, EMData *small_thissq, vector< float > &sigmathisv, vector< float > &sigmatov, vector< float > &s_score, vector< float > &s_coverage, vector< Transform > &s_xform, int i, Dict &upd, Transform initxf, int maxshift) const
Definition: aligner.cpp:4296
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
Symmetry3D - A base class for 3D Symmetry objects.
Definition: symmetry.h:57
vector< Transform > gen_orientations(const string &generatorname="eman", const Dict &parms=Dict())
Ask the Symmetry3D object to generate a set of orientations in its asymmetric unit using an Orientati...
Definition: symmetry.cpp:167
Dict get_rotation(const string &euler_type="eman") const
Get a rotation in any Euler format.
Definition: transform.cpp:829
void invert()
Get the inverse of this transformation matrix.
Definition: transform.cpp:1293
#define InvalidParameterException(desc)
Definition: exception.h:361
#define InvalidCallException(desc)
Definition: exception.h:348

References EMAN::EMData::calc_ccf_masked(), EMAN::EMData::calc_radial_dist(), EMAN::Symmetry3D::gen_orientations(), EMAN::Factory< T >::get(), EMAN::EMData::get_clip(), EMAN::Aligner::get_params(), EMAN::Transform::get_params(), EMAN::Transform::get_rotation(), EMAN::Transform::get_trans(), EMAN::Dict::has_key(), InvalidCallException, InvalidParameterException, EMAN::Transform::inverse(), EMAN::Transform::invert(), EMAN::Aligner::params, EMAN::Dict::set_default(), EMAN::Transform::set_params(), EMAN::Transform::set_trans(), EMAN::Dict::size(), and testort().

Member Data Documentation

◆ NAME

const string RT3DLocalTreeAligner::NAME = "rotate_translate_3d_local_tree"
static

Definition at line 2012 of file aligner.h.

Referenced by get_name().


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