@@ -56,6 +56,7 @@ class Class3DParameters(BaseModel):
5656 initial_model_offset_range : float = 6
5757 initial_model_offset_step : float = 2
5858 start_initial_model_C1 : bool = True
59+ multiple_initial_models : bool = True
5960 dont_combine_weights_via_disc : bool = True
6061 preread_images : bool = True
6162 scratch_dir : str | None = None
@@ -155,12 +156,20 @@ def run_initial_model(
155156 initial_model_command , cwd = str (project_dir ), capture_output = True
156157 )
157158
159+ if initial_model_params .multiple_initial_models :
160+ ini_model_file = (
161+ job_dir
162+ / f"run_it{ initial_model_params .initial_model_iterations :03} _model.star"
163+ )
164+ else :
165+ ini_model_file = job_dir / "initial_model.mrc"
166+
158167 # Register the initial model job with the node creator
159168 logger .info ("Sending relion.initialmodel (model) to node creator" )
160169 node_creator_parameters_refine : dict = {
161170 "job_type" : "relion.initialmodel" ,
162171 "input_file" : f"{ project_dir } /{ particles_file } " ,
163- "output_file" : f" { job_dir } /initial_model.mrc" ,
172+ "output_file" : str ( ini_model_file ) ,
164173 "relion_options" : dict (initial_model_params .relion_options ),
165174 "command" : " " .join (initial_model_command ),
166175 "stdout" : result .stdout .decode ("utf8" , "replace" ),
@@ -177,57 +186,89 @@ def run_initial_model(
177186 )
178187 return "" , []
179188
180- ini_model_file = job_dir / "initial_model.mrc"
181- align_symmetry_command = [
182- "relion_align_symmetry" ,
183- "--i" ,
184- str (
185- job_dir .relative_to (project_dir )
186- / f"run_it{ initial_model_params .initial_model_iterations :03} _model.star"
187- ),
188- "--o" ,
189- f"{ ini_model_file .relative_to (project_dir )} " ,
190- "--sym" ,
191- initial_model_params .symmetry ,
192- "--apply_sym" ,
193- "--select_largest_class" ,
194- "--pipeline_control" ,
195- f"{ job_dir .relative_to (project_dir )} /" ,
196- ]
189+ if (
190+ initial_model_params .multiple_initial_models
191+ and initial_model_params .symmetry != "C1"
192+ ):
193+ for model in ini_model_file .parent .glob (
194+ f"{ ini_model_file .stem .replace ('_model' , '' )} _class*.mrc"
195+ ):
196+ align_symmetry_command = [
197+ "relion_align_symmetry" ,
198+ "--i" ,
199+ str (model .relative_to (project_dir )),
200+ "--o" ,
201+ str (model .relative_to (project_dir )),
202+ "--sym" ,
203+ initial_model_params .symmetry ,
204+ "--apply_sym" ,
205+ "--pipeline_control" ,
206+ f"{ job_dir .relative_to (project_dir )} /" ,
207+ ]
197208
198- # Run symmetry alignment and confirm it ran successfully
199- logger .info ("Running symmetry alignment" )
200- result = subprocess .run (
201- align_symmetry_command , cwd = str (project_dir ), capture_output = True
202- )
209+ # Run symmetry alignment and confirm it ran successfully
210+ logger .info (f"Running symmetry alignment for { model .name } " )
211+ result = subprocess .run (
212+ align_symmetry_command , cwd = str (project_dir ), capture_output = True
213+ )
214+ if result .returncode :
215+ logger .error (
216+ f"Relion initial model symmetry alignment "
217+ f"failed with exitcode { result .returncode } :\n "
218+ + result .stderr .decode ("utf8" , "replace" )
219+ )
203220
204- # Register the initial model job with the node creator
205- logger .info ("Sending relion.initialmodel (alignment) to node creator" )
206- node_creator_parameters_symmetry : dict = {
207- "job_type" : "relion.initialmodel" ,
208- "input_file" : f"{ project_dir } /{ particles_file } " ,
209- "output_file" : f"{ job_dir } /initial_model.mrc" ,
210- "relion_options" : dict (initial_model_params .relion_options ),
211- "command" : " " .join (align_symmetry_command ),
212- "stdout" : result .stdout .decode ("utf8" , "replace" ),
213- "stderr" : result .stderr .decode ("utf8" , "replace" ),
214- "success" : (result .returncode == 0 ),
215- }
216- send_to_rabbitmq ("node_creator" , node_creator_parameters_symmetry )
221+ elif not initial_model_params .multiple_initial_models :
222+ align_symmetry_command = [
223+ "relion_align_symmetry" ,
224+ "--i" ,
225+ str (
226+ job_dir .relative_to (project_dir )
227+ / f"run_it{ initial_model_params .initial_model_iterations :03} _model.star"
228+ ),
229+ "--o" ,
230+ f"{ ini_model_file .relative_to (project_dir )} " ,
231+ "--sym" ,
232+ initial_model_params .symmetry ,
233+ "--apply_sym" ,
234+ "--select_largest_class" ,
235+ "--pipeline_control" ,
236+ f"{ job_dir .relative_to (project_dir )} /" ,
237+ ]
217238
218- # End here if the command failed
219- if result .returncode :
220- logger .error (
221- f"Relion initial model symmetry alignment "
222- f"failed with exitcode { result .returncode } :\n "
223- + result .stderr .decode ("utf8" , "replace" )
239+ # Run symmetry alignment and confirm it ran successfully
240+ logger .info ("Running symmetry alignment" )
241+ result = subprocess .run (
242+ align_symmetry_command , cwd = str (project_dir ), capture_output = True
224243 )
225- return "" , []
244+
245+ # Register the initial model job with the node creator
246+ logger .info ("Sending relion.initialmodel (alignment) to node creator" )
247+ node_creator_parameters_symmetry : dict = {
248+ "job_type" : "relion.initialmodel" ,
249+ "input_file" : f"{ project_dir } /{ particles_file } " ,
250+ "output_file" : f"{ job_dir } /initial_model.mrc" ,
251+ "relion_options" : dict (initial_model_params .relion_options ),
252+ "command" : " " .join (align_symmetry_command ),
253+ "stdout" : result .stdout .decode ("utf8" , "replace" ),
254+ "stderr" : result .stderr .decode ("utf8" , "replace" ),
255+ "success" : (result .returncode == 0 ),
256+ }
257+ send_to_rabbitmq ("node_creator" , node_creator_parameters_symmetry )
258+
259+ # End here if the command failed
260+ if result .returncode :
261+ logger .error (
262+ f"Relion initial model symmetry alignment "
263+ f"failed with exitcode { result .returncode } :\n "
264+ + result .stderr .decode ("utf8" , "replace" )
265+ )
266+ return "" , []
226267
227268 # Send Murfey the location of the initial model
228269 murfey_params = {
229270 "register" : "save_initial_model" ,
230- "initial_model" : f" { job_dir } /initial_model.mrc" ,
271+ "initial_model" : str ( ini_model_file ) ,
231272 }
232273 send_to_rabbitmq ("murfey_feedback" , murfey_params )
233274
@@ -248,38 +289,41 @@ def run_initial_model(
248289 "Will send best initial model to ispyb with "
249290 f"resolution { resolution } and { number_of_particles } particles"
250291 )
251- ini_ispyb_parameters = [
252- {
253- "ispyb_command" : "buffer" ,
254- "buffer_lookup" : {
255- "particle_classification_id" : class_uuids_dict [class_uuids_keys [0 ]]
256- },
257- "buffer_command" : {"ispyb_command" : "insert_cryoem_initial_model" },
258- "number_of_particles" : number_of_particles ,
259- "resolution" : resolution ,
260- "store_result" : "ispyb_initial_model_id" ,
261- }
262- ]
263- for i in range (1 , initial_model_params .class3d_nr_classes ):
264- # Insert initial model for every class, sending model id each time
292+ ini_ispyb_parameters : list [dict ] = []
293+ for i in range (initial_model_params .class3d_nr_classes ):
294+ # Insert initial model for every class,
265295 ini_ispyb_parameters .append (
266296 {
267297 "ispyb_command" : "buffer" ,
268298 "buffer_lookup" : {
269299 "particle_classification_id" : class_uuids_dict [class_uuids_keys [i ]]
270300 },
271301 "buffer_command" : {"ispyb_command" : "insert_cryoem_initial_model" },
272- "number_of_particles" : number_of_particles ,
273- "resolution" : resolution ,
274- "cryoem_initial_model_id" : "$ispyb_initial_model_id" ,
275302 }
276303 )
277304 for i in range (initial_model_params .class3d_nr_classes ):
278305 # Add resolution to every model if it is finite
279- if np .isfinite (float (resolution )):
280- ini_ispyb_parameters [i ]["resolution" ] = resolution
306+ if initial_model_params .multiple_initial_models :
307+ ini_ispyb_parameters [i ]["resolution" ] = (
308+ model_resolutions [i ]
309+ if np .isfinite (float (model_resolutions [i ]))
310+ else 0.0
311+ )
312+ ini_ispyb_parameters [i ]["number_of_particles" ] = (
313+ float (model_scores [i ]) * initial_model_params .batch_size
314+ )
281315 else :
282- ini_ispyb_parameters [i ]["resolution" ] = 0.0
316+ ini_ispyb_parameters [i ]["resolution" ] = (
317+ resolution if np .isfinite (float (resolution )) else 0.0
318+ )
319+ ini_ispyb_parameters [i ]["number_of_particles" ] = number_of_particles
320+ # Set model id for the first class, sending model id each time afterwards
321+ if i == 0 :
322+ ini_ispyb_parameters [i ]["store_result" ] = "ispyb_initial_model_id"
323+ else :
324+ ini_ispyb_parameters [i ]["cryoem_initial_model_id" ] = (
325+ "$ispyb_initial_model_id"
326+ )
283327
284328 logger .info ("Running 3D classification using new initial model" )
285329 return f"{ ini_model_file } " , ini_ispyb_parameters
@@ -500,7 +544,7 @@ def run_class3d(class3d_params: Class3DParameters, send_to_rabbitmq: Callable) -
500544 "class_distribution" : classes_loop [class_id , 1 ],
501545 "rotation_accuracy" : classes_loop [class_id , 2 ],
502546 "translation_accuracy" : classes_loop [class_id , 3 ],
503- "angular_efficiency" : class_efficiencies [class_id ],
547+ "angular_efficiency" : float ( class_efficiencies [class_id ]) ,
504548 "suggested_tilt" : 0 if class_efficiencies [class_id ] > 0.65 else 30 ,
505549 }
506550 if job_is_rerun :
0 commit comments