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

cmp.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033  *
00034  * */
00035 
00036 #include "cmp.h"
00037 #include "emdata.h"
00038 #include "ctf.h"
00039 #include "plugins/cmp_template.h"
00040 
00041 using namespace EMAN;
00042 
00043 const string CccCmp::NAME = "ccc";
00044 const string LodCmp::NAME = "lod";
00045 const string SqEuclideanCmp::NAME = "sqeuclidean";
00046 const string DotCmp::NAME = "dot";
00047 const string TomoCccCmp::NAME = "ccc.tomo";
00048 const string QuadMinDotCmp::NAME = "quadmindot";
00049 const string OptVarianceCmp::NAME = "optvariance";
00050 const string PhaseCmp::NAME = "phase";
00051 const string FRCCmp::NAME = "frc";
00052 
00053 template <> Factory < Cmp >::Factory()
00054 {
00055         force_add<CccCmp>();
00056         force_add<LodCmp>();
00057         force_add<SqEuclideanCmp>();
00058         force_add<DotCmp>();
00059         force_add<TomoCccCmp>();
00060         force_add<QuadMinDotCmp>();
00061         force_add<OptVarianceCmp>();
00062         force_add<PhaseCmp>();
00063         force_add<FRCCmp>();
00064 //      force_add<XYZCmp>();
00065 }
00066 
00067 void Cmp::validate_input_args(const EMData * image, const EMData *with) const
00068 {
00069         if (!image) {
00070                 throw NullPointerException("compared image");
00071         }
00072         if (!with) {
00073                 throw NullPointerException("compare-with image");
00074         }
00075 
00076         if (!EMUtil::is_same_size(image, with)) {
00077                 throw ImageFormatException( "images not same size");
00078         }
00079 
00080         float *d1 = image->get_data();
00081         if (!d1) {
00082                 throw NullPointerException("image contains no data");
00083         }
00084 
00085         float *d2 = with->get_data();
00086         if (!d2) {
00087                 throw NullPointerException("compare-with image data");
00088         }
00089 }
00090 
00091 //  It would be good to add code for complex images!  PAP
00092 float CccCmp::cmp(EMData * image, EMData *with) const
00093 {
00094         ENTERFUNC;
00095         if (image->is_complex() || with->is_complex())
00096                 throw ImageFormatException( "Complex images not supported by CMP::CccCmp");
00097         validate_input_args(image, with);
00098 
00099         const float *const d1 = image->get_const_data();
00100         const float *const d2 = with->get_const_data();
00101 
00102         float negative = (float)params.set_default("negative", 1);
00103         if (negative) negative=-1.0; else negative=1.0;
00104 
00105         double avg1 = 0.0, var1 = 0.0, avg2 = 0.0, var2 = 0.0, ccc = 0.0;
00106         long n = 0;
00107         size_t totsize = image->get_xsize()*image->get_ysize()*image->get_zsize();
00108 
00109         bool has_mask = false;
00110         EMData* mask = 0;
00111         if (params.has_key("mask")) {
00112                 mask = params["mask"];
00113                 if(mask!=0) {has_mask=true;}
00114         }
00115 
00116         if (has_mask) {
00117                 const float *const dm = mask->get_const_data();
00118                 for (size_t i = 0; i < totsize; ++i) {
00119                         if (dm[i] > 0.5) {
00120                                 avg1 += double(d1[i]);
00121                                 var1 += d1[i]*double(d1[i]);
00122                                 avg2 += double(d2[i]);
00123                                 var2 += d2[i]*double(d2[i]);
00124                                 ccc += d1[i]*double(d2[i]);
00125                                 n++;
00126                         }
00127                 }
00128         } else {
00129                 for (size_t i = 0; i < totsize; ++i) {
00130                         avg1 += double(d1[i]);
00131                         var1 += d1[i]*double(d1[i]);
00132                         avg2 += double(d2[i]);
00133                         var2 += d2[i]*double(d2[i]);
00134                         ccc += d1[i]*double(d2[i]);
00135                 }
00136                 n = totsize;
00137         }
00138 
00139         avg1 /= double(n);
00140         var1 = var1/double(n) - avg1*avg1;
00141         avg2 /= double(n);
00142         var2 = var2/double(n) - avg2*avg2;
00143         ccc = ccc/double(n) - avg1*avg2;
00144         ccc /= sqrt(var1*var2);
00145         ccc *= negative;
00146         return static_cast<float>(ccc);
00147         EXITFUNC;
00148 }
00149 
00150 
00151 // Added by JAK 11/12/10
00152 // L^1-norm difference of two maps, after normalization.
00153 float LodCmp::cmp(EMData * image, EMData *with) const
00154 {
00155         ENTERFUNC;
00156         if (image->is_complex() || with->is_complex())
00157                 throw ImageFormatException( "Complex images not yet supported by CMP::LodCmp");
00158         validate_input_args(image, with);
00159 
00160         const float *const d1 = image->get_const_data();
00161         const float *const d2 = with->get_const_data();
00162 
00163         float negative = (float)params.set_default("negative", 1);
00164         if (negative) negative=-1.0; else negative=1.0;
00165 
00166         double avg1 = 0.0, sig1 = 0.0, avg2 = 0.0, sig2 = 0.0, lod = 0.0;
00167         long n = 0;
00168         size_t totsize = image->get_xsize()*image->get_ysize()*image->get_zsize();
00169         size_t i;
00170         
00171         bool has_mask = false;
00172         EMData* mask = 0;
00173         if (params.has_key("mask")) {
00174                 mask = params["mask"];
00175                 if(mask!=0) {has_mask=true;}
00176         }
00177 
00178         int normalize = 0;
00179         if (params.has_key("normalize")) {
00180                 normalize = params["normalize"];
00181         }
00182 
00183         if (normalize) {
00184                 if (has_mask) {
00185                         const float *const dm = mask->get_const_data();
00186                         for (i = 0; i < totsize; ++i) {
00187                                 if (dm[i] > 0.5) {
00188                                         avg1 += double(d1[i]);
00189                                         avg2 += double(d2[i]);
00190                                         n++;
00191                                 }
00192                         }
00193                 } else {
00194                         for (i = 0; i < totsize; ++i) {
00195                                 avg1 += double(d1[i]);
00196                                 avg2 += double(d2[i]);
00197                         }
00198                         n = totsize;
00199                 }
00200 
00201                 avg1 /= double(n);
00202                 avg2 /= double(n);
00203 
00204                 if (has_mask) {
00205                         const float *const dm = mask->get_const_data();
00206                         for (i = 0; i < totsize; ++i) {
00207                                 if (dm[i] > 0.5) {
00208                                         sig1 += fabs(double(d1[i])-avg1);
00209                                         sig2 += fabs(double(d2[i])-avg2);
00210                                 }
00211                         }
00212                 } else {
00213                         for (i = 0; i < totsize; ++i) {
00214                                 sig1 += fabs(double(d1[i])-avg1);
00215                                 sig2 += fabs(double(d2[i])-avg2);
00216                         }
00217                 }
00218         } else {
00219                 avg1 = 0.0; avg2 = 0.0;
00220                 sig1 = 1.0; sig2 = 1.0;
00221         }
00222 
00223         if (has_mask) {
00224                 const float *const dm = mask->get_const_data();
00225                 for (i = 0; i < totsize; ++i) {
00226                         if (dm[i] > 0.5) {
00227                                 lod += fabs((double(d1[i])-avg1)/sig1 - (double(d2[i])-avg2)/sig2);
00228                         }
00229                 }
00230         } else {
00231                 for (i = 0; i < totsize; ++i) {
00232                         lod += fabs((double(d1[i])-avg1)/sig1 - (double(d2[i])-avg2)/sig2);
00233                 }
00234         }
00235         
00236         lod *= (-0.5);
00237         lod *= negative;
00238         return static_cast<float>(lod);
00239         EXITFUNC;
00240 }
00241 
00242 
00243 //float SqEuclideanCmp::cmp(EMData * image, EMData *withorig) const
00244 float SqEuclideanCmp::cmp(EMData *image,EMData * withorig ) const
00245 {
00246         ENTERFUNC;
00247         EMData *with = withorig;
00248         validate_input_args(image, with);
00249 
00250         int zeromask = params.set_default("zeromask",0);
00251         int normto = params.set_default("normto",0);
00252 
00253         if (normto) {
00254                 if (zeromask) with = withorig->process("normalize.toimage",Dict("to",image));
00255                 else with = withorig->process("normalize.toimage",Dict("to",image,"ignore_zero",0));
00256                 with->set_attr("deleteme",1);
00257                 if ((float)(with->get_attr("norm_mult"))<=0) {          // This means the normalization inverted the image, a clear probablity of noise bias, so we undo the normalization
00258                         delete with;
00259                         with=withorig;
00260                 }
00261         }
00262 
00263         const float *const y_data = with->get_const_data();
00264         const float *const x_data = image->get_const_data();
00265         double result = 0.;
00266         float n = 0.0f;
00267         if(image->is_complex() && with->is_complex()) {
00268         // Implemented by PAP  01/09/06 - please do not change.  If in doubts, write/call me.
00269                 int nx  = with->get_xsize();
00270                 int ny  = with->get_ysize();
00271                 int nz  = with->get_zsize();
00272                 nx = (nx - 2 + with->is_fftodd()); // nx is the real-space size of the input image
00273                 int lsd2 = (nx + 2 - nx%2) ; // Extended x-dimension of the complex image
00274 
00275                 int ixb = 2*((nx+1)%2);
00276                 int iyb = ny%2;
00277                 //
00278                 if(nz == 1) {
00279                 //  it looks like it could work in 3D, but it is not, really.
00280                 for ( int iz = 0; iz <= nz-1; iz++) {
00281                         double part = 0.;
00282                         for ( int iy = 0; iy <= ny-1; iy++) {
00283                                 for ( int ix = 2; ix <= lsd2 - 1 - ixb; ix++) {
00284                                                 size_t ii = ix + (iy  + iz * ny)* lsd2;
00285                                                 part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00286                                 }
00287                         }
00288                         for ( int iy = 1; iy <= ny/2-1 + iyb; iy++) {
00289                                 size_t ii = (iy  + iz * ny)* lsd2;
00290                                 part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00291                                 part += (x_data[ii+1] - y_data[ii+1])*double(x_data[ii+1] - y_data[ii+1]);
00292                         }
00293                         if(nx%2 == 0) {
00294                                 for ( int iy = 1; iy <= ny/2-1 + iyb; iy++) {
00295                                         size_t ii = lsd2 - 2 + (iy  + iz * ny)* lsd2;
00296                                         part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00297                                         part += (x_data[ii+1] - y_data[ii+1])*double(x_data[ii+1] - y_data[ii+1]);
00298                                 }
00299 
00300                         }
00301                         part *= 2;
00302                         part += (x_data[0] - y_data[0])*double(x_data[0] - y_data[0]);
00303                         if(ny%2 == 0) {
00304                                 int ii = (ny/2  + iz * ny)* lsd2;
00305                                 part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00306                         }
00307                         if(nx%2 == 0) {
00308                                 int ii = lsd2 - 2 + (0  + iz * ny)* lsd2;
00309                                 part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00310                                 if(ny%2 == 0) {
00311                                         int ii = lsd2 - 2 +(ny/2  + iz * ny)* lsd2;
00312                                         part += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00313                                 }
00314                         }
00315                         result += part;
00316                 }
00317                 n = (float)nx*(float)ny*(float)nz*(float)nx*(float)ny*(float)nz;
00318 
00319                 }else{ //This 3D code is incorrect, but it is the best I can do now 01/09/06 PAP
00320                 int ky, kz;
00321                 int ny2 = ny/2; int nz2 = nz/2;
00322                 for ( int iz = 0; iz <= nz-1; iz++) {
00323                         if(iz>nz2) kz=iz-nz; else kz=iz;
00324                         for ( int iy = 0; iy <= ny-1; iy++) {
00325                                 if(iy>ny2) ky=iy-ny; else ky=iy;
00326                                 for ( int ix = 0; ix <= lsd2-1; ix++) {
00327                                 // Skip Friedel related values
00328                                 if(ix>0 || (kz>=0 && (ky>=0 || kz!=0))) {
00329                                                 size_t ii = ix + (iy  + iz * ny)* lsd2;
00330                                                 result += (x_data[ii] - y_data[ii])*double(x_data[ii] - y_data[ii]);
00331                                         }
00332                                 }
00333                         }
00334                 }
00335                 n = ((float)nx*(float)ny*(float)nz*(float)nx*(float)ny*(float)nz)/2.0f;
00336                 }
00337         } else {                // real space
00338                 size_t totsize = image->get_xsize()*image->get_ysize()*image->get_zsize();
00339                 if (params.has_key("mask")) {
00340                   EMData* mask;
00341                   mask = params["mask"];
00342                   const float *const dm = mask->get_const_data();
00343                   for (size_t i = 0; i < totsize; i++) {
00344                            if (dm[i] > 0.5) {
00345                                 double temp = x_data[i]- y_data[i];
00346                                 result += temp*temp;
00347                                 n++;
00348                            }
00349                   }
00350                 } 
00351                 else if (zeromask) {
00352                         n=0;
00353                         for (size_t i = 0; i < totsize; i++) {
00354                                 if (x_data[i]==0 || y_data[i]==0) continue;
00355                                 double temp = x_data[i]- y_data[i];
00356                                 result += temp*temp;
00357                                 n++;
00358                         }
00359                         
00360                 }
00361                 else {
00362                   for (size_t i = 0; i < totsize; i++) {
00363                                 double temp = x_data[i]- y_data[i];
00364                                 result += temp*temp;
00365                    }
00366                    n = (float)totsize;
00367                 }
00368         }
00369         result/=n;
00370 
00371         EXITFUNC;
00372         if (with->has_attr("deleteme")) delete with;
00373         float ret = (float)result;
00374         if (!Util::goodf(&ret)) return FLT_MAX;
00375         return ret;
00376 }
00377 
00378 
00379 // Even though this uses doubles, it might be wise to recode it row-wise
00380 // to avoid numerical errors on large images
00381 float DotCmp::cmp(EMData* image, EMData* with) const
00382 {
00383         ENTERFUNC;
00384         validate_input_args(image, with);
00385 
00386         const float *const x_data = image->get_const_data();
00387         const float *const y_data = with->get_const_data();
00388 
00389         int normalize = params.set_default("normalize", 0);
00390         float negative = (float)params.set_default("negative", 1);
00391 
00392         if (negative) negative=-1.0; else negative=1.0;
00393         double result = 0.;
00394         long n = 0;
00395         if(image->is_complex() && with->is_complex()) {
00396         // Implemented by PAP  01/09/06 - please do not change.  If in doubts, write/call me.
00397                 int nx  = with->get_xsize();
00398                 int ny  = with->get_ysize();
00399                 int nz  = with->get_zsize();
00400                 nx = (nx - 2 + with->is_fftodd()); // nx is the real-space size of the input image
00401                 int lsd2 = (nx + 2 - nx%2) ; // Extended x-dimension of the complex image
00402 
00403                 int ixb = 2*((nx+1)%2);
00404                 int iyb = ny%2;
00405                 //
00406                 if(nz == 1) {
00407                 //  it looks like it could work in 3D, but does not
00408                 for ( int iz = 0; iz <= nz-1; ++iz) {
00409                         double part = 0.;
00410                         for ( int iy = 0; iy <= ny-1; ++iy) {
00411                                 for ( int ix = 2; ix <= lsd2 - 1 - ixb; ++ix) {
00412                                         size_t ii = ix + (iy  + iz * ny)* lsd2;
00413                                         part += x_data[ii] * double(y_data[ii]);
00414                                 }
00415                         }
00416                         for ( int iy = 1; iy <= ny/2-1 + iyb; ++iy) {
00417                                 size_t ii = (iy  + iz * ny)* lsd2;
00418                                 part += x_data[ii] * double(y_data[ii]);
00419                                 part += x_data[ii+1] * double(y_data[ii+1]);
00420                         }
00421                         if(nx%2 == 0) {
00422                                 for ( int iy = 1; iy <= ny/2-1 + iyb; ++iy) {
00423                                         size_t ii = lsd2 - 2 + (iy  + iz * ny)* lsd2;
00424                                         part += x_data[ii] * double(y_data[ii]);
00425                                         part += x_data[ii+1] * double(y_data[ii+1]);
00426                                 }
00427 
00428                         }
00429                         part *= 2;
00430                         part += x_data[0] * double(y_data[0]);
00431                         if(ny%2 == 0) {
00432                                 size_t ii = (ny/2  + iz * ny)* lsd2;
00433                                 part += x_data[ii] * double(y_data[ii]);
00434                         }
00435                         if(nx%2 == 0) {
00436                                 size_t ii = lsd2 - 2 + (0  + iz * ny)* lsd2;
00437                                 part += x_data[ii] * double(y_data[ii]);
00438                                 if(ny%2 == 0) {
00439                                         int ii = lsd2 - 2 +(ny/2  + iz * ny)* lsd2;
00440                                         part += x_data[ii] * double(y_data[ii]);
00441                                 }
00442                         }
00443                         result += part;
00444                 }
00445                 if( normalize ) {
00446                 //  it looks like it could work in 3D, but does not
00447                 double square_sum1 = 0., square_sum2 = 0.;
00448                 for ( int iz = 0; iz <= nz-1; ++iz) {
00449                         for ( int iy = 0; iy <= ny-1; ++iy) {
00450                                 for ( int ix = 2; ix <= lsd2 - 1 - ixb; ++ix) {
00451                                         size_t ii = ix + (iy  + iz * ny)* lsd2;
00452                                         square_sum1 += x_data[ii] * double(x_data[ii]);
00453                                         square_sum2 += y_data[ii] * double(y_data[ii]);
00454                                 }
00455                         }
00456                         for ( int iy = 1; iy <= ny/2-1 + iyb; ++iy) {
00457                                 size_t ii = (iy  + iz * ny)* lsd2;
00458                                 square_sum1 += x_data[ii] * double(x_data[ii]);
00459                                 square_sum1 += x_data[ii+1] * double(x_data[ii+1]);
00460                                 square_sum2 += y_data[ii] * double(y_data[ii]);
00461                                 square_sum2 += y_data[ii+1] * double(y_data[ii+1]);
00462                         }
00463                         if(nx%2 == 0) {
00464                                 for ( int iy = 1; iy <= ny/2-1 + iyb; ++iy) {
00465                                         size_t ii = lsd2 - 2 + (iy  + iz * ny)* lsd2;
00466                                         square_sum1 += x_data[ii] * double(x_data[ii]);
00467                                         square_sum1 += x_data[ii+1] * double(x_data[ii+1]);
00468                                         square_sum2 += y_data[ii] * double(y_data[ii]);
00469                                         square_sum2 += y_data[ii+1] * double(y_data[ii+1]);
00470                                 }
00471 
00472                         }
00473                         square_sum1 *= 2;
00474                         square_sum1 += x_data[0] * double(x_data[0]);
00475                         square_sum2 *= 2;
00476                         square_sum2 += y_data[0] * double(y_data[0]);
00477                         if(ny%2 == 0) {
00478                                 int ii = (ny/2  + iz * ny)* lsd2;
00479                                 square_sum1 += x_data[ii] * double(x_data[ii]);
00480                                 square_sum2 += y_data[ii] * double(y_data[ii]);
00481                         }
00482                         if(nx%2 == 0) {
00483                                 int ii = lsd2 - 2 + (0  + iz * ny)* lsd2;
00484                                 square_sum1 += x_data[ii] * double(x_data[ii]);
00485                                 square_sum2 += y_data[ii] * double(y_data[ii]);
00486                                 if(ny%2 == 0) {
00487                                         int ii = lsd2 - 2 +(ny/2  + iz * ny)* lsd2;
00488                                         square_sum1 += x_data[ii] * double(x_data[ii]);
00489                                         square_sum2 += y_data[ii] * double(y_data[ii]);
00490                                 }
00491                         }
00492                 }
00493                 result /= sqrt(square_sum1*square_sum2);
00494                 } else  result /= ((float)nx*(float)ny*(float)nz*(float)nx*(float)ny*(float)nz);
00495 
00496                 } else { //This 3D code is incorrect, but it is the best I can do now 01/09/06 PAP
00497                 int ky, kz;
00498                 int ny2 = ny/2; int nz2 = nz/2;
00499                 for ( int iz = 0; iz <= nz-1; ++iz) {
00500                         if(iz>nz2) kz=iz-nz; else kz=iz;
00501                         for ( int iy = 0; iy <= ny-1; ++iy) {
00502                                 if(iy>ny2) ky=iy-ny; else ky=iy;
00503                                 for ( int ix = 0; ix <= lsd2-1; ++ix) {
00504                                         // Skip Friedel related values
00505                                         if(ix>0 || (kz>=0 && (ky>=0 || kz!=0))) {
00506                                                 size_t ii = ix + (iy  + iz * ny)* lsd2;
00507                                                 result += x_data[ii] * double(y_data[ii]);
00508                                         }
00509                                 }
00510                         }
00511                 }
00512                 if( normalize ) {
00513                 //  still incorrect
00514                 double square_sum1 = 0., square_sum2 = 0.;
00515                 int ky, kz;
00516                 int ny2 = ny/2; int nz2 = nz/2;
00517                 for ( int iz = 0; iz <= nz-1; ++iz) {
00518                         if(iz>nz2) kz=iz-nz; else kz=iz;
00519                         for ( int iy = 0; iy <= ny-1; ++iy) {
00520                                 if(iy>ny2) ky=iy-ny; else ky=iy;
00521                                 for ( int ix = 0; ix <= lsd2-1; ++ix) {
00522                                         // Skip Friedel related values
00523                                         if(ix>0 || (kz>=0 && (ky>=0 || kz!=0))) {
00524                                                 size_t ii = ix + (iy  + iz * ny)* lsd2;
00525                                                 square_sum1 += x_data[ii] * double(x_data[ii]);
00526                                                 square_sum2 += y_data[ii] * double(y_data[ii]);
00527                                         }
00528                                 }
00529                         }
00530                 }
00531                 result /= sqrt(square_sum1*square_sum2);
00532                 } else result /= ((float)nx*(float)ny*(float)nz*(float)nx*(float)ny*(float)nz/2);
00533                 }
00534         } else {
00535                 size_t totsize = image->get_xsize() * image->get_ysize() * image->get_zsize();
00536 
00537                 double square_sum1 = 0., square_sum2 = 0.;
00538 
00539                 if (params.has_key("mask")) {
00540                         EMData* mask;
00541                         mask = params["mask"];
00542                         const float *const dm = mask->get_const_data();
00543                         if (normalize) {
00544                                 for (size_t i = 0; i < totsize; i++) {
00545                                         if (dm[i] > 0.5) {
00546                                                 square_sum1 += x_data[i]*double(x_data[i]);
00547                                                 square_sum2 += y_data[i]*double(y_data[i]);
00548                                                 result += x_data[i]*double(y_data[i]);
00549                                         }
00550                                 }
00551                         } else {
00552                                 for (size_t i = 0; i < totsize; i++) {
00553                                         if (dm[i] > 0.5) {
00554                                                 result += x_data[i]*double(y_data[i]);
00555                                                 n++;
00556                                         }
00557                                 }
00558                         }
00559                 } else {
00560                         // this little bit of manual loop unrolling makes the dot product as fast as sqeuclidean with -O2
00561                         for (size_t i=0; i<totsize; i++) result+=x_data[i]*y_data[i];
00562 
00563                         if (normalize) {
00564                                 square_sum1 = image->get_attr("square_sum");
00565                                 square_sum2 = with->get_attr("square_sum");
00566                         } else n = totsize;
00567                 }
00568                 if (normalize) result /= (sqrt(square_sum1*square_sum2)); else result /= n;
00569         }
00570 
00571 
00572         EXITFUNC;
00573         return (float) (negative*result);
00574 }
00575 
00576 // This implements the technique of Mike Schmid where by the cross correlation is normalized
00577 // in an effort to remove the effects of the missing wedge. Somewhat of a heuristic solution, but it seems
00578 // to work. Basiaclly it relies on the observation that 'good' matchs will conentrate the correlation
00579 // signal in the peak, wheras 'bad' correlations will distribute the signal.
00580 // John Flanagan 18-10-2010
00581 
00582 float TomoCccCmp::cmp(EMData * image, EMData *with) const
00583 {
00584         ENTERFUNC;
00585         EMData* ccf = params.set_default("ccf",(EMData*) NULL);
00586         bool ccf_ownership = false;
00587         if (!ccf) {
00588                 ccf = image->calc_ccf(with);
00589                 ccf_ownership = true;
00590         }
00591         bool norm = params.set_default("norm",true);
00592         bool zeroori = params.set_default("zeroori",false);
00593         
00594         if (norm) ccf->process_inplace("normalize");
00595 
00596         IntPoint point;
00597         if (zeroori) {
00598                 point[0] = 0; point[1] = 0; point[2] = 0;
00599         } else {
00600                 int searchx = params.set_default("searchx",-1); 
00601                 int searchy = params.set_default("searchy",-1); 
00602                 int searchz = params.set_default("searchz",-1);
00603                 point = ccf->calc_max_location_wrap(searchx,searchy,searchz);
00604         }
00605         
00606         //this is to prevent us from doing a ccf twice
00607         float tx = (float)point[0]; float ty = (float)point[1]; float tz = (float)point[2];
00608         image->set_attr("tx", tx);
00609         image->set_attr("ty", ty);
00610         image->set_attr("tz", tz);
00611         
00612         float best_score = ccf->get_value_at_wrap(tx,ty,tz);
00613         if (ccf_ownership) delete ccf; ccf = 0;
00614         
00615         return -best_score;
00616 
00617 }
00618 
00619 // Even though this uses doubles, it might be wise to recode it row-wise
00620 // to avoid numerical errors on large images
00621 float QuadMinDotCmp::cmp(EMData * image, EMData *with) const
00622 {
00623         ENTERFUNC;
00624         validate_input_args(image, with);
00625 
00626         if (image->get_zsize()!=1) throw InvalidValueException(0, "QuadMinDotCmp supports 2D only");
00627 
00628         int nx=image->get_xsize();
00629         int ny=image->get_ysize();
00630 
00631         int normalize = params.set_default("normalize", 0);
00632         float negative = (float)params.set_default("negative", 1);
00633 
00634         if (negative) negative=-1.0; else negative=1.0;
00635 
00636         double result[4] = { 0,0,0,0 }, sq1[4] = { 0,0,0,0 }, sq2[4] = { 0,0,0,0 } ;
00637 
00638         vector<int> image_saved_offsets = image->get_array_offsets();
00639         vector<int> with_saved_offsets = with->get_array_offsets();
00640         image->set_array_offsets(-nx/2,-ny/2);
00641         with->set_array_offsets(-nx/2,-ny/2);
00642         int i,x,y;
00643         for (y=-ny/2; y<ny/2; y++) {
00644                 for (x=-nx/2; x<nx/2; x++) {
00645                         int quad=(x<0?0:1) + (y<0?0:2);
00646                         result[quad]+=(*image)(x,y)*(*with)(x,y);
00647                         if (normalize) {
00648                                 sq1[quad]+=(*image)(x,y)*(*image)(x,y);
00649                                 sq2[quad]+=(*with)(x,y)*(*with)(x,y);
00650                         }
00651                 }
00652         }
00653         image->set_array_offsets(image_saved_offsets);
00654         with->set_array_offsets(with_saved_offsets);
00655 
00656         if (normalize) {
00657                 for (i=0; i<4; i++) result[i]/=sqrt(sq1[i]*sq2[i]);
00658         } else {
00659                 for (i=0; i<4; i++) result[i]/=nx*ny/4;
00660         }
00661 
00662         float worst=static_cast<float>(result[0]);
00663         for (i=1; i<4; i++) if (static_cast<float>(result[i])<worst) worst=static_cast<float>(result[i]);
00664 
00665         EXITFUNC;
00666         return (float) (negative*worst);
00667 }
00668 
00669 float OptVarianceCmp::cmp(EMData * image, EMData *with) const
00670 {
00671         ENTERFUNC;
00672         validate_input_args(image, with);
00673 
00674         int keepzero = params.set_default("keepzero", 1);
00675         int invert = params.set_default("invert",0);
00676         int matchfilt = params.set_default("matchfilt",1);
00677         int matchamp = params.set_default("matchamp",0);
00678         int radweight = params.set_default("radweight",0);
00679         int dbug = params.set_default("debug",0);
00680 
00681         size_t size = image->get_xsize() * image->get_ysize() * image->get_zsize();
00682 
00683 
00684         EMData *with2=NULL;
00685         if (matchfilt) {
00686                 EMData *a = image->do_fft();
00687                 EMData *b = with->do_fft();
00688 
00689                 vector <float> rfa=a->calc_radial_dist(a->get_ysize()/2,0.0f,1.0f,1);
00690                 vector <float> rfb=b->calc_radial_dist(b->get_ysize()/2,0.0f,1.0f,1);
00691 
00692                 float avg=0;
00693                 for (size_t i=0; i<a->get_ysize()/2.0f; i++) {
00694                         rfa[i]=(rfb[i]==0?0.0f:(rfa[i]/rfb[i]));
00695                         avg+=rfa[i];
00696                 }
00697 
00698                 avg/=a->get_ysize()/2.0f;
00699                 for (size_t i=0; i<a->get_ysize()/2.0f; i++) {
00700                         if (rfa[i]>avg*10.0) rfa[i]=10.0;                       // If some particular location has a small but non-zero value, we don't want to overcorrect it
00701                 }
00702                 rfa[0]=0.0;
00703 
00704                 if (dbug) b->write_image("a.hdf",-1);
00705 
00706                 b->apply_radial_func(0.0f,1.0f/a->get_ysize(),rfa);
00707                 with2=b->do_ift();
00708 
00709                 if (dbug) b->write_image("a.hdf",-1);
00710                 if (dbug) a->write_image("a.hdf",-1);
00711 
00712 /*              if (dbug) {
00713                         FILE *out=fopen("a.txt","w");
00714                         for (int i=0; i<a->get_ysize()/2.0; i++) fprintf(out,"%d\t%f\n",i,rfa[i]);
00715                         fclose(out);
00716 
00717                         out=fopen("b.txt","w");
00718                         for (int i=0; i<a->get_ysize()/2.0; i++) fprintf(out,"%d\t%f\n",i,rfb[i]);
00719                         fclose(out);
00720                 }*/
00721 
00722 
00723                 delete a;
00724                 delete b;
00725 
00726                 if (dbug) {
00727                         with2->write_image("a.hdf",-1);
00728                         image->write_image("a.hdf",-1);
00729                 }
00730 
00731 //              with2->process_inplace("matchfilt",Dict("to",this));
00732 //              x_data = with2->get_data();
00733         }
00734 
00735         // This applies the individual Fourier amplitudes from 'image' and
00736         // applies them to 'with'
00737         if (matchamp) {
00738                 EMData *a = image->do_fft();
00739                 EMData *b = with->do_fft();
00740                 size_t size2 = a->get_xsize() * a->get_ysize() * a->get_zsize();
00741 
00742                 a->ri2ap();
00743                 b->ri2ap();
00744 
00745                 const float *const ad=a->get_const_data();
00746                 float * bd=b->get_data();
00747 
00748                 for (size_t i=0; i<size2; i+=2) bd[i]=ad[i];
00749                 b->update();
00750 
00751                 b->ap2ri();
00752                 with2=b->do_ift();
00753 //with2->write_image("a.hdf",-1);
00754                 delete a;
00755                 delete b;
00756         }
00757 
00758         const float * x_data;
00759         if (with2) x_data=with2->get_const_data();
00760         else x_data = with->get_const_data();
00761         const float *const y_data = image->get_const_data();
00762 
00763         size_t nx = image->get_xsize();
00764         float m = 0;
00765         float b = 0;
00766 
00767         // This will write the x vs y file used to calculate the density
00768         // optimization. This behavior may change in the future
00769         if (dbug) {
00770                 FILE *out=fopen("dbug.optvar.txt","w");
00771                 if (out) {
00772                         for (size_t i=0; i<size; i++) {
00773                                 if ( !keepzero || (x_data[i] && y_data[i])) fprintf(out,"%g\t%g\n",x_data[i],y_data[i]);
00774                         }
00775                         fclose(out);
00776                 }
00777         }
00778 
00779 
00780         Util::calc_least_square_fit(size, x_data, y_data, &m, &b, keepzero);
00781         if (m == 0) {
00782                 m = FLT_MIN;
00783         }
00784         b = -b / m;
00785         m = 1.0f / m;
00786 
00787         // While negative slopes are really not a valid comparison in most cases, we
00788         // still want to detect these instances, so this if is removed
00789 /*      if (m < 0) {
00790                 b = 0;
00791                 m = 1000.0;
00792         }*/
00793 
00794         double  result = 0;
00795         int count = 0;
00796 
00797         if (radweight) {
00798                 if (image->get_zsize()!=1) throw ImageDimensionException("radweight option is 2D only");
00799                 if (keepzero) {
00800                         for (size_t i = 0,y=0; i < size; y++) {
00801                                 for (size_t x=0; x<nx; i++,x++) {
00802                                         if (y_data[i] && x_data[i]) {
00803 #ifdef  _WIN32
00804                                                 if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m)*(_hypot((float)x,(float)y)+nx/4.0);
00805                                                 else result += Util::square((x_data[i] * m) + b - y_data[i])*(_hypot((float)x,(float)y)+nx/4.0);
00806 #else
00807                                                 if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m)*(hypot((float)x,(float)y)+nx/4.0);
00808                                                 else result += Util::square((x_data[i] * m) + b - y_data[i])*(hypot((float)x,(float)y)+nx/4.0);
00809 #endif
00810                                                 count++;
00811                                         }
00812                                 }
00813                         }
00814                         result/=count;
00815                 }
00816                 else {
00817                         for (size_t i = 0,y=0; i < size; y++) {
00818                                 for (size_t x=0; x<nx; i++,x++) {
00819 #ifdef  _WIN32
00820                                         if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m)*(_hypot((float)x,(float)y)+nx/4.0);
00821                                         else result += Util::square((x_data[i] * m) + b - y_data[i])*(_hypot((float)x,(float)y)+nx/4.0);
00822 #else
00823                                         if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m)*(hypot((float)x,(float)y)+nx/4.0);
00824                                         else result += Util::square((x_data[i] * m) + b - y_data[i])*(hypot((float)x,(float)y)+nx/4.0);
00825 #endif
00826                                 }
00827                         }
00828                         result = result / size;
00829                 }
00830         }
00831         else {
00832                 if (keepzero) {
00833                         for (size_t i = 0; i < size; i++) {
00834                                 if (y_data[i] && x_data[i]) {
00835                                         if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m);
00836                                         else result += Util::square((x_data[i] * m) + b - y_data[i]);
00837                                         count++;
00838                                 }
00839                         }
00840                         result/=count;
00841                 }
00842                 else {
00843                         for (size_t i = 0; i < size; i++) {
00844                                 if (invert) result += Util::square(x_data[i] - (y_data[i]-b)/m);
00845                                 else result += Util::square((x_data[i] * m) + b - y_data[i]);
00846                         }
00847                         result = result / size;
00848                 }
00849         }
00850         scale = m;
00851         shift = b;
00852 
00853         image->set_attr("ovcmp_m",m);
00854         image->set_attr("ovcmp_b",b);
00855         if (with2) delete with2;
00856         EXITFUNC;
00857 
00858 #if 0
00859         return (1 - result);
00860 #endif
00861 
00862         return static_cast<float>(result);
00863 }
00864 
00865 float PhaseCmp::cmp(EMData * image, EMData *with) const
00866 {
00867         ENTERFUNC;
00868 
00869         int snrweight = params.set_default("snrweight", 0);
00870         int snrfn = params.set_default("snrfn",0);
00871         int ampweight = params.set_default("ampweight",0);
00872         int zeromask = params.set_default("zeromask",0);
00873         float minres = params.set_default("minres",500.0f);
00874         float maxres = params.set_default("maxres",2.0f);
00875 
00876         if (snrweight && snrfn) throw InvalidCallException("SNR weight and SNRfn cannot both be set in the phase comparator");
00877 
00878 #ifdef EMAN2_USING_CUDA
00879         if (image->gpu_operation_preferred()) {
00880 //              cout << "Cuda cmp" << endl;
00881                 EXITFUNC;
00882                 return cuda_cmp(image,with);
00883         }
00884 #endif
00885 
00886         EMData *image_fft = NULL;
00887         EMData *with_fft = NULL;
00888 
00889         int ny = image->get_ysize();
00890 //      int np = (int) ceil(Ctf::CTFOS * sqrt(2.0f) * ny / 2) + 2;
00891         int np = 0;
00892         vector<float> snr;
00893 
00894         // weighting based on SNR estimate from CTF
00895         if (snrweight) {
00896                 Ctf *ctf = NULL;
00897                 if (!image->has_attr("ctf")) {
00898                         if (!with->has_attr("ctf")) throw InvalidCallException("SNR weight with no CTF parameters");
00899                         ctf=with->get_attr("ctf");
00900                 }
00901                 else ctf=image->get_attr("ctf");
00902 
00903                 float ds=1.0f/(ctf->apix*ny);
00904                 snr=ctf->compute_1d(ny,ds,Ctf::CTF_SNR); // note that this returns ny/2 values
00905                 if(ctf) {delete ctf; ctf=0;}
00906                 np=snr.size();
00907         }
00908         // weighting based on empirical SNR function (not really good)
00909         else if (snrfn==1) {
00910                 np=ny/2;
00911                 snr.resize(np);
00912 
00913                 for (int i = 0; i < np; i++) {
00914                         float x2 = 10.0f*i/np;
00915                         snr[i] = x2 * exp(-x2);
00916                 }
00917         }
00918         // no weighting
00919         else {
00920                 np=ny/2;
00921                 snr.resize(np);
00922 
00923                 for (int i = 0; i < np; i++) snr[i]=1.0;
00924         }
00925 
00926         // Min/max modifications to weighting
00927         float pmin,pmax;
00928         if (minres>0) pmin=((float)image->get_attr("apix_x")*image->get_ysize())/minres;                //cutoff in pixels, assume square
00929         else pmin=0;
00930         if (maxres>0) pmax=((float)image->get_attr("apix_x")*image->get_ysize())/maxres;
00931         else pmax=0;
00932 
00933 //      printf("%f\t%f\n",pmin,pmax);
00934 
00935         // We use 'soft' edges for the Fourier cutoffs to minimize issues with pixel interpolation
00936         for (int i = 0; i < np; i++) {
00937                 if (pmin>0) snr[i]*=(tanh(5.0f*(i-pmin)/pmin)+1.0f)/2.0f;
00938                 if (pmax>0) snr[i]*=(1.0f-tanh(i-pmax))/2.0f;
00939 //              printf("%d\t%f\n",i,snr[i]);
00940         }
00941 
00942         if (zeromask) {
00943                 image_fft=image->copy();
00944                 with_fft=with->copy();
00945                 
00946                 if (image_fft->is_complex()) image_fft->do_ift_inplace();
00947                 if (with_fft->is_complex()) with_fft->do_ift_inplace();
00948                 
00949                 int sz=image_fft->get_xsize()*image_fft->get_ysize()*image_fft->get_zsize();
00950                 float *d1=image_fft->get_data();
00951                 float *d2=with_fft->get_data();
00952                 
00953                 for (int i=0; i<sz; i++) {
00954                         if (d1[i]==0.0 || d2[i]==0.0) { d1[i]=0.0; d2[i]=0.0; }
00955                 }
00956                 
00957                 image_fft->update();
00958                 with_fft->update();
00959                 image_fft->do_fft_inplace();
00960                 with_fft->do_fft_inplace();
00961                 image_fft->set_attr("free_me",1); 
00962                 with_fft->set_attr("free_me",1); 
00963         }
00964         else {
00965                 if (image->is_complex()) image_fft=image;
00966                 else {
00967                         image_fft=image->do_fft();
00968                         image_fft->set_attr("free_me",1);
00969                 }
00970                 
00971                 if (with->is_complex()) with_fft=with;
00972                 else {
00973                         with_fft=with->do_fft();
00974                         with_fft->set_attr("free_me",1);
00975                 }
00976         }
00977 //      image_fft->ri2ap();
00978 //      with_fft->ri2ap();
00979 
00980         const float *const image_fft_data = image_fft->get_const_data();
00981         const float *const with_fft_data = with_fft->get_const_data();
00982         double sum = 0;
00983         double norm = FLT_MIN;
00984         size_t i = 0;
00985 //      int nx=image_fft->get_xsize();
00986             ny=image_fft->get_ysize();
00987         int nz=image_fft->get_zsize();
00988         int nx2=image_fft->get_xsize()/2;
00989         int ny2=image_fft->get_ysize()/2;
00990 //      int nz2=image_fft->get_zsize()/2;
00991 
00992         // This can never happen any more...
00993         if (np==0) {
00994                 for (int z = 0; z < nz; z++){
00995                         for (int y = 0; y < ny; y++) {
00996                                 for (int x = 0; x < nx2; x ++) {
00997                                         float a;
00998                                         if (ampweight) a= (float)hypot(with_fft_data[i],with_fft_data[i+1]);
00999                                         else a=1.0f;
01000                                         sum += Util::angle_err_ri(image_fft_data[i],image_fft_data[i+1],with_fft_data[i],with_fft_data[i+1]) * a;
01001                                         norm += a;
01002                                         i += 2;
01003                                 }
01004                         }
01005                 }
01006                 
01007         }
01008         else if (nz==1) {
01009                 for (int y = 0; y < ny; y++) {
01010                         for (int x = 0; x < nx2; x ++) {
01011                                 int r=Util::hypot_fast_int(x,y>ny/2?ny-y:y);
01012                                 if (r>=ny2) { i+=2; continue; }         // we only have snr values to the box radius
01013                                 
01014                                 float a;
01015                                 if (ampweight) a= (float)hypot(with_fft_data[i],with_fft_data[i+1]);
01016                                 else a=1.0f;
01017                                 a*=snr[r];
01018                                 sum += Util::angle_err_ri(image_fft_data[i],image_fft_data[i+1],with_fft_data[i],with_fft_data[i+1]) * a;
01019                                 norm += a;
01020                                 i += 2;
01021                         }
01022                 }
01023         }
01024         else {
01025                 for (int z = 0; z < nz; z++){
01026                         for (int y = 0; y < ny; y++) {
01027                                 for (int x = 0; x < nx2; x ++) {
01028                                         int r=(int)Util::hypot3(x,y>ny/2?ny-y:y,z>nz/2?nz-z:z);
01029                                         if (r>=ny2) { i+=2; continue; }         // we only have snr values to the box radius
01030                                         
01031                                         float a;
01032                                         if (ampweight) a= (float)hypot(with_fft_data[i],with_fft_data[i+1]);
01033                                         else a=1.0f;
01034                                         a*=snr[r];
01035                                         sum += Util::angle_err_ri(image_fft_data[i],image_fft_data[i+1],with_fft_data[i],with_fft_data[i+1]) * a;
01036                                         norm += a;
01037                                         i += 2;
01038                                 } 
01039                         }
01040                 }
01041                 
01042         }
01043 
01044         EXITFUNC;
01045 
01046         if( image_fft->has_attr("free_me") )
01047         {
01048                 delete image_fft;
01049                 image_fft = 0;
01050         }
01051         if( with_fft->has_attr("free_me") )
01052         {
01053                 delete with_fft;
01054                 with_fft = 0;
01055         }
01056 #if 0
01057         return (1.0f - sum / norm);
01058 #endif
01059         return (float)(sum / norm);
01060 }
01061 
01062 #ifdef EMAN2_USING_CUDA
01063 #include "cuda/cuda_cmp.h"
01064 float PhaseCmp::cuda_cmp(EMData * image, EMData *with) const
01065 {
01066         ENTERFUNC;
01067         validate_input_args(image, with);
01068 
01069         typedef vector<EMData*> EMDatas;
01070         static EMDatas hist_pyramid;
01071         static EMDatas norm_pyramid;
01072         static EMData weighting;
01073         static int image_size = 0;
01074 
01075         int size;
01076         EMData::CudaDataLock imagelock(image);
01077         EMData::CudaDataLock withlock(with);
01078 
01079         if (image->is_complex()) {
01080                 size = image->get_xsize();
01081         } else {
01082                 int nx = image->get_xsize()+2;
01083                 nx -= nx%2;
01084                 size = nx*image->get_ysize()*image->get_zsize();
01085         }
01086         if (size != image_size) {
01087                 for(unsigned int i =0; i < hist_pyramid.size(); ++i) {
01088                         delete hist_pyramid[i];
01089                         delete norm_pyramid[i];
01090                 }
01091                 hist_pyramid.clear();
01092                 norm_pyramid.clear();
01093                 int s = size;
01094                 if (s < 1) throw UnexpectedBehaviorException("The image is 0 size");
01095                 int p2 = 1;
01096                 while ( s != 1 ) {
01097                         s /= 2;
01098                         p2 *= 2;
01099                 }
01100                 if ( p2 != size ) {
01101                         p2 *= 2;
01102                         s = p2;
01103                 }
01104                 if (s != 1) s /= 2;
01105                 while (true) {
01106                         EMData* h = new EMData();
01107                         h->set_size_cuda(s); h->to_value(0.0);
01108                         hist_pyramid.push_back(h);
01109                         EMData* n = new EMData();
01110                         n->set_size_cuda(s); n->to_value(0.0);
01111                         norm_pyramid.push_back(n);
01112                         if ( s == 1) break;
01113                         s /= 2;
01114                 }
01115                 int nx = image->get_xsize()+2;
01116                 nx -= nx%2; // for Fourier stuff
01117                 int ny = image->get_ysize();
01118                 int nz = image->get_zsize();
01119                 weighting.set_size_cuda(nx,ny,nz);
01120                 // Size of weighting need only be half this, but does that translate into faster code?
01121                 weighting.set_size_cuda(nx/2,ny,nz);
01122                 float np = (int) ceil(Ctf::CTFOS * sqrt(2.0f) * ny / 2) + 2;
01123                 EMDataForCuda tmp = weighting.get_data_struct_for_cuda();
01124                 calc_phase_weights_cuda(&tmp,np);
01125                 //weighting.write_image("phase_wieghts.hdf");
01126                 image_size = size;
01127         }
01128 
01129         EMDataForCuda hist[hist_pyramid.size()];
01130         EMDataForCuda norm[hist_pyramid.size()];
01131 
01132         EMDataForCuda wt = weighting.get_data_struct_for_cuda();
01133         EMData::CudaDataLock lock1(&weighting);
01134         for(unsigned int i = 0; i < hist_pyramid.size(); ++i ) {
01135                 hist[i] = hist_pyramid[i]->get_data_struct_for_cuda();
01136                 hist_pyramid[i]->cuda_lock();
01137                 norm[i] = norm_pyramid[i]->get_data_struct_for_cuda();
01138                 norm_pyramid[i]->cuda_lock();
01139         }
01140 
01141         EMData *image_fft = image->do_fft_cuda();
01142         EMDataForCuda left = image_fft->get_data_struct_for_cuda();
01143         EMData::CudaDataLock lock2(image_fft);
01144         EMData *with_fft = with->do_fft_cuda();
01145         EMDataForCuda right = with_fft->get_data_struct_for_cuda();
01146         EMData::CudaDataLock lock3(image_fft);
01147 
01148         mean_phase_error_cuda(&left,&right,&wt,hist,norm,hist_pyramid.size());
01149         float result;
01150         float* gpu_result = hist_pyramid[hist_pyramid.size()-1]->get_cuda_data();
01151         cudaError_t error = cudaMemcpy(&result,gpu_result,sizeof(float),cudaMemcpyDeviceToHost);
01152         if ( error != cudaSuccess) throw UnexpectedBehaviorException( "CudaMemcpy (host to device) in the phase comparator failed:" + string(cudaGetErrorString(error)));
01153 
01154         delete image_fft; image_fft=0;
01155         delete with_fft; with_fft=0;
01156 
01157         for(unsigned int i = 0; i < hist_pyramid.size(); ++i ) {
01158 //              hist_pyramid[i]->write_image("hist.hdf",-1); // debug
01159 //              norm_pyramid[i]->write_image("norm.hdf",-1); // debug
01160                 hist_pyramid[i]->cuda_unlock();
01161                 norm_pyramid[i]->cuda_unlock();
01162         }
01163 
01164         EXITFUNC;
01165         return result;
01166 
01167 }
01168 
01169 #endif // EMAN2_USING_CUDA
01170 
01171 
01172 float FRCCmp::cmp(EMData * image, EMData * with) const
01173 {
01174         ENTERFUNC;
01175         validate_input_args(image, with);
01176 
01177         int snrweight = params.set_default("snrweight", 0);
01178         int ampweight = params.set_default("ampweight", 0);
01179         int sweight = params.set_default("sweight", 1);
01180         int nweight = params.set_default("nweight", 0);
01181         int zeromask = params.set_default("zeromask",0);
01182         float minres = params.set_default("minres",500.0f);
01183         float maxres = params.set_default("maxres",2.0f);
01184 
01185         if (zeromask) {
01186                 image=image->copy();
01187                 with=with->copy();
01188                 
01189                 int sz=image->get_xsize()*image->get_ysize()*image->get_zsize();
01190                 float *d1=image->get_data();
01191                 float *d2=with->get_data();
01192                 
01193                 for (int i=0; i<sz; i++) {
01194                         if (d1[i]==0.0 || d2[i]==0.0) { d1[i]=0.0; d2[i]=0.0; }
01195                 }
01196                 
01197                 image->update();
01198                 with->update();
01199                 image->do_fft_inplace();
01200                 with->do_fft_inplace();
01201                 image->set_attr("free_me",1); 
01202                 with->set_attr("free_me",1); 
01203         }
01204 
01205 
01206         if (!image->is_complex()) {
01207                 image=image->do_fft(); 
01208                 image->set_attr("free_me",1); 
01209         }
01210         if (!with->is_complex()) { 
01211                 with=with->do_fft(); 
01212                 with->set_attr("free_me",1); 
01213         }
01214 
01215         static vector < float >default_snr;
01216 
01217 //      if (image->get_zsize() > 1) {
01218 //              throw ImageDimensionException("2D only");
01219 //      }
01220 
01221 //      int nx = image->get_xsize();
01222         int ny = image->get_ysize();
01223         int ny2=ny/2+1;
01224 
01225         vector < float >fsc;
01226 
01227                 
01228 
01229         fsc = image->calc_fourier_shell_correlation(with,1);
01230 
01231         // The fast hypot here was supposed to speed things up. Little effect
01232 //      if (image->get_zsize()>1) fsc = image->calc_fourier_shell_correlation(with,1);
01233 //      else {
01234 //              double *sxy = (double *)malloc(ny2*sizeof(double)*4);
01235 //              double *sxx = sxy+ny2;
01236 //              double *syy = sxy+2*ny2;
01237 //              double *norm= sxy+3*ny2;
01238 //
01239 //              float *df1=image->get_data();
01240 //              float *df2=with->get_data();
01241 //              int nx2=image->get_xsize();
01242 //
01243 //              for (int y=-ny/2; y<ny/2; y++) {
01244 //                      for (int x=0; x<nx2/2; x++) {
01245 //                              if (x==0 && y<0) continue;      // skip Friedel pair
01246 //                              short r=Util::hypot_fast_int(x,y);
01247 //                              if (r>ny2-1) continue;
01248 //                              int l=x*2+(y<0?ny+y:y)*nx2;
01249 //                              sxy[r]+=df1[l]*df2[l]+df1[l+1]*df2[l+1];
01250 //                              sxx[r]+=df1[l]*df1[l];
01251 //                              syy[r]+=df2[l]*df2[l];
01252 //                              norm[r]+=1.0;
01253 //                      }
01254 //              }
01255 //              fsc.resize(ny2*3);
01256 //              for (int r=0; r<ny2; r++) {
01257 //                      fsc[r]=r*0.5/ny2;
01258 //                      fsc[ny2+r]=sxy[r]/(sqrt(sxx[r])*sqrt(syy[r]));
01259 //                      fsc[ny2*2+r]=norm[r];
01260 //              }
01261 //              free(sxy);
01262 //      }
01263 
01264         vector<float> snr;
01265         if (snrweight) {
01266                 Ctf *ctf = NULL;
01267                 if (!image->has_attr("ctf")) {
01268                         if (!with->has_attr("ctf")) throw InvalidCallException("SNR weight with no CTF parameters");
01269                         ctf=with->get_attr("ctf");
01270                 }
01271                 else ctf=image->get_attr("ctf");
01272 
01273                 float ds=1.0f/(ctf->apix*ny);
01274                 snr=ctf->compute_1d(ny,ds,Ctf::CTF_SNR);
01275                 if(ctf) {delete ctf; ctf=0;}
01276         }
01277 
01278         vector<float> amp;
01279         if (ampweight) amp=image->calc_radial_dist(ny/2,0,1,0);
01280 
01281         // Min/max modifications to weighting
01282         float pmin,pmax;
01283         if (minres>0) pmin=((float)image->get_attr("apix_x")*image->get_ysize())/minres;                //cutoff in pixels, assume square
01284         else pmin=0;
01285         if (maxres>0) pmax=((float)image->get_attr("apix_x")*image->get_ysize())/maxres;
01286         else pmax=0;
01287 
01288         double sum=0.0, norm=0.0;
01289 
01290         for (int i=0; i<ny/2; i++) {
01291                 double weight=1.0;
01292                 if (sweight) weight*=fsc[(ny2)*2+i];
01293                 if (ampweight) weight*=amp[i];
01294                 if (snrweight) weight*=snr[i];
01295 //              if (snrweight)  {
01296 //                      if (snr[i]>0) weight*=sqrt(snr[i]);
01297 //                      else weight=0;
01298 //              }
01299 //if(snr[i]<0) printf("snr[%d] = %1.5g\n",i,snr[i]);
01300                 if (pmin>0) weight*=(tanh(5.0*(i-pmin)/pmin)+1.0)/2.0;
01301                 if (pmax>0) weight*=(1.0-tanh(i-pmax))/2.0;
01302                 
01303                 sum+=weight*fsc[ny2+i];
01304                 norm+=weight;
01305 //              printf("%d\t%f\t%f\n",i,weight,fsc[ny/2+1+i]);
01306         }
01307 
01308         // This performs a weighting that tries to normalize FRC by correcting from the number of particles represented by the average
01309         sum/=norm;
01310         if (nweight && with->get_attr_default("ptcl_repr",0) && sum>=0 && sum<1.0) {
01311                 sum=sum/(1.0-sum);                                                      // convert to SNR
01312                 sum/=(float)with->get_attr_default("ptcl_repr",0);      // divide by ptcl represented
01313                 sum=sum/(1.0+sum);                                                      // convert back to correlation
01314         }
01315 
01316         if (image->has_attr("free_me")) delete image;
01317         if (with->has_attr("free_me")) delete with;
01318 
01319         EXITFUNC;
01320 
01321 
01322         if (!Util::goodf(&sum)) sum=-3.0e38;
01323         //.Note the negative! This is because EMAN2 follows the convention that
01324         // smaller return values from comparitors indicate higher similarity -
01325         // this enables comparitors to be used in a generic fashion.
01326         return (float)-sum;
01327 }
01328 
01329 void EMAN::dump_cmps()
01330 {
01331         dump_factory < Cmp > ();
01332 }
01333 
01334 map<string, vector<string> > EMAN::dump_cmps_list()
01335 {
01336         return dump_factory_list < Cmp > ();
01337 }
01338 
01339 /* vim: set ts=4 noet: */

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