1
+ ''' Manager classes handle the file maintainance of various runs.
2
+
3
+ They:
4
+ - Call write, run, and read in the appropriate order.
5
+ - Keep a record of progress on disk.
6
+ - Hold a list of all file paths together in one place.
7
+ - Report progress to the user.
8
+
9
+ All choices revolving around file names should be handled here.
10
+
11
+ Tips on avoiding bugs with the write/run/read cycle:
12
+ - Every time data is updated, write the updates to the disk.
13
+ - Every time the data is used, update the Manager from the disk.
14
+ '''
1
15
import crystal
2
16
import propertiesreader
3
17
import os
@@ -122,7 +136,7 @@ def __init__(self,writer,runner,creader=None,name='crystal_run',path=None,
122
136
123
137
self .logname = "%s@%s" % (self .__class__ .__name__ ,self .path + self .name )
124
138
125
- print (self .logname ,": initializing" )
139
+ # print(self.logname,": initializing")
126
140
127
141
# Handle reader and runner defaults.
128
142
self .writer = writer
@@ -163,7 +177,7 @@ def __init__(self,writer,runner,creader=None,name='crystal_run',path=None,
163
177
164
178
# Handle old results if present.
165
179
if os .path .exists (self .path + self .pickle ):
166
- print (self .logname ,": rebooting old manager." )
180
+ # print(self.logname,": rebooting old manager.")
167
181
old = pkl .load (open (self .path + self .pickle ,'rb' ))
168
182
self .recover (old )
169
183
@@ -188,7 +202,7 @@ def recover(self,other):
188
202
update_attributes (copyto = self .runner ,copyfrom = other .runner ,
189
203
skip_keys = ['queue' ,'walltime' ,'np' ,'nn' ,'jobname' ],
190
204
take_keys = ['queueid' ])
191
- update_attributes (copyto = self .runner ,copyfrom = other .runner ,
205
+ update_attributes (copyto = self .prunner ,copyfrom = other .prunner ,
192
206
skip_keys = ['queue' ,'walltime' ,'np' ,'nn' ,'jobname' ],
193
207
take_keys = ['queueid' ])
194
208
@@ -209,6 +223,7 @@ def recover(self,other):
209
223
#----------------------------------------
210
224
def nextstep (self ):
211
225
''' Determine and perform the next step in the calculation.'''
226
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
212
227
213
228
print (self .logname ,": next step." )
214
229
cwd = os .getcwd ()
@@ -321,6 +336,9 @@ def write_summary(self):
321
336
#------------------------------------------------
322
337
def export_qwalk (self ):
323
338
''' Export QWalk input files into current directory.'''
339
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
340
+
341
+ ready = False
324
342
if len (self .qwfiles ['slater' ])== 0 :
325
343
self .nextstep ()
326
344
@@ -336,6 +354,7 @@ def export_qwalk(self):
336
354
status = resolve_status (self .prunner ,self .preader ,self .propoutfn )
337
355
print (self .logname ,": properties status= %s" % (status ))
338
356
if status == 'not_started' :
357
+ ready = False
339
358
self .prunner .add_command ("cp %s INPUT" % self .propinpfn )
340
359
self .prunner .add_task ("Pproperties &> %s" % self .propoutfn )
341
360
@@ -348,14 +367,18 @@ def export_qwalk(self):
348
367
self .preader .collect (self .propoutfn )
349
368
350
369
if self .preader .completed :
370
+ ready = True
351
371
self .qwfiles = crystal2qmc .convert_crystal (base = self .name ,propoutfn = self .propoutfn )
352
372
print (self .logname ,": crystal converted to QWalk input." )
353
373
354
374
os .chdir (cwd )
375
+ else :
376
+ ready = True
377
+
355
378
with open (self .path + self .pickle ,'wb' ) as outf :
356
379
pkl .dump (self ,outf )
357
380
358
- return True
381
+ return ready
359
382
360
383
#----------------------------------------
361
384
def status (self ):
@@ -388,7 +411,7 @@ def __init__(self,writer,reader=None,runner=None,name='psycf_run',path=None,bund
388
411
389
412
self .logname = "%s@%s" % (self .__class__ .__name__ ,self .path + self .name )
390
413
391
- print (self .logname ,": initializing" )
414
+ # print(self.logname,": initializing")
392
415
393
416
self .writer = writer
394
417
if reader is not None : self .reader = reader
@@ -417,24 +440,33 @@ def __init__(self,writer,reader=None,runner=None,name='psycf_run',path=None,bund
417
440
if os .path .exists (self .path + self .pickle ):
418
441
print (self .logname ,": rebooting old manager." )
419
442
old = pkl .load (open (self .path + self .pickle ,'rb' ))
420
- if False : #not self.is_consistent(old): TODO check consistency.
421
- raise NotImplementedError ("Handling updated input files is not implemented yet." )
422
- else :
423
- self .__dict__ = old .__dict__
443
+ self .recover (old )
424
444
425
445
# Update the file.
426
446
if not os .path .exists (self .path ): os .mkdir (self .path )
427
447
with open (self .path + self .pickle ,'wb' ) as outf :
428
448
pkl .dump (self ,outf )
429
449
430
450
#------------------------------------------------
431
- def update_options (self ,other ):
451
+ def recover (self ,other ):
432
452
''' Safe copy options from other to self. '''
433
- updated = update_attributes (old = self .writer ,new = other .writer ,
434
- safe_keys = ['max_cycle' ],
435
- skip_keys = ['completed' ,'chkfile' ,'dm_generator' ])
436
- if updated :
437
- self .writer .completed = False
453
+ # Practically speaking, the run will preserve old `take_keys` and allow new changes to `skip_keys`.
454
+ # This is because you are taking the attributes from the older instance, and copying into the new instance.
455
+ updated = update_attributes (copyto = self ,copyfrom = other ,
456
+ skip_keys = ['writer' ,'runner' ,'reader' , 'path' ,'logname' ,'name' ,'max_restarts' ,'bundle' ],
457
+ take_keys = ['restarts' ,'completed' ,'qwfiles' ])
458
+
459
+ update_attributes (copyto = self .runner ,copyfrom = other .runner ,
460
+ skip_keys = ['queue' ,'walltime' ,'np' ,'nn' ,'jobname' ],
461
+ take_keys = ['queueid' ])
462
+
463
+ update_attributes (copyto = self .reader ,copyfrom = other .reader ,
464
+ skip_keys = [],
465
+ take_keys = ['completed' ,'output' ])
466
+
467
+ updated = update_attributes (copyto = self .writer ,copyfrom = other .writer ,
468
+ skip_keys = ['max_cycle' ],
469
+ take_keys = ['completed' ,'dm_generator' ])
438
470
439
471
# Update the file.
440
472
with open (self .path + self .pickle ,'wb' ) as outf :
@@ -443,6 +475,9 @@ def update_options(self,other):
443
475
#------------------------------------------------
444
476
def nextstep (self ):
445
477
''' Determine and perform the next step in the calculation.'''
478
+ # Recover old data.
479
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
480
+
446
481
print (self .logname ,": next step." )
447
482
cwd = os .getcwd ()
448
483
os .chdir (self .path )
@@ -495,6 +530,9 @@ def update_queueid(self,qid):
495
530
#------------------------------------------------
496
531
def export_qwalk (self ):
497
532
''' Export QWalk input files into current directory.'''
533
+ # Recover old data.
534
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
535
+
498
536
if len (self .qwfiles ['slater' ])== 0 :
499
537
self .nextstep ()
500
538
if not self .completed :
@@ -546,7 +584,7 @@ def __init__(self,writer,reader,runner=None,trialfunc=None,
546
584
547
585
self .logname = "%s@%s" % (self .__class__ .__name__ ,self .path + self .name )
548
586
549
- print (self .logname ,": initializing" )
587
+ # print(self.logname,": initializing")
550
588
551
589
self .writer = writer
552
590
self .reader = reader
@@ -604,42 +642,23 @@ def recover(self,other):
604
642
if updated :
605
643
self .writer .completed = False
606
644
607
- #------------------------------------------------
608
- def update_options (self ,other ):
609
- ''' Safe copy options from other to self.
610
-
611
- Args:
612
- other (QWRunManager): New object to copy attributes from.
613
- '''
614
-
615
- update_attributes (old = self .runner ,new = other .runner ,
616
- safe_keys = ['queue' ,'walltime' ,'np' ,'nn' ,'jobname' ,'prefix' ,'postfix' ],
617
- skip_keys = ['queueid' ])
618
-
619
- # trialfunc gets updated as the manager generating it finishes its calculation.
620
- update_attributes (old = self .writer ,new = other .writer ,
621
- skip_keys = ['completed' ,'trialfunc' ])
622
-
623
- # Update the file.
624
- with open (self .path + self .pickle ,'wb' ) as outf :
625
- pkl .dump (self ,outf )
626
-
627
645
#------------------------------------------------
628
646
def nextstep (self ):
629
647
''' Perform next step in calculation. trialfunc managers are updated if they aren't completed yet.'''
648
+ # Recover old data.
649
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
630
650
631
651
print (self .logname ,": next step." )
632
652
633
653
# Check dependency is completed first.
634
654
if self .writer .trialfunc == '' :
655
+ print (self .logname ,": checking trial function." )
635
656
self .writer .trialfunc = self .trialfunc .export (self .path )
636
657
637
658
# Work on this job.
638
659
cwd = os .getcwd ()
639
660
os .chdir (self .path )
640
661
641
- dir (self .reader )
642
-
643
662
# Write the input file.
644
663
if not self .writer .completed :
645
664
self .writer .qwalk_input (self .infile )
@@ -662,8 +681,6 @@ def nextstep(self):
662
681
self .runner .add_task (exestr )
663
682
elif status == 'done' :
664
683
self .completed = True
665
- else :
666
- print (self .logname ,": %s status= %s" % (self .name ,status ))
667
684
668
685
# Ready for bundler or else just submit the jobs as needed.
669
686
if self .bundle :
@@ -717,6 +734,9 @@ def export_qwalk(self):
717
734
''' Extract jastrow from the optimization run and return that file name.'''
718
735
# Theoretically more than just Jastrow can be provided, but practically that's the only type of wavefunction we tend to export.
719
736
737
+ # Recover old data.
738
+ self .recover (pkl .load (open (self .path + self .pickle ,'rb' )))
739
+
720
740
assert self .writer .qmc_abr != 'dmc' ,"DMC doesn't provide a wave function."
721
741
722
742
if self .qwfiles ['wfout' ]== '' :
0 commit comments