53 fnVol = getParam(
"-i");
54 fnOut = getParam(
"-o");
55 mask_prm.allowed_data_types =
INT_MASK;
56 if ((useMask = checkParam(
"--mask")))
57 mask_prm.readParams(
this);
58 sigma = getDoubleParam(
"--sigma");
59 targetError = getDoubleParam(
"--targetError")/100.0;
60 stop = getDoubleParam(
"--stop");
61 initialSeeds = getIntParam(
"--initialSeeds");
62 growSeeds = getDoubleParam(
"--growSeeds");
63 allowMovement = !checkParam(
"--dontAllowMovement");
64 allowIntensity = !checkParam(
"--dontAllowIntensity");
66 intensityFraction = getDoubleParam(
"--dontAllowIntensity",1);
67 intensityColumn = getParam(
"--intensityColumn");
68 Nclosest = getIntParam(
"--Nclosest");
69 minDistance = getDoubleParam(
"--minDistance");
70 penalty = getDoubleParam(
"--penalty");
71 numThreads = getIntParam(
"--thr");
72 sampling = getDoubleParam(
"--sampling_rate");
73 dontScale = checkParam(
"--dontScale");
74 binarize = checkParam(
"--binarize");
85 std::cout <<
"Input volume: " << fnVol << std::endl
86 <<
"Output volume: " <<
fnOut << std::endl
87 <<
"Sigma: " << sigma << std::endl
88 <<
"Initial seeds: " << initialSeeds << std::endl
89 <<
"Grow seeds: " << growSeeds << std::endl
90 <<
"Target error: " << targetError << std::endl
91 <<
"Stop: " << stop << std::endl
92 <<
"AllowMovement: " << allowMovement << std::endl
93 <<
"AllowIntensity: " << allowIntensity << std::endl
94 <<
"Intensity Frac: " << intensityFraction << std::endl
95 <<
"Intensity Col: " << intensityColumn << std::endl
96 <<
"Nclosest: " << Nclosest << std::endl
97 <<
"Min. Distance: " << minDistance << std::endl
98 <<
"Penalty: " << penalty << std::endl
99 <<
"Threads: " << numThreads << std::endl
100 <<
"Sampling Rate: " <<
sampling << std::endl
101 <<
"Don't scale: " << dontScale << std::endl
102 <<
"Binarize: " << binarize << std::endl
103 <<
"Threshold: " <<
threshold << std::endl
108 std::cout <<
"No mask\n";
113 addUsageLine(
"Creates a set of pseudoatoms representing the density of an EM volume. ");
114 addUsageLine(
"+This is useful for the vector quantization process needed in problems ");
115 addUsageLine(
"+like docking, approximation of structures by Alpha Shapes, Normal Mode ");
116 addUsageLine(
"+Analysis, etc.");
118 addUsageLine(
"+The volume is approximated by Gaussians of a desired size. The user can ");
119 addUsageLine(
"+specify whether the Gaussians can have different intensities or not, as well ");
120 addUsageLine(
"+as the level of precision with which she desires to approximate the input ");
121 addUsageLine(
"+EM volume.");
122 addParamsLine(
" -i <volume> : Input volume");
123 addParamsLine(
" [-o <rootname=\"\">] : Output rootname. If not given, the rootname of the input volume is taken.");
124 addParamsLine(
" : The output of the program is: [rootname].pdb");
125 addParamsLine(
" : (PDB file with the pseudo atoms).");
126 addParamsLine(
" :+If verbose is set to 2, then also [rootname].vol ");
127 addParamsLine(
" :+(the approximation volume), [rootname].hist ");
128 addParamsLine(
" :+(histogram of the Gaussian intensities), ");
129 addParamsLine(
" :+[rootname]_rawDiff.vol (difference between the ");
130 addParamsLine(
" :+input volume and its approximation), ");
131 addParamsLine(
" :+[rootname]_relativeDiff.vol (the raw difference ");
132 addParamsLine(
" :+divided by the input volume at that location; this ");
133 addParamsLine(
" :+gives an idea of how much the error represents with ");
134 addParamsLine(
" :+respect to the input");
135 addParamsLine(
" [--sigma <s=1.5>] : Sigma of gaussians (in Angstroms)");
136 addParamsLine(
" : It should be comparable to the sampling rate");
137 addParamsLine(
" [--initialSeeds+ <N=300>] : Initial number of pseudoatoms");
138 addParamsLine(
" [--growSeeds+ <percentage=30>] : Percentage of growth");
139 addParamsLine(
" :+At each iteration the smallest percentage/2 ");
140 addParamsLine(
" :+pseudoatoms will be removed, and percentage new pseudoatoms will be created.");
141 addParamsLine(
" [--stop+ <p=0.001>] : Stop criterion (0<p<1) for inner iterations");
142 addParamsLine(
" :+At each iteration the current number of gaussians will be optimized until ");
143 addParamsLine(
" :+the average error does not decrease at least this amount relative to the previous iteration.");
144 addParamsLine(
" [--targetError+ <e=2>] : Finish when the average representation");
145 addParamsLine(
" : error is below this threshold (in percentage; by default, 2%)");
146 addParamsLine(
" [--dontAllowMovement+] : Don't allow pseudoatoms to move");
147 addParamsLine(
" [--dontAllowIntensity+ <f=0.01>] : Don't allow pseudoatoms to change intensity");
148 addParamsLine(
" : f determines the fraction of intensity");
149 addParamsLine(
" : held by each pseudoatom");
150 addParamsLine(
" [--intensityColumn+ <s=Bfactor>] : Where to write the intensity in the PDB file");
151 addParamsLine(
" where <s>");
152 addParamsLine(
" occupancy");
153 addParamsLine(
" Bfactor");
154 addParamsLine(
" [--Nclosest+ <N=3>] : N closest atoms, it is used only for the");
155 addParamsLine(
" : distance histogram");
156 addParamsLine(
" [--minDistance+ <d=0.001>] : Minimum distance between two pseudoatoms (in Angstroms)");
157 addParamsLine(
" : Set it to -1 to disable");
158 addParamsLine(
" [--penalty+ <p=10>] : Penalty for overshooting");
159 addParamsLine(
" [--sampling_rate <Ts=1>] : Sampling rate Angstroms/pixel");
160 addParamsLine(
" [--dontScale+] : Don't scale atom weights in the PDB");
161 addParamsLine(
" [--binarize+ <threshold>] : Binarize the volume for a more uniform distribution");
162 addParamsLine(
" [--thr <n=1>] : Number of threads");
163 mask_prm.defineParams(
this,
INT_MASK,
nullptr,
"Statistics restricted to the mask area.",
true);
164 addExampleLine(
"Convert volume to pseudoatoms, each pseudoatom with a different weight",
false);
165 addExampleLine(
"xmipp_volume_to_pseudoatoms -i volume.vol -o pseudoatoms");
166 addExampleLine(
"Convert volume to pseudoatoms, all pseudoatoms with the same weight",
false);
167 addExampleLine(
"xmipp_volume_to_pseudoatoms -i volume.vol -o pseudoatoms --dontAllowIntensity");
175 if (intensityColumn!=
"occupancy" && intensityColumn!=
"Bfactor")
179 Vin().setXmippOrigin();
186 Vcurrent().initZeros(Vin());
187 mask_prm.generate_mask(Vin());
190 gaussianTable.resize(
CEIL(sigma3*
sqrt(3.0)*1000));
196 double minval=1e38, maxval=-1e38;
200 if (useMask && iMask3D(
k,
i,
j)==0)
213 minval, maxval, 200);
218 percentil1=maxval/500;
224 smallAtom=range*intensityFraction;
228 threadIds=(pthread_t *)malloc(numThreads*
sizeof(pthread_t));
231 for (
int i=0;
i<numThreads;
i++)
233 threadArgs[
i].myThreadID=
i;
234 threadArgs[
i].parent=
this;
235 pthread_create( (threadIds+
i),
nullptr, optimizeCurrentAtomsThread,
236 (
void *) (threadArgs+
i));
243 Filter.generateMask(Vin());
244 Filter.do_generate_3dmask=
false;
266 for (
int n=0;
n<Nseeds;
n++)
270 int kmax=0, imax=0, jmax=0;
277 if (first || voxel>maxVal)
296 if (maxVal<smallAtom)
303 drawGaussian(kmax,imax,jmax,Vdiff,-a.
intensity);
307 std::cout <<
"New atom: " << a << std::endl;
310 save.
write(
"PPPDiff.vol");
311 std::cout <<
"Press any key\n";
335 Filter.applyMaskSpace(Vdiff);
340 std::list<SeedCandidate> candidateList;
348 if (listSize==0 || v>lastValue)
352 for (std::list<SeedCandidate>::iterator
iter=candidateList.begin();
iter!=candidateList.end();
iter++)
365 candidateList.push_back(aux);
366 candidateList.sort();
370 candidateList.pop_back();
373 lastValue=candidateList.back().v;
381 for (std::list<SeedCandidate>::iterator
iter=candidateList.begin();
iter!=candidateList.end();
iter++)
391 if (
iter->v<smallAtom)
405 int fromNegative=
ROUND(Nseeds*0.5);
406 int fromSmall=Nseeds-fromNegative;
412 atoms.erase(atoms.begin(),atoms.begin()+fromSmall);
423 int alreadyRemoved=0;
427 for (
double v=vmin+vmin/20; v<0; v-=vmin/20)
432 oldListSize=atoms.size();
436 int kneg=0, ineg=0, jneg=0;
442 if (useMask && iMask3D(
k,
i,
j)==0)
458 int nmax=atoms.size();
462 (kneg-atoms[
n].location(0))*(kneg-atoms[
n].
location(0))+
473 atoms.erase(atoms.begin()+
n);
480 while (oldListSize>atoms.size() && alreadyRemoved<fromNegative);
481 if (alreadyRemoved==fromNegative)
486 removeTooCloseSeeds();
492 if (minDistance>0 && allowIntensity)
494 std::vector<int> toRemove;
495 int nmax=atoms.size();
496 double minDistance2=minDistance*minDistance;
497 for (
int n1=0; n1<
nmax; n1++)
500 int nn=0, nnmax=toRemove.size();
503 if (toRemove[nn]==n1)
508 else if (toRemove[nn]>n1)
514 for (
int n2=n1+1; n2<
nmax; n2++)
520 if (toRemove[nn]==n2)
525 else if (toRemove[nn]>n2)
531 double diffZ=atoms[n1].location(0)-atoms[n2].location(0);
532 double diffY=atoms[n1].location(1)-atoms[n2].location(1);
533 double diffX=atoms[n1].location(2)-atoms[n2].location(2);
534 double d2=diffZ*diffZ+diffY*diffY+diffX*diffX;
539 toRemove.push_back(n1);
543 toRemove.push_back(n2);
544 std::sort(toRemove.begin(),toRemove.end());
548 for (
int n=toRemove.size()-1;
n>=0;
n--)
549 atoms.erase(atoms.begin()+toRemove[
n]);
556 Vcurrent().initZeros(Vin());
557 int nmax=atoms.size();
576 double vperc=fabs(vdiff);
577 energyDiff+=vdiff*vdiff;
578 percentageDiff+=vperc;
582 percentageDiff/=(N*range);
596 for (
int kk=k0; kk<=kF; kk++)
597 for (
int ii=i0; ii<=iF; ii++)
598 for (
int jj=j0; jj<=jF; jj++)
600 return sum/((kF-k0+1)*(iF-i0+1)*(jF-j0+1));
612 for (
int kk=k0; kk<=kF; kk++)
615 double diffkk2=aux*aux;
616 for (
int ii=i0; ii<=iF; ii++)
619 double diffiikk2=aux*aux+diffkk2;
620 for (
int jj=j0; jj<=jF; jj++)
623 double r=
sqrt(diffiikk2+aux*aux);
625 long iaux=lround(aux);
635 double k=atoms[idxGaussian].location(0);
636 double i=atoms[idxGaussian].location(1);
637 double j=atoms[idxGaussian].location(2);
639 double sigma3ToUse=sigma3;
655 for (
int k=k0; k<=kF; k++)
656 for (
int i=i0; i<=iF; i++)
657 for (
int j=j0; j<=jF; j++)
671 save().initZeros(region);
672 save2().initZeros(region);
677 if (Vinv<=0 || (useMask &&
A3D_ELEM(iMask3D,
k,
i,
j)==0))
684 double vperc=(vdiff<0)?-vdiff:penalty*vdiff;
687 std::cout <<
"(k,i,j)=(" <<
k <<
"," <<
i <<
"," <<
j <<
") toSimulate=" << Vinv <<
" simulated=" <<
A3D_ELEM(region,
k,
i,
j) <<
" vdiff=" << vdiff <<
" vperc=" << vperc << std::endl;
692 save.
write(
"PPPtoSimulate.vol");
693 save2.
write(
"PPPsimulated.vol");
694 std::cout <<
"Error=" << avgDiff/(N*range) << std::endl;
695 std::cout <<
"Press any key\n";
696 char c; std::cin >>
c;
698 return avgDiff/(N*range);
710 static pthread_mutex_t mutexUpdateVolume=PTHREAD_MUTEX_INITIALIZER;
718 std::vector< PseudoAtom > &atoms=parent->
atoms;
730 myArgs->Nintensity=0;
732 int nmax=atoms.size();
745 std::cout <<
"Atom n=" <<
n <<
" current intensity=" << atoms[
n].intensity <<
" -> " << currentRegionEval << std::endl;
751 double tryCoeffs[8]={0, 0.1, 0.2, 0.5, 0.9, 0.99, 1.01, 1.1};
754 for (
int t=0; t<8; t++)
759 tryCoeffs[t]*atoms[
n].intensity);
761 double reduction=trialRegionEval-currentRegionEval;
762 if (reduction<bestRed)
767 std::cout <<
" better -> " << trialRegionEval <<
" (factor=" << tryCoeffs[t] <<
")" << std::endl;
773 atoms[
n].intensity*=tryCoeffs[bestT];
776 atoms[
n].
location(2),region,atoms[
n].intensity);
777 pthread_mutex_lock(&mutexUpdateVolume);
779 pthread_mutex_unlock(&mutexUpdateVolume);
783 -atoms[
n].intensity);
786 std::cout <<
" finally -> " << currentRegionEval <<
" (intensity=" << atoms[
n].intensity <<
")" << std::endl;
788 myArgs->Nintensity++;
793 if (allowMovement && atoms[
n].intensity>0)
795 double tryX[6]={-0.45,0.5, 0.0 ,0.0, 0.0 ,0.0};
796 double tryY[6]={ 0.0 ,0.0,-0.45,0.5, 0.0 ,0.0};
797 double tryZ[6]={ 0.0 ,0.0, 0.0 ,0.0,-0.45,0.5};
800 for (
int t=0; t<6; t++)
806 region,atoms[
n].intensity);
808 double reduction=trialRegionEval-currentRegionEval;
809 if (reduction<bestRed)
817 atoms[
n].location(0)+=tryZ[bestT];
818 atoms[
n].location(1)+=tryY[bestT];
819 atoms[
n].location(2)+=tryX[bestT];
824 pthread_mutex_lock(&mutexUpdateVolume);
826 pthread_mutex_unlock(&mutexUpdateVolume);
839 if (!allowIntensity && !allowMovement)
845 double oldError=percentageDiff;
856 for (
int i=0;
i<numThreads;
i++)
858 Nintensity+=threadArgs[
i].Nintensity;
859 Nmovement+=threadArgs[
i].Nmovement;
863 int nmax=atoms.size();
864 for (
int n=nmax-1;
n>=0;
n--)
866 atoms.erase(atoms.begin()+
n);
870 std::cout <<
"Iteration " << iter <<
" error= " << percentageDiff
871 <<
" Natoms= " << atoms.size()
872 <<
" Intensity= " << Nintensity
873 <<
" Location= " << Nmovement
877 if ((oldError-percentageDiff)/oldError<stop)
891 intensities(
i)=atoms[
i].intensity;
897 Vcurrent.write(
fnOut+
"_approximation.vol");
902 Vdiff()=Vin()-Vcurrent();
904 if (useMask &&
XSIZE(iMask3D)!=0)
917 double a=0.99/(maxIntensity-minIntensity);
922 fhOut=fopen((
fnOut+
".pdb").c_str(),
"w");
925 int nmax=atoms.size();
927 if (intensityColumn==
"Bfactor")
929 fprintf(fhOut,
"REMARK xmipp_volume_to_pseudoatoms\n");
931 fprintf(fhOut,
"REMARK intensityColumn %s\n",intensityColumn.c_str());
936 intensity=0.01+
ROUND(100*a*(atoms[
n].intensity-minIntensity))/100.0;
939 "ATOM %5d DENS DENS%5d %8.3f%8.3f%8.3f%6.2f 1 DENS\n",
947 "ATOM %5d DENS DENS%5d %8.3f%8.3f%8.3f 1%6.2f DENS\n",
970 double previousNAtoms=0;
972 double actualGrowSeeds=0.;
977 placeSeeds(initialSeeds);
980 double Natoms=atoms.size();
981 actualGrowSeeds=growSeeds*
std::min(1.0,0.1+(percentageDiff-targetError)/targetError);
982 removeSeeds(
FLOOR(Natoms*(actualGrowSeeds/2)/100));
983 placeSeeds(
FLOOR(Natoms*actualGrowSeeds/100));
987 if (iter==0 && verbose>0)
988 std::cout <<
"Initial error with " << atoms.size()
989 <<
" pseudo-atoms " << percentageDiff << std::endl;
992 optimizeCurrentAtoms();
994 std::cout <<
"Error with " << atoms.size() <<
" pseudo-atoms " 995 << percentageDiff << std::endl;
999 if (fabs(previousNAtoms-atoms.size())/atoms.size()<0.01*actualGrowSeeds/100)
1001 std::cout <<
"The required precision cannot be attained\n" 1002 <<
"Suggestion: Reduce sigma and/or minDistance\n" 1003 <<
"Writing best approximation with current parameters\n";
1007 previousNAtoms=atoms.size();
1009 while (percentageDiff>targetError);
1010 removeTooCloseSeeds();
void read(const FileName &fnPDB)
Read phantom from either a PDB of CIF file.
int numThreads
Number of threads.
int barrier_init(barrier_t *barrier, int needed)
void min(Image< double > &op1, const Image< double > &op2)
void removeSeeds(int Nseeds)
Remove seeds.
__host__ __device__ float2 floor(const float2 v)
#define REPORT_ERROR(nerr, ErrormMsg)
void resizeNoCopy(const MultidimArray< T1 > &v)
void sqrt(Image< double > &op)
Couldn't write to file.
void writeResults()
Write results.
void show() const
show parameters
void write(const FileName &name="", size_t select_img=ALL_IMAGES, bool isStack=false, int mode=WRITE_OVERWRITE, CastWriteMode castMode=CW_CAST, int _swapWrite=0)
void abs(Image< double > &op)
double percentil(double percent_mass)
std::vector< PseudoAtom > atoms
void drawGaussian(double k, double i, double j, MultidimArray< double > &V, double intensity)
Draw a Gaussian on a volume.
void produceSideInfo()
Prepare side info.
void insertRegion(const MultidimArray< double > ®ion)
Insert region.
ql0001_ & k(htemp+1),(cvec+1),(atemp+1),(bj+1),(bl+1),(bu+1),(x+1),(clamda+1), &iout, infoqp, &zero,(w+1), &lenw,(iw+1), &leniw, &glob_grd.epsmac
Matrix1D< T > transpose() const
PseudoAtom()
Empty constructor.
void threshold(double *phi, unsigned long nvox, double limit)
#define A3D_ELEM(V, k, i, j)
#define DIRECT_A1D_ELEM(v, i)
#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
void compute_hist(const MultidimArrayGeneric &array, Histogram1D &hist, int no_steps)
void distanceHistogramPDB(const PDBPhantom &phantomPDB, size_t Nnearest, double maxDistance, int Nbins, Histogram1D &hist)
void extractRegion(int idxGaussian, MultidimArray< double > ®ion, bool extended=false) const
Extract region around a Gaussian.
void optimizeCurrentAtoms()
Optimize current atoms.
void readParams()
Read parameters from command line.
friend std::ostream & operator<<(std::ostream &o, const PseudoAtom &f)
Show pseudo atom.
void write(const FileName &fn) const
void max(Image< double > &op1, const Image< double > &op2)
#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
double intensity
Intensity.
#define DIRECT_MULTIDIM_ELEM(v, n)
bool allowIntensity
Allow gaussians to vary intensity.
#define XMIPP_EQUAL_ZERO(x)
void sort(struct DCEL_T *dcel)
void defineParams()
define parameters
Matrix1D< double > location
Location.
bool allowMovement
Allow gaussians to move.
#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
FileName withoutExtension() const
void placeSeeds(int Nseeds)
Place seeds.
void write(const FileName &fn, MDLabel=MDL_X, MDLabel=MDL_COUNT)
void drawApproximation()
Draw approximation.
bool operator<(const PseudoAtom &a, const PseudoAtom &b)
Comparison between pseudo atoms.
fprintf(glob_prnt.io, "\)
void initZeros(const MultidimArray< T1 > &op)
double computeAverage(int k, int i, int j, MultidimArray< double > &V)
Compute average of a volume.
static void * optimizeCurrentAtomsThread(void *threadArgs)
Optimize current atoms (thread)
int barrier_wait(barrier_t *barrier)
Incorrect value received.
void generateMask(MultidimArray< double > &v)
void removeTooCloseSeeds()
Remove too close seeds.
double evaluateRegion(const MultidimArray< double > ®ion) const
Evaluate region.
void compute_hist_within_binary_mask(const MultidimArray< int > &mask, MultidimArray< T > &v, Histogram1D &hist, int no_steps)
void applyMaskSpace(MultidimArray< double > &v)
double gaussian1D(double x, double sigma, double mu)