1##################################################################
2##  (c) Copyright 2015-  by Jaron T. Krogel                     ##
3##################################################################
4
5
6#====================================================================#
7#  nexus_base.py                                                     #
8#    Provides base class functionality and access to 'global' data   #
9#    for core Nexus classes.                                         #
10#                                                                    #
11#  Content summary:                                                  #
12#    NexusCore                                                       #
13#      Base class for core Nexus classes.                            #
14#      Data intended to be 'global' among core classes is assigned   #
15#      by the Settings class.                                        #
16#                                                                    #
17#    nexus_core                                                      #
18#      Namespace to be accessed by core Nexus classes.               #
19#      These are classes that inherit from NexusCore directly.       #
20#                                                                    #
21#    nexus_noncore                                                   #
22#      Namespace to be accessed in read-only fashion by non-core     #
23#      classes.                                                      #
24#                                                                    #
25#====================================================================#
26
27
28import os
29import traceback
30import gc as garbage_collector
31from versions import nexus_version
32from memory import resident
33from generic import obj
34from developer import DevBase,log
35
36
37# Nexus namespaces
38#  nexus_core:   to be used by NexusCore classes only
39#  nexus_noncore: allows read only access to some nexus_core data to non-core classes
40nexus_core    = obj()
41nexus_noncore = obj()
42nexus_core_noncore = obj()
43
44status_modes = obj(
45    none     = 0,
46    standard = 1,
47    active   = 2,
48    failed   = 3,
49    ready    = 4,
50    )
51
52modes = obj(
53    none       = 0,
54    setup      = 1,
55    send_files = 2,
56    submit     = 3,
57    get_output = 4,
58    analyze    = 5,
59    stages     = 6,
60    all        = 7
61    )
62
63garbage_collector.enable()
64
65
66nexus_noncore_defaults = obj(
67    basis_dir         = None,
68    basissets         = None,
69    )
70
71# core namespace elements that can be accessed by noncore classes
72nexus_core_noncore_defaults = obj(
73    pseudo_dir        = None,              # used by: Settings, VaspInput
74    pseudopotentials  = None,              # used by: Simulation, GamessInput
75    )
76
77nexus_core_defaults = obj(
78    status_only       = False,             # used by: ProjectManager
79    generate_only     = False,             # used by: Simulation,Machine
80    sleep             = 3,                 # used by: ProjectManager
81    runs              = 'runs',            # used by: Simulation,Machine
82    results           = '',                # used by: Simulation
83    local_directory   = './',              # used by: Simulation,Machine
84    remote_directory  = './',              # used by: Simulation
85    file_locations    = ['./'],            # used by: Simulation
86    monitor           = True,              # used by: ProjectManager,Simulation,Machine
87    skip_submit       = False,             # used by: Simulation
88    load_images       = True,              # used by: ProjectManager
89    modes             = modes,             # used by: ProjectManager,Simulation
90    mode              = modes.stages,      # used by: Simulation
91    stages_set        = set(),             # used by: ProjectManager,Simulation
92    stages            = [],                # used by: Simulation
93    primary_modes     = ['setup','send_files','submit','get_output','analyze'], # used by: Settings
94    dependent_modes   = set(['submit']),   # used by: ProjectManager,Simulation
95    verbose           = True,              # used by: NexusCore
96    debug             = False,             # used by: NexusCore
97    trace             = False,             # used by: NexusCore
98    indent            = '  ',              # used by: NexusCore
99    status_modes      = status_modes,      # used by: ProjectManager
100    status            = status_modes.none, # used by: ProjectManager
101    emulate           = False,             # unused
102    progress_tty      = False,             # used by: ProjectManager
103    graph_sims        = False,             # used by: ProjectManager
104    command_line      = True,              # used by: Settings
105    **nexus_core_noncore_defaults
106    )
107
108def restore_nexus_core_defaults():
109    nexus_core.clear()
110    nexus_noncore.clear()
111    nexus_core_noncore.clear()
112
113    nexus_core.set(**nexus_core_defaults.copy())
114    nexus_noncore.set(**nexus_noncore_defaults.copy())
115    nexus_core_noncore.transfer_from(nexus_core,keys=list(nexus_core_noncore_defaults.keys()))
116#end def restore_nexus_core_defaults
117
118restore_nexus_core_defaults()
119
120
121nexus_core_no_process = set('''
122  status_only  generate_only  sleep
123  '''.split())
124
125
126class NexusCore(DevBase):
127
128    # garbage collector
129    gc = garbage_collector
130
131    # mutable/dynamic nexus core data
132    wrote_something   = False # for pretty printing
133    working_directory = None
134    wrote_splash      = False
135
136    @staticmethod
137    def write_splash():
138        if not NexusCore.wrote_splash:
139            splash_text = '''
140_____________________________________________________
141
142                     Nexus {}.{}.{}
143
144        (c) Copyright 2012-  Nexus developers
145
146                     Please cite:
147  J. T. Krogel Comput. Phys. Commun. 198 154 (2016)
148     https://doi.org/10.1016/j.cpc.2015.08.012
149_____________________________________________________
150
151            '''.format(*nexus_version)
152            log(splash_text)
153            NexusCore.wrote_splash = True
154        #end if
155    #end def write_splash
156
157    @staticmethod
158    def write_end_splash():
159        return # don't do this yet
160        splash_text = '''
161_____________________________________________________
162_____________________________________________________
163            '''
164        print(splash_text)
165    #end def write_end_splash
166
167    def mem_usage(self):
168        return int(resident()/1e6)
169    #end def mem_usage
170
171    def log(self,*texts,**kwargs):
172        """Write output to log file.
173           Keyword arguments
174            n - spaces to indent
175            progress - if True and output is to a terminal, overwrite and
176                       update the last line, rather than scrolling.
177        """
178        if nexus_core.verbose:
179            if len(kwargs)>0:
180                n = kwargs['n']
181            else:
182                n=0
183            #end if
184            is_progress = kwargs.get('progress',False)
185            text=''
186            for t in texts:
187                text+=str(t)+' '
188            #end for
189            pad = n*nexus_core.indent
190            output_text = pad+text.replace('\n','\n'+pad)
191            if nexus_core.progress_tty and is_progress and self._logfile.isatty():
192                # spaces to ensure previous line is overwritten.  Need better solution.
193                self._logfile.write(output_text+'        \r')
194                self._logfile.flush()
195            else:
196                self._logfile.write(output_text+'\n')
197        #end if
198        NexusCore.wrote_something = True
199    #end def log
200
201    def dlog(self,*texts,**kwargs):
202        if nexus_core.debug:
203            #self.log('mem_usage',self.mem_usage(),n=5)
204            self.log(*texts,**kwargs)
205        #end if
206    #end def dlog
207
208    def tlog(self,*texts,**kwargs):
209        if nexus_core.trace:
210            self.log(*texts,**kwargs)
211            w,s,j,f,g,a=int(self.setup),int(self.submitted),int(self.job.finished),int(self.finished),int(self.got_output),int(self.analyzed)
212            self.log('w,s,j,f,g,a',w,s,j,f,g,a,n=kwargs['n']+1)
213            #self.log('dependencies',self.dependencies.keys(),n=kwargs['n']+1)
214            #self.log('dependents  ',self.dependents.keys(),n=kwargs['n']+1)
215        #end if
216    #end def tlog
217
218    def enter(self,directory,changedir=True,msg=''):
219        NexusCore.working_directory = os.getcwd()
220        self.log('    Entering '+directory,msg)
221        if changedir:
222            os.chdir(directory)
223        #end if
224        pad = '      '
225        return pad
226    #end def enter
227
228    def leave(self):
229        os.chdir(NexusCore.working_directory)
230    #end def leave
231#end class NexusCore
232