3232#include " flood_fill.cc"
3333#include " gemmi/symmetry.hpp"
3434#include " peaks_to_rlvs.cc"
35+ #include " refine_crystal.cc"
3536#include " scan_static_predictor.cc"
3637#include " score_crystals.cc"
3738#include " xyz_to_rlp.cc"
@@ -68,6 +69,12 @@ int main(int argc, char **argv) {
6869 .help (" The maximum number of candidate lattices to refine during indexing" )
6970 .default_value <size_t >(50 )
7071 .scan <' u' , size_t >();
72+ parser.add_argument (" --macro-cycles" )
73+ .help (
74+ " The number of macrocycles of refinement to run after the initial indexing. "
75+ " Set to zero for no post-indexing refinement." )
76+ .default_value <size_t >(5 )
77+ .scan <' u' , size_t >();
7178 parser.add_argument (" --test" )
7279 .help (" Enable additional output for testing" )
7380 .default_value <bool >(false )
@@ -115,6 +122,7 @@ int main(int argc, char **argv) {
115122 std::string filename = parser.get <std::string>(" refl" );
116123 double max_cell = parser.get <float >(" max-cell" );
117124 size_t max_refine = parser.get <size_t >(" max-refine" );
125+ size_t macro_cycles = parser.get <size_t >(" macro-cycles" );
118126
119127 // Parse the experiment list (a json file) and load the models.
120128 // Will be moved to dx2.
@@ -161,25 +169,39 @@ int main(int argc, char **argv) {
161169 // coordinates on the detector into reciprocal space.
162170 xyz_to_rlp_results results = xyz_to_rlp (xyzobs_px, panel, beam, scan, gonio);
163171 logger.info (" Number of reflections: {}" , results.rlp .extent (0 ));
172+ uint32_t n_points = parser.get <uint32_t >(" fft-npoints" );
173+
174+ // Determine the d_min limit of the data, will be used in macrocycles of refinement.
175+ double d_min_data;
176+ std::vector<double > d_values (results.rlp .extent (0 ), 0 );
177+ for (int i = 0 ; i < results.rlp .extent (0 ); ++i) {
178+ d_values[i] = 1.0 / Eigen::Map<Vector3d>(&results.rlp (i, 0 )).norm ();
179+ }
180+ d_min_data = *std::min_element (d_values.begin (), d_values.end ());
181+ logger.debug (" dmin of highest resolution spot: {:.5f}" , d_min_data);
164182
165- // If a resolution limit was not specified, determine from the highest resolution spot.
166183 double d_min;
167184 if (parser.is_used (" dmin" )) {
168185 d_min = parser.get <float >(" dmin" );
169186 } else {
170- std::vector<double > d_values (results.rlp .extent (0 ), 0 );
171- for (int i = 0 ; i < results.rlp .extent (0 ); ++i) {
172- d_values[i] = 1.0 / Eigen::Map<Vector3d>(&results.rlp (i, 0 )).norm ();
173- }
174- d_min = *std::min_element (d_values.begin (), d_values.end ());
175- logger.info (" Setting dmin based on highest resolution spot: {:.5f}" , d_min);
187+ /* rough calculation of suitable d_min based on max cell
188+ see also Campbell, J. (1998). J. Appl. Cryst., 31(3), 407-413.
189+ fft_cell should be greater than twice max_cell, so say:
190+ fft_cell = 2.5 * max_cell
191+ then:
192+ fft_cell = n_points * d_min/2
193+ 2.5 * max_cell = n_points * d_min/2
194+ a little bit of rearrangement:
195+ d_min = 5 * max_cell/n_points. */
196+ d_min = 5.0 * max_cell / n_points;
197+ d_min = std::max (d_min, d_min_data);
198+ logger.info (" Setting dmin to {:.5f}" , d_min);
176199 }
177200
178201 // b_iso is an isotropic b-factor used to weight the points when doing the fft.
179202 // i.e. high resolution (weaker) spots are downweighted by the expected
180203 // intensity fall-off as as function of resolution.
181204 double b_iso = -4.0 * std::pow (d_min, 2 ) * log (0.05 );
182- uint32_t n_points = parser.get <uint32_t >(" fft-npoints" );
183205 logger.info (" Setting b_iso = {:.3f}" , b_iso);
184206
185207 // Create an array to store the fft result. This is a 3D grid of points, typically 256^3.
@@ -374,6 +396,55 @@ int main(int argc, char **argv) {
374396 expt.beam ().set_s0 (best_beam.get_s0 ());
375397 expt.detector ().update (best_panel.get_d_matrix ());
376398
399+ // Now do macrocycles of refinement
400+ if (macro_cycles) {
401+ std::vector<double > d_steps;
402+ double d_min_step = (d_min - d_min_data) / macro_cycles;
403+ logger.info (" Performing {} macro cycles with a dmin step of {:.3f}" ,
404+ macro_cycles,
405+ d_min_step);
406+ for (int i = 0 ; i < macro_cycles; ++i) {
407+ d_steps.push_back (d_min - (i + 1 ) * d_min_step);
408+ }
409+ for (int i = 0 ; i < macro_cycles; ++i) {
410+ double d_min = d_steps[i];
411+ logger.info (" Performing macro cycle {} with d_min={:.3f}" , i + 1 , d_min);
412+ results = xyz_to_rlp (
413+ xyzobs_px, expt.detector ().panels ()[0 ], expt.beam (), scan, gonio);
414+
415+ // Make a selection on dmin and rotation angle like dials
416+ std::vector<bool > selection (results.rlp .extent (0 ), true );
417+ double osc_trim_limit = scan.get_oscillation ()[0 ] + 360.0 ;
418+ for (int i = 0 ; i < results.rlp .extent (0 ); ++i) {
419+ Eigen::Map<Vector3d> rlp_i (&results.rlp (i, 0 ));
420+ if (1.0 / rlp_i.norm () <= d_min) {
421+ selection[i] = false ;
422+ } else if (results.xyzobs_mm (i, 2 ) * RAD2DEG > osc_trim_limit) {
423+ selection[i] = false ;
424+ }
425+ }
426+ ReflectionTable reflections;
427+ reflections.add_column (std::string (" flags" ), flags.size (), 1 , flags);
428+ reflections.add_column (std::string (" xyzobs.mm.value" ),
429+ results.xyzobs_mm .extent (0 ),
430+ 3 ,
431+ results.xyzobs_mm_data );
432+ reflections.add_column (
433+ std::string (" s1" ), results.s1 .extent (0 ), 3 , results.s1_data );
434+ reflections.add_column (
435+ std::string (" rlp" ), results.rlp .extent (0 ), 3 , results.rlp_data );
436+ reflections.add_column (std::string (" entering" ), enterings);
437+ const ReflectionTable filtered = reflections.select (selection);
438+
439+ refine_crystal (expt.crystal (),
440+ filtered,
441+ gonio,
442+ expt.beam (),
443+ expt.detector ().panels ()[0 ],
444+ scan_width);
445+ }
446+ }
447+
377448 // Save the indexed experiment list.
378449 json elist_out = expt.to_json ();
379450 std::string efile_name = " indexed.expt" ;
@@ -511,7 +582,7 @@ int main(int argc, char **argv) {
511582 flags_ = strong_reflections.column <std::size_t >(" flags" );
512583 flag_span = flags_.value ();
513584 } else {
514- auto flag_span = flags_.value ();
585+ flag_span = flags_.value ();
515586 for (int i = 0 ; i < assign_results.miller_indices .extent (0 ); ++i) {
516587 if ((assign_results.miller_indices (i, 0 )) != 0
517588 | (assign_results.miller_indices (i, 1 ) != 0 )
@@ -530,7 +601,7 @@ int main(int argc, char **argv) {
530601 strong_reflections);
531602 // reset the predicted flags as these are observed not predicted
532603 for (int i = 0 ; i < flag_span.extent (0 ); ++i) {
533- flag_span (i, 0 ) = flag_span (i, 0 ) & ~predicted_value;
604+ flag_span (i, 0 ) &= ~predicted_value;
534605 }
535606
536607 // Save the indexed reflection table.
0 commit comments