Package nMOLDYN :: Package Analysis :: Module Template |
[hide private]
[frames] | no frames]

# Source Code for Module nMOLDYN.Analysis.Template

      1  """
      2  This modules implements the estimate, serial and parrallel templates for all analysis.
      3  """
      4
      5  # The Python distribution modules.
      6  import getpass
      7  import os
      8  import subprocess
      9  import sys
     10  from time import asctime, sleep
     11  from timeit import default_timer
     12
     13  # The Scientific module.
     14  from Scientific.DistributedComputing.MasterSlave import initializeMasterProcess, TaskRaisedException
     15
     16  # The nMOLDYN modules.
     17  from nMOLDYN.Core.Error import Error
     18  from nMOLDYN.Core.Logger import LogMessage
     19  from nMOLDYN.Analysis import Analysis
     20  from nMOLDYN.Analysis.Dynamics import *
     21  from nMOLDYN.Analysis.NMR import *
     22  from nMOLDYN.Analysis.Scattering import *
     23  from nMOLDYN.Analysis.Structure import *
     24
     25  # Package path
     26  nmoldyn_package_path = os.path.dirname(os.path.split(__file__)[0])
     27
     28 -def startSlaves(taskName, pyroServer, pyroNodes):
     29      """Starts the slaves.
     30
     31      @param pyroServer: the type of pyro server. One of 'multiprocessor' or 'cluster'.
     32      @type pyroServer: string.
     33
     34      @param pyroNodes: a dictionnary whose keys are the name of the nodes and the value
     35      the number of cpus to allocate to this node.
     36      @type pyroNodes: dict.
     37      """
     38
     39      taskmanager = os.path.join(os.path.dirname(sys.executable), 'task_manager')
     40
     41      # Case of an analysis launched only on localhost.
     42      if pyroServer == 'multiprocessor':
     43          for k, v in pyroNodes.items():
     44              [subprocess.Popen([taskmanager, 'slave', taskName]) for p in range(v)]
     45
     46      elif pyroServer == 'cluster':
     47          raise NotImplementedError
     48
     49  # #################################
     50  # atom-by-atom abstract classes
     51  # #################################
     52 -class SerialPerAtom:
     53      """Template class for an analysis atom-by-atom ran in serial mode.
     54      """
     55
     56 -    def internalRun(self):
     57          """Performs the analysis in serial mode.
     58          """
     59
     60          # Estimate mode. First evaluate the time taken to parse the trajectory file for all selected atoms.
     61          if self.estimate:
     62              self.offset = default_timer()
     63
     64              first = True
     65              for atom in self.subset:
     66                  junk = self.trajectory.readParticleTrajectory(atom, first = self.first, last = self.last, skip = self.skip).array
     67                  if first:
     68                      timeToReadFirstAtom = default_timer() - self.offset
     69                      first = False
     70
     71              self.offset = default_timer() - self.offset - self.nAtoms*timeToReadFirstAtom
     72
     73              for atom in self.subset:
     74                  self.chrono = default_timer()
     75                  x = self.calc(atom, self.trajectoryFilename)
     76                  self.combine(atom,x)
     77                  self.updateJobProgress(1)
     78                  break
     79
     80              # The estimation is computed as:
     81              # Tau = Sum(ri - r1) + N*(r1 + c1) with
     82              # N  = number of atoms.
     83              # ri = time to read trajectory of atom i
     84              # r1 = time to read the trajectory of atom 1
     85              # c1 = time to process atom 1 (by hypothesis c1 ~ c2 ~ c3 ... ~ cN)
     86              self.chrono = int(self.offset + self.nAtoms*(default_timer() - self.chrono))
     87
     88          else:
     89              # The analysis actual starting time.
     90              self.chrono = default_timer()
     91
     92              for atom in self.subset:
     93                  x = self.calc(atom, self.trajectoryFilename)
     94                  self.combine(atom,x)
     95                  self.updateJobProgress(self.nAtoms)
     96
     97              self.finalize()
     98
     99              # The actual time taken for the analysis.
    100              self.chrono = int(default_timer() - self.chrono)
    101
    102 -class ParallelPerAtom:
    103      """Template class for an analysis atom-by-atom ran in parallel mode.
    104      """
    105
    106 -    def internalRun(self):
    107          """Performs the analysis in parallel mode.
    108          """
    109
    110          LogMessage('info', 'Setting Pyro name server. Please wait ...', ['console'])
    111
    112          s = subprocess.Popen([sys.executable, '-m', 'Pyro.naming'], stdout = subprocess.PIPE)
    113
    114          # let a few seconds to the pyroserver to start up
    115          sleep(3)
    116
    117          # This should be enough to create a unique task name.
    118          self.taskName = '%s_%s_%s' % (self.shortName, getpass.getuser(), '_'.join(asctime().split()))
    119
    120  #        tasks = initializeMasterProcess(self.taskName, slave_module = 'nMOLDYN.Analysis.Slave', use_name_server = True)
    121          script = os.path.abspath(os.path.join(os.path.dirname(__file__), 'Slave.py'))
    122          tasks = initializeMasterProcess(self.taskName, slave_script = script, use_name_server = True)
    123
    124          for atom in self.subset:
    125              task_id = tasks.requestTask("analysisPerElement", self, atom, self.trajectoryFilename)
    126
    127          startSlaves(self.taskName, self.pyroServer, self.pyroNodes)
    128
    129          LogMessage('info', 'Pyro name server ready.', ['console'])
    130
    131          # The analysis actual starting time.
    132          self.chrono = default_timer()
    133
    134          for atom in self.subset:
    135
    136              try:
    137                  task_id, tag, x = tasks.retrieveResult("analysisPerElement")
    138                  self.combine(atom,x)
    139                  self.updateJobProgress(self.nAtoms)
    140
    141              except:
    142                  raise Error('Error when retrieving the results over the pyroserver.')
    143
    144          self.finalize()
    145
    146          # The actual time taken for the analysis.
    147          self.chrono = int(default_timer() - self.chrono)
    148
    149  # #################################
    150  # frame-by-frame abstract classes
    151  # #################################
    152 -class SerialPerFrame:
    153      """Template class for an analysis atom-by-atom ran in serial mode.
    154      """
    155
    156 -    def internalRun(self):
    157          """Performs the analysis in serial mode.
    158          """
    159
    160          if self.estimate:
    161              self.offset = default_timer()
    162
    163              first = True
    164              for frameIndex in range(self.nFrames):
    165                  frame = self.frameIndexes[frameIndex]
    166                  self.universe.setFromTrajectory(self.trajectory, frame)
    167                  if first:
    168                      timeToReadFirstFrame = default_timer() - self.offset
    169                      first = False
    170
    171              self.offset = default_timer() - self.offset - self.nFrames*timeToReadFirstFrame
    172
    173              # Treat only the first frame.
    174              for frameIndex in range(self.nFrames):
    175                  self.chrono = default_timer()
    176                  x = self.calc(frameIndex, self.trajectoryFilename)
    177                  self.combine(frameIndex,x)
    178                  self.updateJobProgress(1)
    179                  break
    180
    181              # The estimation is computed as:
    182              # Tau = Sum(ri - r1) + N*(r1 + c1) with
    183              # N  = number of frames.
    184              # ri = time to read the frame i
    185              # r1 = time to read the frame 1
    186              # c1 = time to process frame 1 (by hypothesis c1 ~ c2 ~ c3 ... ~ cN)
    187              self.chrono = int(self.offset + self.nFrames*(default_timer() - self.chrono))
    188
    189          else:
    190              # The analysis actual starting time.
    191              self.chrono = default_timer()
    192
    193              for frameIndex in range(self.nFrames):
    194                  x = self.calc(frameIndex, self.trajectoryFilename)
    195                  self.combine(frameIndex,x)
    196                  self.updateJobProgress(self.nFrames)
    197
    198              self.finalize()
    199
    200              # The actual time taken for the analysis.
    201              self.chrono = int(default_timer() - self.chrono)
    202
    203 -class ParallelPerFrame:
    204      """Template class for an analysis frame-by-frame ran in parallel mode.
    205      """
    206
    207 -    def internalRun(self):
    208          """Performs the analysis in parallel mode.
    209          """
    210
    211          LogMessage('info', 'Setting Pyro name server. Please wait ...', ['console'])
    212
    213          s = subprocess.Popen([sys.executable, '-m', 'Pyro.naming'], stdout = subprocess.PIPE)
    214
    215          # let a few seconds to the pyroserver to start up
    216          sleep(3)
    217
    218          # This should be enough to create a unique task name.
    219          self.taskName = '%s_%s_%s' % (self.shortName, getpass.getuser(), '_'.join(asctime().split()))
    220
    221  #        tasks = initializeMasterProcess(self.taskName, slave_module = 'nMOLDYN.Analysis.Slave', use_name_server = True)
    222          script = os.path.abspath(os.path.join(os.path.dirname(__file__), 'Slave.py'))
    223          tasks = initializeMasterProcess(self.taskName, slave_script = script, use_name_server = True)
    224
    225          for frameIndex in range(self.nFrames):
    226              task_id = tasks.requestTask("analysisPerElement", self, frameIndex, self.trajectoryFilename)
    227
    228          startSlaves(self.taskName, self.pyroServer, self.pyroNodes)
    229
    230          LogMessage('info', 'Pyro name server ready.', ['console'])
    231
    232          # The analysis actual starting time.
    233          self.chrono = default_timer()
    234
    235          for frameIndex in range(self.nFrames):
    236              try:
    237                  task_id, tag, x = tasks.retrieveResult("analysisPerElement")
    238                  self.combine(frameIndex,x)
    239                  self.updateJobProgress(self.nFrames)
    240
    241              except:
    242                  raise Error('Error when retrieving the results over the pyroserver.')
    243
    244          self.finalize()
    245
    246          # The actual time taken for the analysis.
    247          self.chrono = int(default_timer() - self.chrono)
    248
    249  # #################################
    250  # group-by-group abstract classes
    251  # #################################
    252 -class SerialPerGroup:
    253      """Template class for an analysis group-by-group ran in serial mode.
    254      """
    255
    256 -    def internalRun(self):
    257          """Performs the analysis in serial mode.
    258          """
    259
    260          if self.estimate:
    261              self.offset = default_timer()
    262
    263              first = True
    264              for groupIndex in range(self.nGroups):
    265                  g = self.group[groupIndex]
    266                  junk = self.trajectory.readRigidBodyTrajectory(g,\
    267                                                                 first = self.first,\
    268                                                                 last = self.last,\
    269                                                                 skip = self.skip,\
    270                                                                 reference = self.refConfig)
    271                  if first:
    272                      timeToReadFirstGroup = default_timer() - self.offset
    273                      first = False
    274
    275              self.offset = default_timer() - self.offset - self.nGroups*timeToReadFirstGroup
    276
    277              # Treat only the first group.
    278              for groupIndex in range(self.nGroups):
    279                  self.chrono = default_timer()
    280                  x = self.calc(groupIndex, self.trajectoryFilename)
    281                  self.combine(groupIndex, x)
    282                  self.updateJobProgress(1)
    283                  break
    284
    285              # The estimation is computed as:
    286              # Tau = Sum(ri - r1) + N*(r1 + c1) with
    287              # N  = number of frames.
    288              # ri = time to read the frame i
    289              # r1 = time to read the frame 1
    290              # c1 = time to process frame 1 (by hypothesis c1 ~ c2 ~ c3 ... ~ cN)
    291              self.chrono = int(self.offset + self.nGroups*(default_timer() - self.chrono))
    292
    293          else:
    294              # The analysis actual starting time.
    295              self.chrono = default_timer()
    296
    297              for groupIndex in range(self.nGroups):
    298                  x = self.calc(groupIndex, self.trajectoryFilename)
    299                  self.combine(groupIndex, x)
    300                  self.updateJobProgress(self.nGroups)
    301
    302              self.finalize()
    303
    304              # The actual time taken for the analysis.
    305              self.chrono = int(default_timer() - self.chrono)
    306
    307 -class ParallelPerGroup:
    308      """Template class for an analysis group-by-group ran in parallel mode.
    309      """
    310
    311 -    def internalRun(self):
    312          """Performs the analysis in parallel mode.
    313          """
    314
    315          LogMessage('info', 'Setting Pyro name server. Please wait ...', ['console'])
    316
    317          s = subprocess.Popen([sys.executable, '-m', 'Pyro.naming'], stdout = subprocess.PIPE)
    318
    319          # let a few seconds to the pyroserver to start up
    320          sleep(3)
    321
    322          # This should be enough to create a unique task name.
    323          self.taskName = '%s_%s_%s' % (self.shortName, getpass.getuser(), '_'.join(asctime().split()))
    324
    325  #        tasks = initializeMasterProcess(self.taskName, slave_module = 'nMOLDYN.Analysis.Slave', use_name_server = True)
    326          script = os.path.abspath(os.path.join(os.path.dirname(__file__), 'Slave.py'))
    327          tasks = initializeMasterProcess(self.taskName, slave_script = script, use_name_server = True)
    328
    329          for groupIndex in range(self.nGroups):
    330              task_id = tasks.requestTask("analysisPerElement", self, groupIndex, self.trajectoryFilename)
    331
    332          startSlaves(self.taskName, self.pyroServer, self.pyroNodes)
    333
    334          LogMessage('info', 'Pyro name server ready.', ['console'])
    335
    336          # The analysis actual starting time.
    337          self.chrono = default_timer()
    338
    339          for groupIndex in range(self.nGroups):
    340              try:
    341                  task_id, tag, x = tasks.retrieveResult("analysisPerElement")
    342                  self.combine(groupIndex, x)
    343                  self.updateJobProgress(self.nGroups)
    344
    345              except:
    346                  raise Error('Error when retrieving the results over the pyroserver.')
    347
    348          self.finalize()
    349
    350          # The actual time taken for the analysis.
    351          self.chrono = int(default_timer() - self.chrono)
    352
    353 -class SerialPerQShell:
    354      """Template class for an analysis qshell-by-qshell ran in serial mode.
    355      """
    356
    357 -    def internalRun(self):
    358          """Performs the analysis in serial mode.
    359          """
    360          # The analysis actual starting time.
    361          self.chrono = default_timer()
    362
    363          for qIndex in range(self.nQValues):
    364              x = self.calc(qIndex, self.trajectoryFilename)
    365              self.combine(qIndex, x)
    366              self.updateJobProgress(self.nQValues)
    367
    368          self.finalize()
    369
    370          # The analysis actual starting time.
    371          self.chrono = default_timer()
    372
    373 -class ParallelPerQShell:
    374      """Template class for an analysis qshell-by-qshell ran in parallel mode.
    375      """
    376
    377 -    def internalRun(self):
    378          """Performs the analysis in parallel mode.
    379          """
    380
    381          LogMessage('info', 'Setting Pyro name server. Please wait ...', ['console'])
    382
    383          s = subprocess.Popen([sys.executable, '-m', 'Pyro.naming'], stdout = subprocess.PIPE)
    384
    385          sleep(3)
    386
    387          # This should be enough to create a unique task name.
    388          self.taskName = '%s_%s_%s' % (self.shortName, getpass.getuser(), '_'.join(asctime().split()))
    389
    390  #        tasks = initializeMasterProcess(self.taskName, slave_module = 'nMOLDYN.Analysis.Slave', use_name_server = True)
    391          script = os.path.abspath(os.path.join(os.path.dirname(__file__), 'Slave.py'))
    392          tasks = initializeMasterProcess(self.taskName, slave_script = script, use_name_server = True)
    393
    394          for qIndex in range(self.nQValues):
    395              task_id = tasks.requestTask("analysisPerElement", self, qIndex, self.trajectoryFilename)
    396
    397          startSlaves(self.taskName, self.pyroServer, self.pyroNodes)
    398
    399          LogMessage('info', 'Pyro name server ready.', ['console'])
    400
    401          # The analysis actual starting time.
    402          self.chrono = default_timer()
    403
    404          for qIndex in range(self.nQValues):
    405              try:
    406                  task_id, tag, x = tasks.retrieveResult("analysisPerElement")
    407                  self.combine(qIndex, x)
    408                  self.updateJobProgress(self.nQValues)
    409
    410              except:
    411                  raise Error('Error when retrieving the results over the pyroserver.')
    412
    413          self.finalize()
    414
    415          # The actual time taken for the analysis.
    416          self.chrono = int(default_timer() - self.chrono)
    417
    418  # The templates for each analysis that will be parallelized.
    419  # By construction, those that are not currently parallelizable will have only a serial version.
    420
    421  # ############
    422  # MSD
    423  # ############
    424 -class MeanSquareDisplacement_serial(Analysis, MeanSquareDisplacement, SerialPerAtom):
    425      pass
    426
    427 -class MeanSquareDisplacement_parallel(Analysis, MeanSquareDisplacement, ParallelPerAtom):
    428      pass
    429
    430  # ############
    431  # RMSD
    432  # ############
    433 -class RootMeanSquareDeviation_serial(Analysis, RootMeanSquareDeviation, SerialPerAtom):
    434      pass
    435
    436 -class RootMeanSquareDeviation_parallel(Analysis, RootMeanSquareDeviation, ParallelPerAtom):
    437      pass
    438
    439  # ############
    440  # VACF
    441  # ############
    442 -class CartesianVelocityAutoCorrelationFunction_serial(Analysis, CartesianVelocityAutoCorrelationFunction, SerialPerAtom):
    443      pass
    444
    445 -class CartesianVelocityAutoCorrelationFunction_parallel(Analysis, CartesianVelocityAutoCorrelationFunction, ParallelPerAtom):
    446      pass
    447
    448  # ############
    449  # DOS
    450  # ############
    451 -class CartesianDensityOfStates_serial(Analysis, CartesianDensityOfStates, SerialPerAtom):
    452      pass
    453
    454 -class CartesianDensityOfStates_parallel(Analysis, CartesianDensityOfStates, ParallelPerAtom):
    455      pass
    456
    457  # ############
    458  # ARA
    459  # ############
    460 -class AutoRegressiveAnalysis_serial(Analysis, AutoRegressiveAnalysis, SerialPerAtom):
    461      pass
    462
    463 -class AutoRegressiveAnalysis_parallel(Analysis, AutoRegressiveAnalysis, ParallelPerAtom):
    464      pass
    465
    466  # ############
    467  # PBFT
    468  # ############
    469 -class PassBandFilteredTrajectory_serial(Analysis, PassBandFilteredTrajectory, SerialPerAtom):
    470      pass
    471
    472 -class PassBandFilteredTrajectory_parallel(Analysis, PassBandFilteredTrajectory, ParallelPerAtom):
    473      pass
    474
    475  # ############
    476  # ISF
    477  # ############
    478 -class DynamicIncoherentStructureFactor_serial(Analysis, DynamicIncoherentStructureFactor, SerialPerAtom):
    479      pass
    480
    481 -class DynamicIncoherentStructureFactor_parallel(Analysis, DynamicIncoherentStructureFactor, ParallelPerAtom):
    482      pass
    483
    484  # ############
    485  # ISFG
    486  # ############
    487 -class DynamicIncoherentStructureFactorGaussian_serial(Analysis, DynamicIncoherentStructureFactorGaussian, SerialPerAtom):
    488      pass
    489
    490 -class DynamicIncoherentStructureFactorGaussian_parallel(Analysis, DynamicIncoherentStructureFactorGaussian, ParallelPerAtom):
    491      pass
    492
    493  # ############
    494  # EISF
    495  # ############
    496 -class ElasticIncoherentStructureFactor_serial(Analysis, ElasticIncoherentStructureFactor, SerialPerAtom):
    497      pass
    498
    499 -class ElasticIncoherentStructureFactor_parallel(Analysis, ElasticIncoherentStructureFactor, ParallelPerAtom):
    500      pass
    501
    502  # ############
    503  # ROG
    504  # ############
    505 -class RadiusOfGyration_serial(Analysis, RadiusOfGyration, SerialPerAtom):
    506      pass
    507
    508 -class RadiusOfGyration_parallel(Analysis, RadiusOfGyration, ParallelPerAtom):
    509      pass
    510
    511  # ############
    512  # DISFAR
    513  # ############
    514 -class DynamicIncoherentStructureFactorAR_serial(Analysis, DynamicIncoherentStructureFactorAR, SerialPerAtom):
    515      pass
    516
    517 -class DynamicIncoherentStructureFactorAR_parallel(Analysis, DynamicIncoherentStructureFactorAR, ParallelPerAtom):
    518      pass
    519
    520  # ############
    521  # SSCSF
    522  # ############
    523 -class SmoothedStaticCoherentStructureFactor_serial(Analysis, SmoothedStaticCoherentStructureFactor, SerialPerFrame):
    524      pass
    525
    526 -class SmoothedStaticCoherentStructureFactor_parallel(Analysis, SmoothedStaticCoherentStructureFactor, ParallelPerFrame):
    527      pass
    528
    529  # ############
    530  # PDF
    531  # ############
    532 -class PairDistributionFunction_serial(Analysis, PairDistributionFunction, SerialPerFrame):
    533      pass
    534
    535 -class PairDistributionFunction_parallel(Analysis, PairDistributionFunction, ParallelPerFrame):
    536      pass
    537
    538  # ############
    539  # CN
    540  # ############
    541 -class CoordinationNumber_serial(Analysis, CoordinationNumber, SerialPerFrame):
    542      pass
    543
    544 -class CoordinationNumber_parallel(Analysis, CoordinationNumber, ParallelPerFrame):
    545      pass
    546
    547  # ############
    548  # SFA
    549  # ############
    550 -class ScrewFitAnalysis_serial(Analysis, ScrewFitAnalysis, SerialPerFrame):
    551      pass
    552
    553 -class ScrewFitAnalysis_parallel(Analysis, ScrewFitAnalysis, ParallelPerFrame):
    554      pass
    555
    556  # ############
    557  # SD
    558  # ############
    559 -class SpatialDensity_serial(Analysis, SpatialDensity, SerialPerFrame):
    560      pass
    561
    562 -class SpatialDensity_parallel(Analysis, SpatialDensity, ParallelPerFrame):
    563      pass
    564
    565  # ############
    566  # GMTF
    567  # ############
    568 -class GlobalMotionFilteredTrajectory_serial(Analysis, GlobalMotionFilteredTrajectory, SerialPerFrame):
    569      pass
    570
    571 -class GlobalMotionFilteredTrajectory_parallel(Analysis, GlobalMotionFilteredTrajectory, ParallelPerFrame):
    572      pass
    573
    574  # ############
    575  # COMT
    576  # ############
    577 -class CenterOfMassTrajectory_serial(Analysis, CenterOfMassTrajectory, SerialPerFrame):
    578      pass
    579
    580 -class CenterOfMassTrajectory_parallel(Analysis, CenterOfMassTrajectory, ParallelPerFrame):
    581      pass
    582
    583  # ############
    584  # OPCM
    585  # ############
    586 -class OrderParameterContactModel_serial(Analysis, OrderParameterContactModel, SerialPerFrame):
    587      pass
    588
    589 -class OrderParameterContactModel_parallel(Analysis, OrderParameterContactModel, ParallelPerFrame):
    590      pass
    591
    592  # ############
    593  # AC
    594  # ############
    595 -class AngularCorrelation_serial(Analysis, AngularCorrelation, SerialPerGroup):
    596      pass
    597
    598 -class AngularCorrelation_parallel(Analysis, AngularCorrelation, ParallelPerGroup):
    599      pass
    600
    601  # ############
    602  # RBT
    603  # ############
    604 -class RigidBodyTrajectory_serial(Analysis, RigidBodyTrajectory, SerialPerGroup):
    605      pass
    606
    607 -class RigidBodyTrajectory_parallel(Analysis, RigidBodyTrajectory, ParallelPerGroup):
    608      pass
    609
    610  # ############
    611  # RCF
    612  # ############
    613 -class ReorientationalCorrelationFunction_serial(Analysis, ReorientationalCorrelationFunction, SerialPerGroup):
    614      pass
    615
    616 -class ReorientationalCorrelationFunction_parallel(Analysis, ReorientationalCorrelationFunction, ParallelPerGroup):
    617      pass
    618
    619  # ############
    620  # AVACF
    621  # ############
    622 -class AngularVelocityAutoCorrelationFunction_serial(Analysis, AngularVelocityAutoCorrelationFunction, SerialPerGroup):
    623      pass
    624
    625 -class AngularVelocityAutoCorrelationFunction_parallel(Analysis, AngularVelocityAutoCorrelationFunction, ParallelPerGroup):
    626      pass
    627
    628  # ############
    629  # ADOS
    630  # ############
    631 -class AngularDensityOfStates_serial(Analysis, AngularDensityOfStates, SerialPerGroup):
    632      pass
    633
    634 -class AngularDensityOfStates_parallel(Analysis, AngularDensityOfStates, ParallelPerGroup):
    635      pass
    636
    637  # ############
    638  # OP
    639  # ############
    640 -class OrderParameter_serial(Analysis, OrderParameter, SerialPerGroup):
    641      pass
    642
    643 -class OrderParameter_parallel(Analysis, OrderParameter, ParallelPerGroup):
    644      pass
    645
    646  # ############
    647  # QHA
    648  # ############
    649 -class QuasiHarmonicAnalysis_serial(Analysis, QuasiHarmonicAnalysis):
    650      pass
    651
    652  # ############
    653  # DCSF
    654  # ############
    655 -class DynamicCoherentStructureFactor_serial(Analysis, DynamicCoherentStructureFactor, SerialPerQShell):
    656      pass
    657
    658 -class DynamicCoherentStructureFactor_parallel(Analysis, DynamicCoherentStructureFactor, ParallelPerQShell):
    659      pass
    660
    661  # ############
    662  # SCSF
    663  # ############
    664 -class StaticCoherentStructureFactor_serial(Analysis, StaticCoherentStructureFactor, SerialPerQShell):
    665      pass
    666
    667 -class StaticCoherentStructureFactor_parallel(Analysis, StaticCoherentStructureFactor, ParallelPerQShell):
    668      pass
    669
    670  # ############
    671  # DCSFAR
    672  # ############
    673 -class DynamicCoherentStructureFactorAR_serial(Analysis, DynamicCoherentStructureFactorAR, SerialPerQShell):
    674      pass
    675
    676 -class DynamicCoherentStructureFactorAR_parallel(Analysis, DynamicCoherentStructureFactorAR, ParallelPerQShell):
    677      pass
    678