<commit_before># $Id: module_base.py,v 1.15 2002/05/03 11:44:48 cpbotha Exp $

# ----------------------------------------------------------------------------

"""Module containing class-related utilities and code for dscas3 modules.

In this module you'll find a base class as well as several useful mixins.
Please see the documentation.

author: Charl P. Botha <cpbotha@ieee.org>
"""

class module_base:
    """Base class for all modules.

    Any module wishing to take part in the dscas3 party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """We need to know where the module manager is so we can query
        it about the module path, e.g.
        """
        self._module_manager = module_manager

    def close(self):
	"""Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """
	raise NotImplementedError

    def get_input_descriptions(self):
	"""Returns tuple of input descriptions, mostly used by the graph editor
	to make a nice glyph for this module."""
	raise NotImplementedError

    def set_input(self, idx, input_stream):
	"""Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.
        """
	raise NotImplementedError

    def get_output_descriptions(self):
	"""Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
	raise NotImplementedError

    def get_output(self, idx):
	"""Get the n-th output.

        This will be used for connecting this output to the input of another
        module.
        """
	raise NotImplementedError

    def sync_config(self):
	raise NotImplementedError

    def apply_config(self):
	raise NotImplementedError

    def execute_module(self):
	raise NotImplementedError

    def view(self):
	"""Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.
        """
	raise NotImplementedError

# ----------------------------------------------------------------------------

from vtkPipeline.ConfigVtkObj import ConfigVtkObj
from vtkPipeline.vtkPipeline import vtkPipelineBrowser

class module_mixin_vtk_pipeline_config:
    """Mixin to use for modules that want to make use of the vtkPipeline
    functionality.

    Modules that use this as mixin can make use of the vtk_object_configure
    and vtk_pipeline_configure methods to use ConfigVtkObj and
    vtkPipelineBrowser, respectively.  These methods will make sure that you
    use only one instance of a browser/config class per object.
    """

    def vtk_object_configure(self, parent, renwin, vtk_obj):
        """This will instantiate and show only one object config frame per
        unique vtk_obj (per module instance).

        If it is called multiple times for the same object, it will merely
        bring the pertinent window to the top (by show()ing).

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroyed.
        renwin: render window (optionally None) which will be
        render()ed when changes are made to the vtk object which is being
        configured.
        vtk_obj: the object you want to config.
        """
        if not hasattr(self, '_vtk_obj_cfs'):
            self._vtk_obj_cfs = {}
        if not self._vtk_obj_cfs.has_key(vtk_obj):
            self._vtk_obj_cfs[vtk_obj] = ConfigVtkObj(parent, renwin, vtk_obj)
        self._vtk_obj_cfs[vtk_obj].show()

    def close_vtk_object_configure(self):
        """Explicitly close() all ConfigVtkObj's that vtk_objct_configure has
        created.

        Usually, the ConfigVtkObj windows will be children of some frame, and
        when that frame gets destroyed, they will be too.  However, when this
        is not the case, you can make use of this method.
        """
        if hasattr(self, '_vtk_obj_cfs'):
            for key in self._vtk_obj_cfs.keys():
                self._vtk_obj_cfs[key].close()
            self._vtk_obj_cfs.clear()

    def vtk_pipeline_configure(self, parent, renwin, objects):
        """This will instantiate and show only one pipeline config per
        module instance.

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroy()ed.
        renwin: render window (optionally None) which will be render()ed
        when changes are made AND if objects is None, will be used to determine
        the pipeline.
        objects: if you don't want the pipeline to be extracted from the
        renderwindow, you can specify a sequence of objects to be used as the
        multiple roots of a partial pipeline.

        NOTE: renwin and objects can't BOTH be None/empty.
        """
        if not hasattr(self, '_pipeline') or self._pipeline == None:
            self._pipeline = vtkPipelineBrowser(parent, renwin, objects)
        self._pipeline.show()

    def close_pipeline_configure(self):
        """Explicitly close() the pipeline browser of this module.

        This should happen automatically if a valid 'parent' was passed to
        vtk_pipeline_configure(), i.e. when the parent dies, the pipeline
        browser will die too.  However, you can use this method to take
        care of it explicitly.
        """
        if hasattr(self, '_pipeline'):
            self._pipeline.close()
        self._pipeline = None

# ----------------------------------------------------------------------------

from wxPython.wx import wxFileDialog, wxOPEN, wxID_OK

class module_mixin_fo_dialog:
    """Module mixin to make use of file open dialog."""

    def fn_browse(self, parent, message, wildcard, style=wxOPEN):
        """Utility method to make use of wxFileDialog.

        This function will open up exactly one dialog per 'message' and this
        dialog won't be destroyed.  This persistence makes sure that the dialog
        retains its previous settings and also that there is less overhead for
        subsequent creations.  The dialog will be a child of 'parent', so when
        parent is destroyed, this dialog will be too.
        """
        if not hasattr(self, '_fo_dlgs'):
            self._fo_dlgs = {}
        if not self._fo_dlgs.has_key(message):
            self._fo_dlgs[message] = wxFileDialog(parent,
                                                  message, "", "",
                                                  wildcard, style)
        if self._fo_dlgs[message].ShowModal() == wxID_OK:
            return self._fo_dlgs[message].GetPath()
        else:
            return None

    def close_fn_browse(self):
        """Use this method to close all created dialogs explicitly.

        This should be taken care of automatically if you've passed in a valid
        'parent'.  Use this method in cases where this was not possible.
        """
        if hasattr(self, '_fo_dlgs'):
            for key in self._fo_dlgs.keys():
                self._fo_dlgs[key].Destroy()
            self._fo_dlgs.clear()
<commit_msg>Small fix.<commit_after># $Id: module_base.py,v 1.16 2002/06/07 15:52:40 cpbotha Exp $

# ----------------------------------------------------------------------------

"""Module containing class-related utilities and code for dscas3 modules.

In this module you'll find a base class as well as several useful mixins.
Please see the documentation.

author: Charl P. Botha <cpbotha@ieee.org>
"""

class module_base:
    """Base class for all modules.

    Any module wishing to take part in the dscas3 party will have to offer all
    of these methods.
    """

    def __init__(self, module_manager):
        """We need to know where the module manager is so we can query
        it about the module path, e.g.
        """
        self._module_manager = module_manager

    def close(self):
	"""Idempotent method for de-initialising module as far as possible.

        We can't guarantee the calling of __del__, as Python does garbage
        collection and the object might destruct a while after we've removed
        all references to it.

        In addition, with python garbage collection, __del__ can cause
        uncollectable objects, so try to avoid it as far as possible.
        """
	raise NotImplementedError

    def get_input_descriptions(self):
	"""Returns tuple of input descriptions, mostly used by the graph editor
	to make a nice glyph for this module."""
	raise NotImplementedError

    def set_input(self, idx, input_stream):
	"""Attaches input_stream (which is e.g. the output of a previous
        module) to this module's input at position idx.
        """
	raise NotImplementedError

    def get_output_descriptions(self):
	"""Returns a tuple of output descriptions.

        Mostly used by the graph editor to make a nice glyph for this module.
        These are also clues to the user as to which glyphs can be connected.
        """
	raise NotImplementedError

    def get_output(self, idx):
	"""Get the n-th output.

        This will be used for connecting this output to the input of another
        module.
        """
	raise NotImplementedError

    def sync_config(self):
	raise NotImplementedError

    def apply_config(self):
	raise NotImplementedError

    def execute_module(self):
	raise NotImplementedError

    def view(self):
	"""Pop up a dialog with all config possibilities, including optional
        use of the pipeline browser.
        """
	raise NotImplementedError

# ----------------------------------------------------------------------------

from vtkPipeline.ConfigVtkObj import ConfigVtkObj
from vtkPipeline.vtkPipeline import vtkPipelineBrowser

class module_mixin_vtk_pipeline_config:
    """Mixin to use for modules that want to make use of the vtkPipeline
    functionality.

    Modules that use this as mixin can make use of the vtk_object_configure
    and vtk_pipeline_configure methods to use ConfigVtkObj and
    vtkPipelineBrowser, respectively.  These methods will make sure that you
    use only one instance of a browser/config class per object.
    """

    def vtk_object_configure(self, parent, renwin, vtk_obj):
        """This will instantiate and show only one object config frame per
        unique vtk_obj (per module instance).

        If it is called multiple times for the same object, it will merely
        bring the pertinent window to the top (by show()ing).

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroyed.
        renwin: render window (optionally None) which will be
        render()ed when changes are made to the vtk object which is being
        configured.
        vtk_obj: the object you want to config.
        """
        if not hasattr(self, '_vtk_obj_cfs'):
            self._vtk_obj_cfs = {}
        if not self._vtk_obj_cfs.has_key(vtk_obj):
            self._vtk_obj_cfs[vtk_obj] = ConfigVtkObj(parent, renwin, vtk_obj)
        self._vtk_obj_cfs[vtk_obj].show()

    def close_vtk_object_configure(self):
        """Explicitly close() all ConfigVtkObj's that vtk_objct_configure has
        created.

        Usually, the ConfigVtkObj windows will be children of some frame, and
        when that frame gets destroyed, they will be too.  However, when this
        is not the case, you can make use of this method.
        """
        if hasattr(self, '_vtk_obj_cfs'):
            for key in self._vtk_obj_cfs.keys():
                self._vtk_obj_cfs[key].close()
            self._vtk_obj_cfs.clear()

    def vtk_pipeline_configure(self, parent, renwin, objects=None):
        """This will instantiate and show only one pipeline config per
        module instance.

        parent: parent wxWindow derivative.  It's important to pass a parent,
        else the here-created window might never be destroy()ed.
        renwin: render window (optionally None) which will be render()ed
        when changes are made AND if objects is None, will be used to determine
        the pipeline.
        objects: if you don't want the pipeline to be extracted from the
        renderwindow, you can specify a sequence of objects to be used as the
        multiple roots of a partial pipeline.

        NOTE: renwin and objects can't BOTH be None/empty.
        """
        if not hasattr(self, '_pipeline') or self._pipeline == None:
            self._pipeline = vtkPipelineBrowser(parent, renwin, objects)
        self._pipeline.show()

    def close_pipeline_configure(self):
        """Explicitly close() the pipeline browser of this module.

        This should happen automatically if a valid 'parent' was passed to
        vtk_pipeline_configure(), i.e. when the parent dies, the pipeline
        browser will die too.  However, you can use this method to take
        care of it explicitly.
        """
        if hasattr(self, '_pipeline'):
            self._pipeline.close()
        self._pipeline = None

# ----------------------------------------------------------------------------

from wxPython.wx import wxFileDialog, wxOPEN, wxID_OK

class module_mixin_fo_dialog:
    """Module mixin to make use of file open dialog."""

    def fn_browse(self, parent, message, wildcard, style=wxOPEN):
        """Utility method to make use of wxFileDialog.

        This function will open up exactly one dialog per 'message' and this
        dialog won't be destroyed.  This persistence makes sure that the dialog
        retains its previous settings and also that there is less overhead for
        subsequent creations.  The dialog will be a child of 'parent', so when
        parent is destroyed, this dialog will be too.
        """
        if not hasattr(self, '_fo_dlgs'):
            self._fo_dlgs = {}
        if not self._fo_dlgs.has_key(message):
            self._fo_dlgs[message] = wxFileDialog(parent,
                                                  message, "", "",
                                                  wildcard, style)
        if self._fo_dlgs[message].ShowModal() == wxID_OK:
            return self._fo_dlgs[message].GetPath()
        else:
            return None

    def close_fn_browse(self):
        """Use this method to close all created dialogs explicitly.

        This should be taken care of automatically if you've passed in a valid
        'parent'.  Use this method in cases where this was not possible.
        """
        if hasattr(self, '_fo_dlgs'):
            for key in self._fo_dlgs.keys():
                self._fo_dlgs[key].Destroy()
            self._fo_dlgs.clear()
<|endoftext|>


<commit_before>#  sop-apogee timer
#  history
#  added say alert
# 03/11/2013:  EM: changed voice to mac system Glass.wav
# 04/20/2013:  EM: multiple refinement,  added format and colors,
#  changed time left for None if no exposures left in sop sequence.
# 04/22/2013: EM:
#   changed colors to self.fg=["black", "ForestGreen","OrangeRed"]
#   changed name from Timer to apogeeTimer
#    added check button for sound on / off, default on.
# 2012-05-17 EM: changed text " Apogee exposure time left = " to " apogeeTimer: "
#   and use this to start with.

import RO.Wdg
import TUI.Models
import Tkinter
import TUI.PlaySound

class ScriptClass(object):
    def __init__(self, sr, ):

       self.sr=sr
       self.fg=["DarkGrey", "ForestGreen","Brown"]
  #     self.ft=("Times", "16", "bold")
       self.ft=("Times", "16")

       sPath="/Library/Application Support/STUIAdditions"
       ffid=sPath+"/Scripts/Glass.wav"
       self.soundFid = RO.Wdg.SoundPlayer(ffid)

       self.sopModel = TUI.Models.getModel("sop")
       self.apogeeModel = TUI.Models.getModel("apogee")

       self.alertTime=5.0  # min
       self.alert=True
       self.name=" apogeeTimer: "

       sr.master.winfo_toplevel().wm_resizable(True, True)
       F1 = Tkinter.Frame(sr.master)
       gr = RO.Wdg.Gridder(F1)
       F1.grid(row=0, column=0, sticky="ns")
       self.labWdg = RO.Wdg.Label(master=F1, text =self.name,
            font=self.ft, fg=self.fg[0])
       self.labWdg.grid(row=0, column=0, sticky="ew")
       self.checkWdg = RO.Wdg.Checkbutton(master=F1,
            text = "", defValue=True, helpText ="Play sound",)
       self.checkWdg.grid(row=0, column=1, sticky="ew")
       self.expTimer = RO.Wdg.ProgressBar(master = sr.master,
          valueFormat = "%4.1f", label = None, )
       self.expTimer.grid(row=1, column=0, sticky="ew")
       sr.master.rowconfigure(0, weight=1)
       sr.master.rowconfigure(1, weight=1)
       sr.master.columnconfigure(0, weight=1)

       self.record()
       self.sopModel.doApogeeScience_sequenceState.addCallback(self.seqState,callNow=False)
       self.sopModel.doApogeeScienceState.addCallback(self.sopState,callNow=False)
       self.apogeeModel.utrReadState.addCallback(self.utrState,callNow=False)

    def sopState (self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def seqState(self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def utrState(self, keyVar):
      if not keyVar.isGenuine: return
      if keyVar[1] == "Done":
          self.record()

    def setNone(self, state):
        self.labWdg.set("%s  %s " % (self.name,state))
        self.expTimer.setValue(newValue=0.0, newMin=0.0, newMax=0.0001)
        self.labWdg.config(fg=self.fg[0])
        return

    def record(self,):
      self.state=self.sopModel.doApogeeScienceState[0]
      if self.state!='running':
           self.setNone(self.state)
           return
#sop
      self.sq, self.indState = self.sopModel.doApogeeScience_sequenceState[0:2]
      self.seqCount=self.sopModel.doApogeeScience_seqCount[0]
      self.sopExp=self.sopModel.doApogeeScience_expTime[0]/60.
      self.sqTotal=len(self.sq)*self.sopExp
      self.sqOver=(self.indState)*self.sopExp
#apogee
      self.utr2, self.utr3 =self.apogeeModel.utrReadState[2:4]
      self.utrExp=self.apogeeModel.utrReadTime[0]/60.
      self.utrTotal=self.utr3*self.utrExp
      self.utrOver=self.utr2*self.utrExp
# total time estimation
      if self.sqTotal > self.sqOver:
          total=self.sqTotal
          self.timeLeft=(self.sqTotal-self.sqOver-self.utrOver)
      else:
          total=self.utrTotal
          self.timeLeft=(self.utrTotal-self.utrOver)
 #     self.labWdg.set("%s %5.1f min ( %5.1f min)" % (self.name,self.timeLeft, total))
      self.labWdg.set("%s %5.1f min " % (self.name,self.timeLeft))
      if (self.timeLeft > self.alertTime):
             self.alert=True;  fgi=1
      elif (0 < self.timeLeft <= self.alertTime):
            if self.alert and  self.checkWdg.getBool():
                self.soundFid.play(); self.soundFid.play();
            self.alert = False;  fgi=2;
      else:  fgi=0
      self.labWdg.config(fg=self.fg[fgi])
      self.expTimer.setValue(newValue=self.timeLeft, newMin=0, newMax=total)
      return

    def run(self, sr):
        self.record()

    def end(self, sr):
        pass
      #  self.sopModel.doApogeeScience_sequenceState.removeCallback(self.seqState)
      #  self.apogeeModel.utrReadState.removeCallback(self.utrState)
      #  print "-- call removed,  done --"

#    Key("doApogeeScience_expTime", Float(help="exposure time", units="sec"), Float(help="default", units="sec")),
#    Key("doApogeeScience_sequenceState", String(help="full exposure sequence. Basically ditherSeq * seqCount"),
#        Int(help="index of running exposure")),

<commit_msg>apogeeTimer<commit_after>#  sop-apogee timer
#  history
#  added say alert
# 03/11/2013:  EM: changed voice to mac system Glass.wav
# 04/20/2013:  EM: multiple refinement,  added format and colors,
#  changed time left for None if no exposures left in sop sequence.
# 04/22/2013: EM:
#   changed colors to self.fg=["black", "ForestGreen","OrangeRed"]
#   changed name from Timer to apogeeTimer
#    added check button for sound on / off, default on.
#   2012-05-17 EM: change label text to just "apogeeTimer"

import RO.Wdg
import TUI.Models
import Tkinter
import TUI.PlaySound

class ScriptClass(object):
    def __init__(self, sr, ):

       self.sr=sr
       self.fg=["DarkGrey", "ForestGreen","Brown"]
  #     self.ft=("Times", "16", "bold")
       self.ft=("Times", "16")

       sPath="/Library/Application Support/STUIAdditions"
       ffid=sPath+"/Scripts/Glass.wav"
       self.soundFid = RO.Wdg.SoundPlayer(ffid)

       self.sopModel = TUI.Models.getModel("sop")
       self.apogeeModel = TUI.Models.getModel("apogee")

       self.alertTime=5.0  # min
       self.alert=True
       self.name=" apogeeTimer: "

       sr.master.winfo_toplevel().wm_resizable(True, True)
       F1 = Tkinter.Frame(sr.master)
       gr = RO.Wdg.Gridder(F1)
       F1.grid(row=0, column=0, sticky="ns")
       self.labWdg = RO.Wdg.Label(master=F1, text =self.name,
            font=self.ft, fg=self.fg[0])
       self.labWdg.grid(row=0, column=0, sticky="ew")
       self.checkWdg = RO.Wdg.Checkbutton(master=F1,
            text = "", defValue=True, helpText ="Play sound",)
       self.checkWdg.grid(row=0, column=1, sticky="ew")
       self.expTimer = RO.Wdg.ProgressBar(master = sr.master,
          valueFormat = "%4.1f", label = None, )
       self.expTimer.grid(row=1, column=0, sticky="ew")
       sr.master.rowconfigure(0, weight=1)
       sr.master.rowconfigure(1, weight=1)
       sr.master.columnconfigure(0, weight=1)

       self.record()
       self.sopModel.doApogeeScience_sequenceState.addCallback(self.seqState,callNow=False)
       self.sopModel.doApogeeScienceState.addCallback(self.sopState,callNow=False)
       self.apogeeModel.utrReadState.addCallback(self.utrState,callNow=False)

    def sopState (self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def seqState(self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def utrState(self, keyVar):
      if not keyVar.isGenuine: return
      if keyVar[1] == "Done":
          self.record()

    def setNone(self, state):
        self.labWdg.set("%s  %s " % (self.name,state))
        self.expTimer.setValue(newValue=0.0, newMin=0.0, newMax=0.0001)
        self.labWdg.config(fg=self.fg[0])
        return

    def record(self,):
      self.state=self.sopModel.doApogeeScienceState[0]
      if self.state!='running':
           self.setNone(self.state)
           return
#sop
      self.sq, self.indState = self.sopModel.doApogeeScience_sequenceState[0:2]
      self.seqCount=self.sopModel.doApogeeScience_seqCount[0]
      self.sopExp=self.sopModel.doApogeeScience_expTime[0]/60.
      self.sqTotal=len(self.sq)*self.sopExp
      self.sqOver=(self.indState)*self.sopExp
#apogee
      self.utr2, self.utr3 =self.apogeeModel.utrReadState[2:4]
      self.utrExp=self.apogeeModel.utrReadTime[0]/60.
      self.utrTotal=self.utr3*self.utrExp
      self.utrOver=self.utr2*self.utrExp
# total time estimation
      if self.sqTotal > self.sqOver:
          total=self.sqTotal
          self.timeLeft=(self.sqTotal-self.sqOver-self.utrOver)
      else:
          total=self.utrTotal
          self.timeLeft=(self.utrTotal-self.utrOver)
 #     self.labWdg.set("%s %5.1f min ( %5.1f min)" % (self.name,self.timeLeft, total))
      self.labWdg.set("%s %5.1f min " % (self.name,self.timeLeft))
      if (self.timeLeft > self.alertTime):
             self.alert=True;  fgi=1
      elif (0 < self.timeLeft <= self.alertTime):
            if self.alert and  self.checkWdg.getBool():
                self.soundFid.play(); self.soundFid.play();
            self.alert = False;  fgi=2;
      else:  fgi=0
      self.labWdg.config(fg=self.fg[fgi])
      self.expTimer.setValue(newValue=self.timeLeft, newMin=0, newMax=total)
      return

    def run(self, sr):
        self.record()

    def end(self, sr):
        pass
      #  self.sopModel.doApogeeScience_sequenceState.removeCallback(self.seqState)
      #  self.apogeeModel.utrReadState.removeCallback(self.utrState)
      #  print "-- call removed,  done --"

#    Key("doApogeeScience_expTime", Float(help="exposure time", units="sec"), Float(help="default", units="sec")),
#    Key("doApogeeScience_sequenceState", String(help="full exposure sequence. Basically ditherSeq * seqCount"),
#        Int(help="index of running exposure")),

<|endoftext|>


<commit_before>#  sop-apogee timer
#  history
#  added say alert
# 03/11/2013:  EM: changed voice to mac system Glass.wav
# 04/20/2013:  EM: multiple refinement,  added format and colors,
#  changed time left for None if no exposures left in sop sequence.
# 04/22/2013: EM:
#   changed colors to self.fg=["black", "ForestGreen","OrangeRed"]
#   changed name from Timer to apogeeTimer
#    added check button for sound on / off, default on.

import RO.Wdg
import TUI.Models
import Tkinter
import TUI.PlaySound

class ScriptClass(object):
    def __init__(self, sr, ):

       self.sr=sr
       self.fg=["DarkGrey", "ForestGreen","Brown"]
  #     self.ft=("Times", "16", "bold")
       self.ft=("Times", "16")

       sPath="/Library/Application Support/STUIAdditions"
       ffid=sPath+"/Scripts/Glass.wav"
       self.soundFid = RO.Wdg.SoundPlayer(ffid)

       self.sopModel = TUI.Models.getModel("sop")
       self.apogeeModel = TUI.Models.getModel("apogee")

       self.alertTime=5.0  # min
       self.alert=True
       self.name="  Apogee exposure time left  = "

       sr.master.winfo_toplevel().wm_resizable(True, True)
       F1 = Tkinter.Frame(sr.master)
       gr = RO.Wdg.Gridder(F1)
       F1.grid(row=0, column=0, sticky="ns")
       self.labWdg = RO.Wdg.Label(master=F1, text =self.name,
            font=self.ft, fg=self.fg[0])
       self.labWdg.grid(row=0, column=0, sticky="ew")
       self.checkWdg = RO.Wdg.Checkbutton(master=F1,
            text = "", defValue=True, helpText ="Play sound",)
       self.checkWdg.grid(row=0, column=1, sticky="ew")
       self.expTimer = RO.Wdg.ProgressBar(master = sr.master,
          valueFormat = "%4.1f", label = None, )
       self.expTimer.grid(row=1, column=0, sticky="ew")
       sr.master.rowconfigure(0, weight=1)
       sr.master.rowconfigure(1, weight=1)
       sr.master.columnconfigure(0, weight=1)

       self.record()
       self.sopModel.doApogeeScience_sequenceState.addCallback(self.seqState,callNow=False)
       self.sopModel.doApogeeScienceState.addCallback(self.sopState,callNow=False)
       self.apogeeModel.utrReadState.addCallback(self.utrState,callNow=False)

    def sopState (self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def seqState(self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def utrState(self, keyVar):
      if not keyVar.isGenuine: return
      if keyVar[1] == "Done":
          self.record()

    def setNone(self, state):
        self.labWdg.set("Apogee:  %s " % (state))
        self.expTimer.setValue(newValue=0.0, newMin=0.0, newMax=0.0001)
        self.labWdg.config(fg=self.fg[0])
        return

    def record(self,):
      self.state=self.sopModel.doApogeeScienceState[0]
      if self.state!='running':
           self.setNone(self.state)
           return
#sop
      self.sq, self.indState = self.sopModel.doApogeeScience_sequenceState[0:2]
      self.seqCount=self.sopModel.doApogeeScience_seqCount[0]
      self.sopExp=self.sopModel.doApogeeScience_expTime[0]/60.
      self.sqTotal=len(self.sq)*self.sopExp
      self.sqOver=(self.indState)*self.sopExp
#apogee
      self.utr2, self.utr3 =self.apogeeModel.utrReadState[2:4]
      self.utrExp=self.apogeeModel.utrReadTime[0]/60.
      self.utrTotal=self.utr3*self.utrExp
      self.utrOver=self.utr2*self.utrExp
# total time estimation
      if self.sqTotal > self.sqOver:
          total=self.sqTotal
          self.timeLeft=(self.sqTotal-self.sqOver-self.utrOver)
      else:
          total=self.utrTotal
          self.timeLeft=(self.utrTotal-self.utrOver)
      self.labWdg.set("%s %5.1f min ( %5.1f min)" % (self.name,self.timeLeft, total))
      if (self.timeLeft > self.alertTime):
             self.alert=True;  fgi=1
      elif (0 < self.timeLeft <= self.alertTime):
            if self.alert and  self.checkWdg.getBool():
                self.soundFid.play(); self.soundFid.play();
            self.alert = False;  fgi=2;
      else:  fgi=0
      self.labWdg.config(fg=self.fg[fgi])
      self.expTimer.setValue(newValue=self.timeLeft, newMin=0, newMax=total)
      return

    def run(self, sr):
        self.record()

    def end(self, sr):
        pass
      #  self.sopModel.doApogeeScience_sequenceState.removeCallback(self.seqState)
      #  self.apogeeModel.utrReadState.removeCallback(self.utrState)
      #  print "-- call removed,  done --"

#    Key("doApogeeScience_expTime", Float(help="exposure time", units="sec"), Float(help="default", units="sec")),
#    Key("doApogeeScience_sequenceState", String(help="full exposure sequence. Basically ditherSeq * seqCount"),
#        Int(help="index of running exposure")),

<commit_msg>apogeeTimer<commit_after>#  sop-apogee timer
#  history
#  added say alert
# 03/11/2013:  EM: changed voice to mac system Glass.wav
# 04/20/2013:  EM: multiple refinement,  added format and colors,
#  changed time left for None if no exposures left in sop sequence.
# 04/22/2013: EM:
#   changed colors to self.fg=["black", "ForestGreen","OrangeRed"]
#   changed name from Timer to apogeeTimer
#    added check button for sound on / off, default on.
#   2012-05-17 EM: cut label text to just "bossTimer"

import RO.Wdg
import TUI.Models
import Tkinter
import TUI.PlaySound

class ScriptClass(object):
    def __init__(self, sr, ):

       self.sr=sr
       self.fg=["DarkGrey", "ForestGreen","Brown"]
  #     self.ft=("Times", "16", "bold")
       self.ft=("Times", "16")

       sPath="/Library/Application Support/STUIAdditions"
       ffid=sPath+"/Scripts/Glass.wav"
       self.soundFid = RO.Wdg.SoundPlayer(ffid)

       self.sopModel = TUI.Models.getModel("sop")
       self.apogeeModel = TUI.Models.getModel("apogee")

       self.alertTime=5.0  # min
       self.alert=True
       self.name=" apogeeTimer: "

       sr.master.winfo_toplevel().wm_resizable(True, True)
       F1 = Tkinter.Frame(sr.master)
       gr = RO.Wdg.Gridder(F1)
       F1.grid(row=0, column=0, sticky="ns")
       self.labWdg = RO.Wdg.Label(master=F1, text =self.name,
            font=self.ft, fg=self.fg[0])
       self.labWdg.grid(row=0, column=0, sticky="ew")
       self.checkWdg = RO.Wdg.Checkbutton(master=F1,
            text = "", defValue=True, helpText ="Play sound",)
       self.checkWdg.grid(row=0, column=1, sticky="ew")
       self.expTimer = RO.Wdg.ProgressBar(master = sr.master,
          valueFormat = "%4.1f", label = None, )
       self.expTimer.grid(row=1, column=0, sticky="ew")
       sr.master.rowconfigure(0, weight=1)
       sr.master.rowconfigure(1, weight=1)
       sr.master.columnconfigure(0, weight=1)

       self.record()
       self.sopModel.doApogeeScience_sequenceState.addCallback(self.seqState,callNow=False)
       self.sopModel.doApogeeScienceState.addCallback(self.sopState,callNow=False)
       self.apogeeModel.utrReadState.addCallback(self.utrState,callNow=False)

    def sopState (self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def seqState(self, keyVar):
      if not keyVar.isGenuine: return
      self.record()

    def utrState(self, keyVar):
      if not keyVar.isGenuine: return
      if keyVar[1] == "Done":
          self.record()

    def setNone(self, state):
        self.labWdg.set("%s  %s " % (self.name,state))
        self.expTimer.setValue(newValue=0.0, newMin=0.0, newMax=0.0001)
        self.labWdg.config(fg=self.fg[0])
        return

    def record(self,):
      self.state=self.sopModel.doApogeeScienceState[0]
      if self.state!='running':
           self.setNone(self.state)
           return
#sop
      self.sq, self.indState = self.sopModel.doApogeeScience_sequenceState[0:2]
      self.seqCount=self.sopModel.doApogeeScience_seqCount[0]
      self.sopExp=self.sopModel.doApogeeScience_expTime[0]/60.
      self.sqTotal=len(self.sq)*self.sopExp
      self.sqOver=(self.indState)*self.sopExp
#apogee
      self.utr2, self.utr3 =self.apogeeModel.utrReadState[2:4]
      self.utrExp=self.apogeeModel.utrReadTime[0]/60.
      self.utrTotal=self.utr3*self.utrExp
      self.utrOver=self.utr2*self.utrExp
# total time estimation
      if self.sqTotal > self.sqOver:
          total=self.sqTotal
          self.timeLeft=(self.sqTotal-self.sqOver-self.utrOver)
      else:
          total=self.utrTotal
          self.timeLeft=(self.utrTotal-self.utrOver)
 #     self.labWdg.set("%s %5.1f min ( %5.1f min)" % (self.name,self.timeLeft, total))
      self.labWdg.set("%s %5.1f min " % (self.name,self.timeLeft))
      if (self.timeLeft > self.alertTime):
             self.alert=True;  fgi=1
      elif (0 < self.timeLeft <= self.alertTime):
            if self.alert and  self.checkWdg.getBool():
                self.soundFid.play(); self.soundFid.play();
            self.alert = False;  fgi=2;
      else:  fgi=0
      self.labWdg.config(fg=self.fg[fgi])
      self.expTimer.setValue(newValue=self.timeLeft, newMin=0, newMax=total)
      return

    def run(self, sr):
        self.record()

    def end(self, sr):
        pass
      #  self.sopModel.doApogeeScience_sequenceState.removeCallback(self.seqState)
      #  self.apogeeModel.utrReadState.removeCallback(self.utrState)
      #  print "-- call removed,  done --"

#    Key("doApogeeScience_expTime", Float(help="exposure time", units="sec"), Float(help="default", units="sec")),
#    Key("doApogeeScience_sequenceState", String(help="full exposure sequence. Basically ditherSeq * seqCount"),
#        Int(help="index of running exposure")),

<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""
bulb.py
~~~~~~~

This module is for communicating with the MagicHome LED bulb over the network.

Wire protocol:

-------------------------------------
|header(1)|data(5-70)|0f|checksum(1)|
-------------------------------------

header:
    31 color & white
    41 camera
    51 custom
    61 function

color, white, camera (8 bytes):
    00-ff red
    00-ff green
    00-ff blue
    00-ff white
    mode:
        0f white
        f0 color

functions (5 bytes):
    25-38 modes
    1f-01 speed (decreasing)
    0f who knows

custom (70 bytes):
    64 bytes of r, g, b, 0 (empty color is 0x01020300)
    1f-01 speed (decreasing)
    3a,3b,3c gradual, jumping, strobe
    ff tail

tail:
    0f
    checksum (sum of data fields)
"""
import socket
import sys
from datetime import datetime
from typing import Dict

import pytz
from astral import Astral

from home import config
from home.core.utils import num

SUPPORTED_MODES = ['31', '41', '61']
SUPPORTED_FUNCTIONS = list(range(25, 39))
TAIL = '0f'

seven_color_cross_fade = 0x25
red_gradual_change = 0x26
green_gradual_change = 0x27
blue_gradual_change = 0x28
yellow_gradual_change = 0x29
cyan_gradual_change = 0x2a
purple_gradual_change = 0x2b
white_gradual_change = 0x2c
red_green_cross_fade = 0x2d
red_blue_cross_fade = 0x2e
green_blue_cross_fade = 0x2f
seven_color_strobe_flash = 0x30
red_strobe_flash = 0x31
green_strobe_flash = 0x32
blue_stobe_flash = 0x33
yellow_strobe_flash = 0x34
cyan_strobe_flash = 0x35
purple_strobe_flash = 0x36
white_strobe_flash = 0x37
seven_color_jumping = 0x38

CONTROL_PORT = 5577
# The HFLPB100's control/debug module
HF_COMMAND_PORT = 48899
HF_COMMAND = 'HF-A11ASSISTHREAD'.encode()
HF_COMMAND_OK = '+ok'.encode()

prepare_hex = lambda x: format(x, 'x').zfill(2)

def calc_sunlight() -> int:
    """
    Calculate an appropriate brightness for the bulb depending on
    current sunlight.
    :return: White brightness
    """
    a = Astral()
    a.solar_depression = 'civil'
    city = a[config.LOCATION]
    sun = city.sun(date=datetime.now(), local=True)
    dt = datetime.utcnow().replace(tzinfo=pytz.UTC)
    white = 255
    if dt < sun['sunrise']:
        white = 255 - (sun['sunrise'] - dt).total_seconds() / 3600 * 200 / 6
    elif dt > sun['sunset']:
        white = 255 - (dt - sun['sunset']).total_seconds() / 3600 * 200 / 6
    return white

class Bulb:
    """
    A class representing a single MagicHome LED Bulb.
    """

    def __init__(self, host):
        self.host = host

    def auth(self) -> None:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(HF_COMMAND, (self.host, HF_COMMAND_PORT))
        s.sendto(HF_COMMAND_OK, (self.host, HF_COMMAND_PORT))

    def change_color(self, red: int = 0, green: int = 0, blue: int = 0, white: int = 0, brightness: int = 255,
                     mode: str = '31', function: str = None, speed: str = '1f') -> None:
        """
        Provided RGB values and a brightness, change the color of the
        bulb with a TCP socket.
        """
        if mode not in SUPPORTED_MODES:
            raise NotImplementedError

        if function:
            if num(function) not in SUPPORTED_FUNCTIONS:
                raise NotImplementedError
            data = bytearray.fromhex(mode + function + speed + TAIL)
        else:
            red, green, blue, white, brightness = num(red, green, blue, white, brightness)
            red = num(red * brightness / 255)
            green = num(green * brightness / 255)
            blue = num(blue * brightness / 255)
            white = num(white * brightness / 255)
            color_hex = (prepare_hex(red) + prepare_hex(green) + prepare_hex(blue)
                         + prepare_hex(white))
            if white:
                color_mode = '0f'
            else:
                color_mode = 'f0'
            # Build packet
            data = bytearray.fromhex(mode + color_hex
                                     + color_mode + TAIL)
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            # TCP port 5577
            s.connect((self.host, CONTROL_PORT))
            # Compute checksum
            data.append(sum(data) % 256)
            s.send(data)
        except Exception:
            pass

    def sunlight(self) -> None:
        self.change_color(white=calc_sunlight())

    def fade(self, start: Dict = None, stop: Dict = None, bright: int = None, speed: int = 1) -> None:
        speed = abs(speed)
        if start:
            bright = bright or 255
            while bright > 0:
                self.change_color(**start, brightness=bright, mode='41')
                bright -= speed
        if stop:
            bright = bright or 0
            while bright < 255:
                self.change_color(**stop, brightness=bright, mode='41')
                bright += speed

    def fade_sunlight(self, speed: int = 1) -> None:
        self.fade(stop={'white': calc_sunlight()}, speed=speed)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        sys.exit('Nope')
    colors = list(map(lambda x: int(x), sys.argv[2:]))
    print(colors)
    b = Bulb(sys.argv[1])
    b.change_color(*colors)
<commit_msg>Try long socket<commit_after>#!/usr/bin/env python3
"""
bulb.py
~~~~~~~

This module is for communicating with the MagicHome LED bulb over the network.

Wire protocol:

-------------------------------------
|header(1)|data(5-70)|0f|checksum(1)|
-------------------------------------

header:
    31 color & white
    41 camera
    51 custom
    61 function

color, white, camera (8 bytes):
    00-ff red
    00-ff green
    00-ff blue
    00-ff white
    mode:
        0f white
        f0 color

functions (5 bytes):
    25-38 modes
    1f-01 speed (decreasing)
    0f who knows

custom (70 bytes):
    64 bytes of r, g, b, 0 (empty color is 0x01020300)
    1f-01 speed (decreasing)
    3a,3b,3c gradual, jumping, strobe
    ff tail

tail:
    0f
    checksum (sum of data fields)
"""
import socket
import sys
from datetime import datetime
from typing import Dict

import pytz
from astral import Astral

from home import config
from home.core.utils import num

SUPPORTED_MODES = ['31', '41', '61']
SUPPORTED_FUNCTIONS = list(range(25, 39))
TAIL = '0f'

seven_color_cross_fade = 0x25
red_gradual_change = 0x26
green_gradual_change = 0x27
blue_gradual_change = 0x28
yellow_gradual_change = 0x29
cyan_gradual_change = 0x2a
purple_gradual_change = 0x2b
white_gradual_change = 0x2c
red_green_cross_fade = 0x2d
red_blue_cross_fade = 0x2e
green_blue_cross_fade = 0x2f
seven_color_strobe_flash = 0x30
red_strobe_flash = 0x31
green_strobe_flash = 0x32
blue_stobe_flash = 0x33
yellow_strobe_flash = 0x34
cyan_strobe_flash = 0x35
purple_strobe_flash = 0x36
white_strobe_flash = 0x37
seven_color_jumping = 0x38

CONTROL_PORT = 5577
# The HFLPB100's control/debug module
HF_COMMAND_PORT = 48899
HF_COMMAND = 'HF-A11ASSISTHREAD'.encode()
HF_COMMAND_OK = '+ok'.encode()

prepare_hex = lambda x: format(x, 'x').zfill(2)

def calc_sunlight() -> int:
    """
    Calculate an appropriate brightness for the bulb depending on
    current sunlight.
    :return: White brightness
    """
    a = Astral()
    a.solar_depression = 'civil'
    city = a[config.LOCATION]
    sun = city.sun(date=datetime.now(), local=True)
    dt = datetime.utcnow().replace(tzinfo=pytz.UTC)
    white = 255
    if dt < sun['sunrise']:
        white = 255 - (sun['sunrise'] - dt).total_seconds() / 3600 * 200 / 6
    elif dt > sun['sunset']:
        white = 255 - (dt - sun['sunset']).total_seconds() / 3600 * 200 / 6
    return white

class Bulb:
    """
    A class representing a single MagicHome LED Bulb.
    """

    def __init__(self, host):
        self.host = host
        self.socket = None

    def auth(self) -> None:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.sendto(HF_COMMAND, (self.host, HF_COMMAND_PORT))
        s.sendto(HF_COMMAND_OK, (self.host, HF_COMMAND_PORT))
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((self.host, CONTROL_PORT))

    def change_color(self, red: int = 0, green: int = 0, blue: int = 0, white: int = 0, brightness: int = 255,
                     mode: str = '31', function: str = None, speed: str = '1f') -> None:
        """
        Provided RGB values and a brightness, change the color of the
        bulb with a TCP socket.
        """
        if mode not in SUPPORTED_MODES:
            raise NotImplementedError

        if function:
            if num(function) not in SUPPORTED_FUNCTIONS:
                raise NotImplementedError
            data = bytearray.fromhex(mode + function + speed + TAIL)
        else:
            red, green, blue, white, brightness = num(red, green, blue, white, brightness)
            red = num(red * brightness / 255)
            green = num(green * brightness / 255)
            blue = num(blue * brightness / 255)
            white = num(white * brightness / 255)
            color_hex = (prepare_hex(red) + prepare_hex(green) + prepare_hex(blue)
                         + prepare_hex(white))
            if white:
                color_mode = '0f'
            else:
                color_mode = 'f0'
            # Build packet
            data = bytearray.fromhex(mode + color_hex
                                     + color_mode + TAIL)
        try:
            # Compute checksum
            data.append(sum(data) % 256)
            self.socket.send(data)
        except Exception as e:
            print(e)
            self.auth()
            self.socket.send(data)

    def sunlight(self) -> None:
        self.change_color(white=calc_sunlight())

    def fade(self, start: Dict = None, stop: Dict = None, bright: int = None, speed: int = 1) -> None:
        speed = abs(speed)
        if start:
            bright = bright or 255
            while bright > 0:
                self.change_color(**start, brightness=bright, mode='41')
                bright -= speed
        if stop:
            bright = bright or 0
            while bright < 255:
                self.change_color(**stop, brightness=bright, mode='41')
                bright += speed

    def fade_sunlight(self, speed: int = 1) -> None:
        self.fade(stop={'white': calc_sunlight()}, speed=speed)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        sys.exit('Nope')
    colors = list(map(lambda x: int(x), sys.argv[2:]))
    print(colors)
    b = Bulb(sys.argv[1])
    b.change_color(*colors)
<|endoftext|>


<commit_before>'''
Created on 06.01.2014

@author: steffen
'''

import logging
import vobject
import os
import json
import gnupg

def add_vcard_to_contact(config):
    for dirpath, _, filenames in os.walk(config['media_dir']):
        for filename in filenames:
            with open(os.path.join(dirpath, filename)) as file_handle:
                if file_handle.readline().strip() == 'BEGIN:VCARD':
                    file_handle.seek(0)
                    v = vobject.readOne(file_handle)

                    name = v.fn.value
                    email = v.email.value
                    uris = []
                    if 'x-uris' in v.contents:
                        for uri in v.contents['x-uris']:
                            short_title = uri.value.split('/')[2]
                            uris.append((short_title, uri.value))

                    gpg_key = None
                    gpg_path = os.path.join(dirpath, '.'.join((filename.split('.')[:-1])) + '.asc')
                    if os.path.exists(gpg_path):

                        gpg = gnupg.GPG()
                        key_data = open(gpg_path).read()
                        keyfile = gpg.import_keys(key_data)
                        fingerprint = keyfile.results[0]['fingerprint']

                        if gpg_path.startswith(os.sep):
                            gpg_path = gpg_path[len(os.sep):]
                        if gpg_path.startswith(config['media_dir']):
                            gpg_path = gpg_path[len(config['media_dir']):]
                        gpg_key = fingerprint, gpg_path

                    meta_data = []
                    meta_data.append(('title', name))
                    meta_data.append(('type', 'contact'))
                    meta_data.append(('category', 'contact'))
                    meta_data.append(('name', name))
                    meta_data.append(('email', email))

                    if gpg_key:
                        meta_data.append(('gpg', gpg_key))

                    if uris:
                        meta_data.append(('links', uris))

                    new_filename = filename.split('.')[:-1]
                    new_filename.append('mkd')
                    new_filename = '.'.join(new_filename)

                    new_path = os.path.sep.join([config['content_dir'], 'contact', new_filename])

                    with open(new_path, 'wb') as new_file_handle:
                        for key, value in meta_data:
                            if not isinstance(value, basestring):
                                value = json.dumps(value)
                            new_file_handle.write('%s: %s\n' % (key, value))
                        new_file_handle.writelines('---\n')

if __name__ == '__main__':
    logging.basicConfig(format = '%(asctime)s %(levelname)s %(name)s:%(message)s', level = logging.DEBUG)
    add_vcard_to_contact({})<commit_msg>create markdown files as .md instead of .mkd<commit_after>'''
Created on 06.01.2014

@author: steffen
'''

import logging
import vobject
import os
import json
import gnupg

def add_vcard_to_contact(config):
    for dirpath, _, filenames in os.walk(config['media_dir']):
        for filename in filenames:
            with open(os.path.join(dirpath, filename)) as file_handle:
                if file_handle.readline().strip() == 'BEGIN:VCARD':
                    file_handle.seek(0)
                    v = vobject.readOne(file_handle)

                    name = v.fn.value
                    email = v.email.value
                    uris = []
                    if 'x-uris' in v.contents:
                        for uri in v.contents['x-uris']:
                            short_title = uri.value.split('/')[2]
                            uris.append((short_title, uri.value))

                    gpg_key = None
                    gpg_path = os.path.join(dirpath, '.'.join((filename.split('.')[:-1])) + '.asc')
                    if os.path.exists(gpg_path):

                        gpg = gnupg.GPG()
                        key_data = open(gpg_path).read()
                        keyfile = gpg.import_keys(key_data)
                        fingerprint = keyfile.results[0]['fingerprint']

                        if gpg_path.startswith(os.sep):
                            gpg_path = gpg_path[len(os.sep):]
                        if gpg_path.startswith(config['media_dir']):
                            gpg_path = gpg_path[len(config['media_dir']):]
                        gpg_key = fingerprint, gpg_path

                    meta_data = []
                    meta_data.append(('title', name))
                    meta_data.append(('type', 'contact'))
                    meta_data.append(('category', 'contact'))
                    meta_data.append(('name', name))
                    meta_data.append(('email', email))

                    if gpg_key:
                        meta_data.append(('gpg', gpg_key))

                    if uris:
                        meta_data.append(('links', uris))

                    new_filename = filename.split('.')[:-1]
                    new_filename.append('md')
                    new_filename = '.'.join(new_filename)

                    new_path = os.path.sep.join([config['content_dir'], 'contact', new_filename])

                    with open(new_path, 'wb') as new_file_handle:
                        for key, value in meta_data:
                            if not isinstance(value, basestring):
                                value = json.dumps(value)
                            new_file_handle.write('%s: %s\n' % (key, value))
                        new_file_handle.writelines('---\n')

if __name__ == '__main__':
    logging.basicConfig(format = '%(asctime)s %(levelname)s %(name)s:%(message)s', level = logging.DEBUG)
    add_vcard_to_contact({})<|endoftext|>


<commit_before># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

"""Compute properties of hard particle configurations."""

from __future__ import print_function

from hoomd import _hoomd
from hoomd.operation import Compute
from hoomd.hpmc import _hpmc
from hoomd.hpmc import integrate
from hoomd.data.parameterdicts import ParameterDict
from hoomd.logging import log
import hoomd
import numpy

class FreeVolume(Compute):
    r"""Compute the free volume available to a test particle.

    Args:
        test_particle_type (str): Test particle type.
        num_samples (int): Number of samples to evaluate.

    `FreeVolume` computes the free volume in the simulation state available to a
    given test particle using Monte Carlo integration. It must be used in
    combination with an HPMC integrator, which defines the particle shape
    parameters.

    `FreeVolume` generates `num_samples` uniform random test particle placements
    (position and orientation) inside the box and counts the number of times
    these test placements overlap with the particles in the simulation state.
    It then computes the free volume with:

    .. math::
        V_\mathrm{free} = \left( \frac{n_\mathrm{samples} - n_\mathrm{overlaps}}
                               {n_\mathrm{samples}} \right) V_\mathrm{box}

    where :math:`V_\mathrm{free}` is the estimated free volume `free_volume`,
    :math:`n_\mathrm{samples}` is the number of samples `num_samples`,
    :math:`n_\mathrm{overlaps}` is the number of overlapping test placements,
    and :math:`V_\mathrm{box}` is the volume of the simulation box.

    Note:

        The test particle type must exist in the simulation state and its shape
        parameters must be set in the simulation's HPMC integrator. Particles
        with this type may or may not be present in the simulation state.

    Note:

        `FreeVolume` respects the ``interaction_matrix`` set in the HPMC
        integrator.

    Examples::

        fv = hoomd.hpmc.compute.FreeVolume(test_particle_type='B',
                                           num_samples=1000)

    Attributes:
        test_particle_type (str): Test particle type.

        num_samples (int): Number of samples to evaluate.

    """
    def __init__(self, test_particle_type, num_samples):
        # store metadata
        param_dict = ParameterDict(
            test_particle_type=str,
            num_samples=int
        )
        param_dict.update(
            dict(test_particle_type=test_particle_type,
                 num_samples=num_samples))
        self._param_dict.update(param_dict)

    def _attach(self):
        integrator = self._simulation.operations.integrator
        if not isinstance(integrator, integrate.HPMCIntegrator):
            raise RuntimeError("The integrator must be an HPMC integrator.")

        # Extract 'Shape' from '<hoomd.hpmc.integrate.Shape object>'
        integrator_name = integrator.__class__.__name__
        try:
            if isinstance(self._simulation.device, hoomd.device.CPU):
                cpp_cls = getattr(_hpmc, 'ComputeFreeVolume' + integrator_name)
            else:
                cpp_cls = getattr(_hpmc,
                                  'ComputeFreeVolume' + integrator_name + 'GPU')
        except AttributeError:
            raise RuntimeError("Unsupported integrator.")

        cl = _hoomd.CellList(self._simulation.state._cpp_sys_def)
        self._cpp_obj = cpp_cls(self._simulation.state._cpp_sys_def,
                                integrator._cpp_obj,
                                cl)

        super()._attach()

    @log
    def free_volume(self):
        """Free volume available to the test particle."""
        if self._attached:
            self._cpp_obj.compute(self._simulation.timestep)
            return self._cpp_obj.free_volume
        else:
            return None

class SDF(Compute):
    r"""Compute the scale distribution function.

    Args:
        xmax (float): Maximum *x* value at the right hand side of the rightmost
          bin (distance units).
        dx (float): Bin width (distance units).

    `SDF` computes a distribution function of scale parameters
    :math:`x`. For each particle, it finds the smallest scale factor :math:`1+x`
    that would cause the particle to touch one of its neighbors and records that
    in the histogram :math:`s(x)`. The histogram is discrete and :math:`s(x_i) =
    s[i]` where :math:`x_i = i \cdot dx + dx/2`.

    In an NVT simulation, the extrapolation of :math:`s(x)` to :math:`x = 0`,
    :math:`s(0+)` is related to the pressure.

    .. math::
        \frac{P}{kT} = \rho \left(1 + \frac{s(0+)}{2d} \right)

    where :math:`d` is the dimensionality of the system and :math:`\rho` is the
    number density.

    Suggested parameters for most systems (assuming particle diameters are ~1):

      * *xmax* = 0.02
      * *dx* = 1e-4

    In systems near densest packings, ``dx=1e-5`` may be needed along with
    either a smaller xmax or a smaller region to fit. A good rule of is to fit
    a region where ``numpy.sum(s[0:n]*dx)`` ~ 0.5.

    `betaP` performs the curve fit and computes :math:`\frac{P}{kT}` using a
    polynomial curve fit of degree 5.

    Warning:
        `SDF` does not compute correct pressures for simulations with
        concave particles or enthalpic interactions.

    Note:

        `SDF` SDF runs on the CPU even in GPU simulations.

    Examples::

        sdf = hoomd.hpmc.compute.SDF(xmax=0.02, dx=1e-4)

    Attributes:
        xmax (float): Maximum *x* value at the right hand side of the rightmost
          bin.

        dx (float): Bin width.

    """
    def __init__(self, xmax, dx):
        # store metadata
        param_dict = ParameterDict(xmax=float(xmax), dx=float(dx))
        self._param_dict.update(param_dict)

    def _attach(self):
        integrator = self._simulation.operations.integrator
        if not isinstance(integrator, integrate.HPMCIntegrator):
            raise RuntimeError("The integrator must be an HPMC integrator.")

        # Extract 'Shape' from '<hoomd.hpmc.integrate.Shape object>'
        integrator_name = integrator.__class__.__name__

        cpp_cls = getattr(_hpmc, 'ComputeSDF' + integrator_name)

        self._cpp_obj = cpp_cls(self._simulation.state._cpp_sys_def,
                                integrator._cpp_obj,
                                self.xmax,
                                self.dx)

        super()._attach()

    @log
    def sdf(self):
        """Scale distribution function."""
        if self._attached:
            self._cpp_obj.compute(self._simulation.timestep)
            return self._cpp_obj.sdf
        else:
            return None

    @log
    def betaP(self):
        r"""Pressure in NVT simulations.

        Use a polynomial curve fit to estimate :math:`\frac{s(0+)}{2d}` and
        compute the pressure via:
        .. math::
            \frac{P}{kT} = \rho \left(1 + \frac{s(0+)}{2d} \right)
        """
        if self._attached:
            # get the values to fit
            n_fit = int(numpy.ceil(self.xmax / self.dx))
            sdf_fit = self.sdf[0:n_fit]
            # construct the x coordinates
            x_fit = numpy.arange(0, self.xmax, self.dx)
            x_fit += self.dx / 2
            # perform the fit and extrapolation
            p = numpy.polyfit(x_fit, sdf_fit, 5)

            box = self._simulation.state.box
            N = self._simulation.state.N_particles
            rho = N / box.volume
            return rho * (1 + numpy.polyval(p, 0.0) / (2 * box.dimensions))
        else:
            return None
<commit_msg>Add note about SDF running on thee CPU even in GPU simulations<commit_after># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

"""Compute properties of hard particle configurations."""

from __future__ import print_function

from hoomd import _hoomd
from hoomd.operation import Compute
from hoomd.hpmc import _hpmc
from hoomd.hpmc import integrate
from hoomd.data.parameterdicts import ParameterDict
from hoomd.logging import log
import hoomd
import numpy

class FreeVolume(Compute):
    r"""Compute the free volume available to a test particle.

    Args:
        test_particle_type (str): Test particle type.
        num_samples (int): Number of samples to evaluate.

    `FreeVolume` computes the free volume in the simulation state available to a
    given test particle using Monte Carlo integration. It must be used in
    combination with an HPMC integrator, which defines the particle shape
    parameters.

    `FreeVolume` generates `num_samples` uniform random test particle placements
    (position and orientation) inside the box and counts the number of times
    these test placements overlap with the particles in the simulation state.
    It then computes the free volume with:

    .. math::
        V_\mathrm{free} = \left( \frac{n_\mathrm{samples} - n_\mathrm{overlaps}}
                               {n_\mathrm{samples}} \right) V_\mathrm{box}

    where :math:`V_\mathrm{free}` is the estimated free volume `free_volume`,
    :math:`n_\mathrm{samples}` is the number of samples `num_samples`,
    :math:`n_\mathrm{overlaps}` is the number of overlapping test placements,
    and :math:`V_\mathrm{box}` is the volume of the simulation box.

    Note:

        The test particle type must exist in the simulation state and its shape
        parameters must be set in the simulation's HPMC integrator. Particles
        with this type may or may not be present in the simulation state.

    Note:

        `FreeVolume` respects the ``interaction_matrix`` set in the HPMC
        integrator.

    Examples::

        fv = hoomd.hpmc.compute.FreeVolume(test_particle_type='B',
                                           num_samples=1000)

    Attributes:
        test_particle_type (str): Test particle type.

        num_samples (int): Number of samples to evaluate.

    """
    def __init__(self, test_particle_type, num_samples):
        # store metadata
        param_dict = ParameterDict(
            test_particle_type=str,
            num_samples=int
        )
        param_dict.update(
            dict(test_particle_type=test_particle_type,
                 num_samples=num_samples))
        self._param_dict.update(param_dict)

    def _attach(self):
        integrator = self._simulation.operations.integrator
        if not isinstance(integrator, integrate.HPMCIntegrator):
            raise RuntimeError("The integrator must be an HPMC integrator.")

        # Extract 'Shape' from '<hoomd.hpmc.integrate.Shape object>'
        integrator_name = integrator.__class__.__name__
        try:
            if isinstance(self._simulation.device, hoomd.device.CPU):
                cpp_cls = getattr(_hpmc, 'ComputeFreeVolume' + integrator_name)
            else:
                cpp_cls = getattr(_hpmc,
                                  'ComputeFreeVolume' + integrator_name + 'GPU')
        except AttributeError:
            raise RuntimeError("Unsupported integrator.")

        cl = _hoomd.CellList(self._simulation.state._cpp_sys_def)
        self._cpp_obj = cpp_cls(self._simulation.state._cpp_sys_def,
                                integrator._cpp_obj,
                                cl)

        super()._attach()

    @log
    def free_volume(self):
        """Free volume available to the test particle."""
        if self._attached:
            self._cpp_obj.compute(self._simulation.timestep)
            return self._cpp_obj.free_volume
        else:
            return None

class SDF(Compute):
    r"""Compute the scale distribution function.

    Args:
        xmax (float): Maximum *x* value at the right hand side of the rightmost
          bin (distance units).
        dx (float): Bin width (distance units).

    `SDF` computes a distribution function of scale parameters
    :math:`x`. For each particle, it finds the smallest scale factor :math:`1+x`
    that would cause the particle to touch one of its neighbors and records that
    in the histogram :math:`s(x)`. The histogram is discrete and :math:`s(x_i) =
    s[i]` where :math:`x_i = i \cdot dx + dx/2`.

    In an NVT simulation, the extrapolation of :math:`s(x)` to :math:`x = 0`,
    :math:`s(0+)` is related to the pressure.

    .. math::
        \frac{P}{kT} = \rho \left(1 + \frac{s(0+)}{2d} \right)

    where :math:`d` is the dimensionality of the system and :math:`\rho` is the
    number density.

    Suggested parameters for most systems (assuming particle diameters are ~1):

      * *xmax* = 0.02
      * *dx* = 1e-4

    In systems near densest packings, ``dx=1e-5`` may be needed along with
    either a smaller xmax or a smaller region to fit. A good rule of is to fit
    a region where ``numpy.sum(s[0:n]*dx)`` ~ 0.5.

    `betaP` performs the curve fit and computes :math:`\frac{P}{kT}` using a
    polynomial curve fit of degree 5.

    Warning:
        `SDF` does not compute correct pressures for simulations with
        concave particles or enthalpic interactions.

    Note:

        `SDF` runs on the CPU even in GPU simulations.

    Examples::

        sdf = hoomd.hpmc.compute.SDF(xmax=0.02, dx=1e-4)

    Attributes:
        xmax (float): Maximum *x* value at the right hand side of the rightmost
          bin.

        dx (float): Bin width.

    """
    def __init__(self, xmax, dx):
        # store metadata
        param_dict = ParameterDict(xmax=float(xmax), dx=float(dx))
        self._param_dict.update(param_dict)

    def _attach(self):
        integrator = self._simulation.operations.integrator
        if not isinstance(integrator, integrate.HPMCIntegrator):
            raise RuntimeError("The integrator must be an HPMC integrator.")

        # Extract 'Shape' from '<hoomd.hpmc.integrate.Shape object>'
        integrator_name = integrator.__class__.__name__

        cpp_cls = getattr(_hpmc, 'ComputeSDF' + integrator_name)

        self._cpp_obj = cpp_cls(self._simulation.state._cpp_sys_def,
                                integrator._cpp_obj,
                                self.xmax,
                                self.dx)

        super()._attach()

    @log
    def sdf(self):
        """Scale distribution function."""
        if self._attached:
            self._cpp_obj.compute(self._simulation.timestep)
            return self._cpp_obj.sdf
        else:
            return None

    @log
    def betaP(self):
        r"""Pressure in NVT simulations.

        Use a polynomial curve fit to estimate :math:`\frac{s(0+)}{2d}` and
        compute the pressure via:
        .. math::
            \frac{P}{kT} = \rho \left(1 + \frac{s(0+)}{2d} \right)
        """
        if self._attached:
            # get the values to fit
            n_fit = int(numpy.ceil(self.xmax / self.dx))
            sdf_fit = self.sdf[0:n_fit]
            # construct the x coordinates
            x_fit = numpy.arange(0, self.xmax, self.dx)
            x_fit += self.dx / 2
            # perform the fit and extrapolation
            p = numpy.polyfit(x_fit, sdf_fit, 5)

            box = self._simulation.state.box
            N = self._simulation.state.N_particles
            rho = N / box.volume
            return rho * (1 + numpy.polyval(p, 0.0) / (2 * box.dimensions))
        else:
            return None
<|endoftext|>


<commit_before>"""
url.py - Jenni Bitly Module
Author: Michael Yanovich, http://yanovich.net/
About: http://inamidst.com/phenny/

This module will record all URLs to bitly via an api key and account.
It also automatically displays the "title" of any URL pasted into the channel.
"""

import re, urllib2
from htmlentitydefs import name2codepoint
import web

# Place a file in your ~/jenni/ folder named, bitly.txt
# and inside this file place your API key followed by a ','
# and then your username. For example, the only line in that
# file should look like this:
# R_d67798xkjc87sdx6x8c7kjc87,myusername

# this variable is to determine when to use bitly. If the URL is more
# than this length, it'll display a bitly URL instead. To disable bit.ly, put None
# even if it's set to None, triggering .bitly command will still work!
BITLY_TRIGGER_LEN = 50

# do not edit below this line unless you know what you're doing
bitly_loaded = 0
try:
    file = open("bitly.txt", "r")
    key = file.read()
    key = key.split(",")
    bitly_api_key = str(key[0].lstrip().rstrip())
    bitly_user = str(key[1].lstrip().rstrip())
    file.close()
    bitly_loaded = 1
except:
    print "ERROR: No bitly.txt found."

url_finder = re.compile(r'((http|https|ftp)(://\S+))')
r_entity = re.compile(r'&[A-Za-z0-9#]+;')
INVALID_WEBSITE = 0x01

def find_title(url):
    """
    This finds the title when provided with a string of a URL. It returns "
    """
    uri = url

    if not re.search('^((https?)|(ftp))://', uri):
        uri = 'http://' + uri

    if "twitter.com" in uri:
        uri = uri.replace('#!', '?_escaped_fragment_=')

    redirects = 0
    while True:
        req = urllib2.Request(uri, headers={'Accept':'text/html'})
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722')
        u = urllib2.urlopen(req)
        info = u.info()
        u.close()

        if not isinstance(info, list):
            status = '200'
        else:
            status = str(info[1])
            info = info[0]
        if status.startswith('3'):
            uri = urlparse.urljoin(uri, info['Location'])
        else: break

        redirects += 1
        if redirects >= 50:
            return "Too many re-directs."

    try: mtype = info['content-type']
    except:
        return
    if not (('/html' in mtype) or ('/xhtml' in mtype)):
        return

    u = urllib2.urlopen(req)
    bytes = u.read(262144)
    u.close()
    content = bytes
    regex = re.compile('<(/?)title( [^>]+)?>', re.IGNORECASE)
    content = regex.sub(r'<\1title>',content)
    regex = re.compile('[\'"]<title>[\'"]', re.IGNORECASE)
    content = regex.sub('',content)
    start = content.find('<title>')
    if start == -1: return INVALID_WEBSITE
    end = content.find('</title>', start)
    if end == -1: return
    content = content[start+7:end]
    content = content.strip('\n').rstrip().lstrip()
    title = content

    if len(title) > 200:
        title = title[:200] + '[...]'

    def e(m):
        entity = m.group()
        if entity.startswith('&#x'):
            cp = int(entity[3:-1],16)
            return unichr(cp).encode('utf-8')
        elif entity.startswith('&#'):
            cp = int(entity[2:-1])
            return unichr(cp).encode('utf-8')
        else:
            char = name2codepoint[entity[1:-1]]
            return unichr(char).encode('utf-8')

    title = r_entity.sub(e, title)

    if title:
        try: title.decode('utf-8')
        except:
            try: title = title.decode('iso-8859-1').encode('utf-8')
            except: title = title.decode('cp1252').encode('utf-8')
        else: pass
    else: title = 'None'

    title = title.replace('\n', '')
    title = title.replace('\r', '')

    def remove_spaces(x):
        if "  " in x:
            x = x.replace("  ", " ")
            return remove_spaces(x)
        else:
            return x

    title = remove_spaces (title)

    if title:
        return title

def short(text):
    """
    This function creates a bitly url for each url in the provided "text" string.
    The return type is a list.
    """

    if not bitly_loaded: return [ ]
    bitlys = [ ]
    try:
        a = re.findall(url_finder, text)
        k = len(a)
        i = 0
        while i < k:
            b = str(a[i][0])
            if not b.startswith("http://bit.ly") or not b.startswith("http://j.mp/"):
                # check to see if the url is valid
                try: c = web.head(b)
                except: return [[None, None]]

                url = "http://api.j.mp/v3/shorten?login=%s&apiKey=%s&longUrl=%s&format=txt" % (bitly_user, bitly_api_key, urllib2.quote(b))
                shorter = web.get(url)
                shorter.strip()
                bitlys.append([b, shorter])
            i += 1
        return bitlys
    except:
        return

def generateBitLy (jenni, input):
    if not bitly_loaded: return
    bitly = short(input)
    idx = 7
    for b in bitly:
        displayBitLy(jenni, b[0], b[1])
generateBitLy.commands = ['bitly']
generateBitLy.priority = 'high'

def displayBitLy (jenni, url, shorten):
    if url is None or shorten is None: return
    u = getTLD(url)
    jenni.say('%s  -  %s' % (u, shorten))

def getTLD (url):
    idx = 7
    if url.startswith('https://'): idx = 8
    elif url.startswith('ftp://'): idx = 6
    u = url[idx:]
    f = u.find('/')
    if f == -1: u = url
    else: u = url[0:idx] + u[0:f]
    return u

def doUseBitLy (url):
    return bitly_loaded and BITLY_TRIGGER_LEN is not None and len(url) > BITLY_TRIGGER_LEN

def get_results(text):
    a = re.findall(url_finder, text)
    k = len(a)
    i = 0
    display = [ ]
    while i < k:
        url = str(a[i][0])
        try:
            page_title = find_title(url)
        except:
            page_title = None # if it can't access the site fail silently
        if bitly_loaded: # and (page_title is not None or page_title == INVALID_WEBSITE):
            bitly = short(url)
            bitly = bitly[0][1]
        else: bitly = url
        display.append([page_title, url, bitly])
        i += 1
    return display

def show_title_auto (jenni, input):
    if input.startswith('.title ') or input.startswith('.bitly '): return
    regexp = jenni.config.nick + "\:.*\s\-\shttp://bit.ly/[\S]{6}$"
    if len(re.findall("\([\d]+\sfiles\sin\s[\d]+\sdirs\)", input)) == 1 or len(re.findall(regexp, input)) >= 1: return
    try:
        results = get_results(input)
    except: return
    if results is None: return

    for r in results:
        useBitLy = doUseBitLy(r[1])
        if r[0] is None:
            if useBitLy: displayBitLy(jenni, r[1], r[2])
            continue
        if useBitLy: r[1] = r[2]
        else: r[1] = getTLD(r[1])
        jenni.say('[ %s ] - %s' % (r[0], r[1]))
show_title_auto.rule = '.*((http|https)(://\S+)).*'
show_title_auto.priority = 'high'

def show_title_demand (jenni, input):
    try:
        results = get_results(input)
    except: return
    if results is None: return

    for r in results:
        if r[0] is None: continue
        if doUseBitLy(r[1]): r[1] = r[2]
        else: r[1] = getTLD(r[1])
        jenni.say('[ %s ] - %s' % (r[0], r[1]))
show_title_demand.commands = ['title']
show_title_demand.priority = 'high'

if __name__ == '__main__':
    print __doc__.strip()
<commit_msg>increased bitly length for URLs and removed an incomplete sentence.<commit_after>"""
url.py - Jenni Bitly Module
Author: Michael Yanovich, http://yanovich.net/
About: http://inamidst.com/phenny/

This module will record all URLs to bitly via an api key and account.
It also automatically displays the "title" of any URL pasted into the channel.
"""

import re, urllib2
from htmlentitydefs import name2codepoint
import web

# Place a file in your ~/jenni/ folder named, bitly.txt
# and inside this file place your API key followed by a ','
# and then your username. For example, the only line in that
# file should look like this:
# R_d67798xkjc87sdx6x8c7kjc87,myusername

# this variable is to determine when to use bitly. If the URL is more
# than this length, it'll display a bitly URL instead. To disable bit.ly, put None
# even if it's set to None, triggering .bitly command will still work!
BITLY_TRIGGER_LEN = 65

# do not edit below this line unless you know what you're doing
bitly_loaded = 0
try:
    file = open("bitly.txt", "r")
    key = file.read()
    key = key.split(",")
    bitly_api_key = str(key[0].lstrip().rstrip())
    bitly_user = str(key[1].lstrip().rstrip())
    file.close()
    bitly_loaded = 1
except:
    print "ERROR: No bitly.txt found."

url_finder = re.compile(r'((http|https|ftp)(://\S+))')
r_entity = re.compile(r'&[A-Za-z0-9#]+;')
INVALID_WEBSITE = 0x01

def find_title(url):
    """
    This finds the title when provided with a string of a URL."
    """
    uri = url

    if not re.search('^((https?)|(ftp))://', uri):
        uri = 'http://' + uri

    if "twitter.com" in uri:
        uri = uri.replace('#!', '?_escaped_fragment_=')

    redirects = 0
    while True:
        req = urllib2.Request(uri, headers={'Accept':'text/html'})
        req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.8) Gecko/20100722')
        u = urllib2.urlopen(req)
        info = u.info()
        u.close()

        if not isinstance(info, list):
            status = '200'
        else:
            status = str(info[1])
            info = info[0]
        if status.startswith('3'):
            uri = urlparse.urljoin(uri, info['Location'])
        else: break

        redirects += 1
        if redirects >= 50:
            return "Too many re-directs."

    try: mtype = info['content-type']
    except:
        return
    if not (('/html' in mtype) or ('/xhtml' in mtype)):
        return

    u = urllib2.urlopen(req)
    bytes = u.read(262144)
    u.close()
    content = bytes
    regex = re.compile('<(/?)title( [^>]+)?>', re.IGNORECASE)
    content = regex.sub(r'<\1title>',content)
    regex = re.compile('[\'"]<title>[\'"]', re.IGNORECASE)
    content = regex.sub('',content)
    start = content.find('<title>')
    if start == -1: return INVALID_WEBSITE
    end = content.find('</title>', start)
    if end == -1: return
    content = content[start+7:end]
    content = content.strip('\n').rstrip().lstrip()
    title = content

    if len(title) > 200:
        title = title[:200] + '[...]'

    def e(m):
        entity = m.group()
        if entity.startswith('&#x'):
            cp = int(entity[3:-1],16)
            return unichr(cp).encode('utf-8')
        elif entity.startswith('&#'):
            cp = int(entity[2:-1])
            return unichr(cp).encode('utf-8')
        else:
            char = name2codepoint[entity[1:-1]]
            return unichr(char).encode('utf-8')

    title = r_entity.sub(e, title)

    if title:
        try: title.decode('utf-8')
        except:
            try: title = title.decode('iso-8859-1').encode('utf-8')
            except: title = title.decode('cp1252').encode('utf-8')
        else: pass
    else: title = 'None'

    title = title.replace('\n', '')
    title = title.replace('\r', '')

    def remove_spaces(x):
        if "  " in x:
            x = x.replace("  ", " ")
            return remove_spaces(x)
        else:
            return x

    title = remove_spaces (title)

    if title:
        return title

def short(text):
    """
    This function creates a bitly url for each url in the provided "text" string.
    The return type is a list.
    """

    if not bitly_loaded: return [ ]
    bitlys = [ ]
    try:
        a = re.findall(url_finder, text)
        k = len(a)
        i = 0
        while i < k:
            b = str(a[i][0])
            if not b.startswith("http://bit.ly") or not b.startswith("http://j.mp/"):
                # check to see if the url is valid
                try: c = web.head(b)
                except: return [[None, None]]

                url = "http://api.j.mp/v3/shorten?login=%s&apiKey=%s&longUrl=%s&format=txt" % (bitly_user, bitly_api_key, urllib2.quote(b))
                shorter = web.get(url)
                shorter.strip()
                bitlys.append([b, shorter])
            i += 1
        return bitlys
    except:
        return

def generateBitLy (jenni, input):
    if not bitly_loaded: return
    bitly = short(input)
    idx = 7
    for b in bitly:
        displayBitLy(jenni, b[0], b[1])
generateBitLy.commands = ['bitly']
generateBitLy.priority = 'high'

def displayBitLy (jenni, url, shorten):
    if url is None or shorten is None: return
    u = getTLD(url)
    jenni.say('%s  -  %s' % (u, shorten))

def getTLD (url):
    idx = 7
    if url.startswith('https://'): idx = 8
    elif url.startswith('ftp://'): idx = 6
    u = url[idx:]
    f = u.find('/')
    if f == -1: u = url
    else: u = url[0:idx] + u[0:f]
    return u

def doUseBitLy (url):
    return bitly_loaded and BITLY_TRIGGER_LEN is not None and len(url) > BITLY_TRIGGER_LEN

def get_results(text):
    a = re.findall(url_finder, text)
    k = len(a)
    i = 0
    display = [ ]
    while i < k:
        url = str(a[i][0])
        try:
            page_title = find_title(url)
        except:
            page_title = None # if it can't access the site fail silently
        if bitly_loaded: # and (page_title is not None or page_title == INVALID_WEBSITE):
            bitly = short(url)
            bitly = bitly[0][1]
        else: bitly = url
        display.append([page_title, url, bitly])
        i += 1
    return display

def show_title_auto (jenni, input):
    if input.startswith('.title ') or input.startswith('.bitly '): return
    regexp = jenni.config.nick + "\:.*\s\-\shttp://bit.ly/[\S]{6}$"
    if len(re.findall("\([\d]+\sfiles\sin\s[\d]+\sdirs\)", input)) == 1 or len(re.findall(regexp, input)) >= 1: return
    try:
        results = get_results(input)
    except: return
    if results is None: return

    for r in results:
        useBitLy = doUseBitLy(r[1])
        if r[0] is None:
            if useBitLy: displayBitLy(jenni, r[1], r[2])
            continue
        if useBitLy: r[1] = r[2]
        else: r[1] = getTLD(r[1])
        jenni.say('[ %s ] - %s' % (r[0], r[1]))
show_title_auto.rule = '.*((http|https)(://\S+)).*'
show_title_auto.priority = 'high'

def show_title_demand (jenni, input):
    try:
        results = get_results(input)
    except: return
    if results is None: return

    for r in results:
        if r[0] is None: continue
        if doUseBitLy(r[1]): r[1] = r[2]
        else: r[1] = getTLD(r[1])
        jenni.say('[ %s ] - %s' % (r[0], r[1]))
show_title_demand.commands = ['title']
show_title_demand.priority = 'high'

if __name__ == '__main__':
    print __doc__.strip()
<|endoftext|>


<commit_before># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

"""Implement MD Integrator."""

import itertools

from hoomd.md import _md
from hoomd.data.parameterdicts import ParameterDict
from hoomd.data.typeconverter import OnlyFrom, OnlyTypes
from hoomd.integrate import BaseIntegrator
from hoomd.data import syncedlist
from hoomd.md.methods import Method
from hoomd.md.force import Force
from hoomd.md.constrain import Constraint, Rigid

def _preprocess_aniso(value):
    if value is True:
        return "true"
    elif value is False:
        return "false"
    else:
        return value

def _set_synced_list(old_list, new_list):
    old_list.clear()
    old_list.extend(new_list)

class _DynamicIntegrator(BaseIntegrator):

    def __init__(self, forces, constraints, methods, rigid):
        forces = [] if forces is None else forces
        constraints = [] if constraints is None else constraints
        methods = [] if methods is None else methods
        self._forces = syncedlist.SyncedList(
            Force, syncedlist._PartialGetAttr('_cpp_obj'), iterable=forces)

        self._constraints = syncedlist.SyncedList(
            OnlyTypes(Constraint, disallow_types=(Rigid,)),
            syncedlist._PartialGetAttr('_cpp_obj'),
            iterable=constraints)

        self._methods = syncedlist.SyncedList(
            Method, syncedlist._PartialGetAttr('_cpp_obj'), iterable=methods)

        param_dict = ParameterDict(rigid=OnlyTypes(Rigid, allow_none=True))
        if rigid is not None and rigid._added:
            raise ValueError("Rigid object can only belong to one integrator.")
        param_dict["rigid"] = rigid
        self._param_dict.update(param_dict)

    def _attach(self):
        self.forces._sync(self._simulation, self._cpp_obj.forces)
        self.constraints._sync(self._simulation, self._cpp_obj.constraints)
        self.methods._sync(self._simulation, self._cpp_obj.methods)
        super()._attach()
        if self.rigid is not None:
            self.rigid._attach()
            self._cpp_obj.rigid = self.rigid._cpp_obj

    def _add(self, simulation):
        super()._add(simulation)
        if self.rigid is not None:
            self.rigid._add(simulation)

    @property
    def forces(self):
        return self._forces

    @forces.setter
    def forces(self, value):
        _set_synced_list(self._forces, value)

    @property
    def constraints(self):
        return self._constraints

    @constraints.setter
    def constraints(self, value):
        _set_synced_list(self._constraints, value)

    @property
    def methods(self):
        return self._methods

    @methods.setter
    def methods(self, value):
        _set_synced_list(self._methods, value)

    @property
    def _children(self):
        children = list(self.forces)
        children.extend(self.constraints)
        children.extend(self.methods)

        for child in itertools.chain(self.forces, self.constraints,
                                     self.methods):
            children.extend(child._children)

        return children

    def _getattr_param(self, attr):
        if attr == "rigid":
            return self._param_dict["rigid"]
        return super()._getattr_param(attr)

    def _setattr_param(self, attr, value):
        if attr == "rigid":
            self._set_rigid(value)
            return
        super()._setattr_param(attr, value)

    def _set_rigid(self, value):
        """Handles the adding and detaching of potential Rigid objects."""
        # this generally only happens when attaching and we can ignore it since
        # we attach the rigid body in _attach.
        if value is self.rigid:
            return

        old_rigid = self.rigid
        self._param_dict["rigid"] = value

        if self.rigid is not None and self.rigid._added:
            raise ValueError("Cannot add Rigid object to multiple integrators.")

        if old_rigid is not None and self._attached:
            old_rigid._detach()

        if self._added:
            if old_rigid is not None:
                old_rigid._remove()
            self.rigid._add(self._simulation)

        if self._attached:
            self.rigid._attach()
            self._cpp_obj.rigid = value._cpp_obj

class Integrator(_DynamicIntegrator):
    """Enables a variety of standard integration methods.

    Args:
        dt (float): Integrator time step size :math:`[\\mathrm{time}]`.

        methods (Sequence[hoomd.md.methods.Method]): Sequence of integration
            methods. Each integration method can be applied to only a specific
            subset of particles. The intersection of the subsets must be null.
            The default value of ``None`` initializes an empty list.

        forces (Sequence[hoomd.md.force.Force]): Sequence of forces applied to
            the particles in the system. All the forces are summed together.
            The default value of ``None`` initializes an empty list.

        aniso (str or bool): Whether to integrate rotational degrees of freedom
            (bool), default 'auto' (autodetect if there is anisotropic factor
            from any defined active or constraint forces).

        constraints (Sequence[hoomd.md.constrain.Constraint]): Sequence of
            constraint forces applied to the particles in the system.
            The default value of ``None`` initializes an empty list. Rigid body
            objects (i.e. `hoomd.md.constrain.Rigid`) are not allowed in the
            list.

        rigid (hoomd.md.constrain.Rigid): A rigid bodies object defining the
            rigid bodies in the simulation.

    The following classes can be used as elements in `methods`

    - `hoomd.md.methods.Brownian`
    - `hoomd.md.methods.Langevin`
    - `hoomd.md.methods.NVE`
    - `hoomd.md.methods.NVT`
    - `hoomd.md.methods.NPT`

    The classes of following modules can be used as elements in `forces`

    - `hoomd.md.angle`
    - `hoomd.md.bond`
    - `hoomd.md.charge`
    - `hoomd.md.dihedral`
    - `hoomd.md.external.field`
    - `hoomd.md.force`
    - `hoomd.md.improper`
    - `hoomd.md.pair`
    - `hoomd.md.wall`
    - `hoomd.md.special_pair`

    The classes of the following module can be used as elements in `constraints`

    - `hoomd.md.constrain`

    Examples::

        nlist = hoomd.md.nlist.Cell()
        lj = hoomd.md.pair.LJ(nlist=nlist)
        lj.params.default = dict(epsilon=1.0, sigma=1.0)
        lj.r_cut[('A', 'A')] = 2**(1/6)
        nve = hoomd.md.methods.NVE(filter=hoomd.filter.All())
        integrator = hoomd.md.Integrator(dt=0.001, methods=[nve], forces=[lj])
        sim.operations.integrator = integrator

    Attributes:
        dt (float): Integrator time step size :math:`[\\mathrm{time}]`.

        methods (list[hoomd.md.methods.Method]): List of integration methods.
            Each integration method can be applied to only a specific subset of
            particles.

        forces (list[hoomd.md.force.Force]): List of forces applied to
            the particles in the system. All the forces are summed together.

        aniso (str): Whether rotational degrees of freedom are integrated.

        constraints (list[hoomd.md.constrain.Constraint]): List of
            constraint forces applied to the particles in the system.

        rigid (hoomd.md.constrain.Rigid): The rigid body definition for the
            simulation associated with the integrator.
    """

    def __init__(self,
                 dt,
                 aniso='auto',
                 forces=None,
                 constraints=None,
                 methods=None,
                 rigid=None):

        super().__init__(forces, constraints, methods, rigid)

        self._param_dict.update(
            ParameterDict(dt=float(dt),
                          aniso=OnlyFrom(['true', 'false', 'auto'],
                                         preprocess=_preprocess_aniso),
                          _defaults={"aniso": "auto"}))
        if aniso is not None:
            self.aniso = aniso

    def _attach(self):
        # initialize the reflected c++ class
        self._cpp_obj = _md.IntegratorTwoStep(
            self._simulation.state._cpp_sys_def, self.dt)
        # Call attach from DynamicIntegrator which attaches forces,
        # constraint_forces, and methods, and calls super()._attach() itself.
        super()._attach()
<commit_msg>Fix hoomd.md._DynamicIntegrator._detach<commit_after># Copyright (c) 2009-2021 The Regents of the University of Michigan
# This file is part of the HOOMD-blue project, released under the BSD 3-Clause
# License.

"""Implement MD Integrator."""

import itertools

from hoomd.md import _md
from hoomd.data.parameterdicts import ParameterDict
from hoomd.data.typeconverter import OnlyFrom, OnlyTypes
from hoomd.integrate import BaseIntegrator
from hoomd.data import syncedlist
from hoomd.md.methods import Method
from hoomd.md.force import Force
from hoomd.md.constrain import Constraint, Rigid

def _preprocess_aniso(value):
    if value is True:
        return "true"
    elif value is False:
        return "false"
    else:
        return value

def _set_synced_list(old_list, new_list):
    old_list.clear()
    old_list.extend(new_list)

class _DynamicIntegrator(BaseIntegrator):

    def __init__(self, forces, constraints, methods, rigid):
        forces = [] if forces is None else forces
        constraints = [] if constraints is None else constraints
        methods = [] if methods is None else methods
        self._forces = syncedlist.SyncedList(
            Force, syncedlist._PartialGetAttr('_cpp_obj'), iterable=forces)

        self._constraints = syncedlist.SyncedList(
            OnlyTypes(Constraint, disallow_types=(Rigid,)),
            syncedlist._PartialGetAttr('_cpp_obj'),
            iterable=constraints)

        self._methods = syncedlist.SyncedList(
            Method, syncedlist._PartialGetAttr('_cpp_obj'), iterable=methods)

        param_dict = ParameterDict(rigid=OnlyTypes(Rigid, allow_none=True))
        if rigid is not None and rigid._added:
            raise ValueError("Rigid object can only belong to one integrator.")
        param_dict["rigid"] = rigid
        self._param_dict.update(param_dict)

    def _attach(self):
        self.forces._sync(self._simulation, self._cpp_obj.forces)
        self.constraints._sync(self._simulation, self._cpp_obj.constraints)
        self.methods._sync(self._simulation, self._cpp_obj.methods)
        super()._attach()
        if self.rigid is not None:
            self.rigid._attach()
            self._cpp_obj.rigid = self.rigid._cpp_obj

    def _detach(self):
        self.forces._unsync()
        self.methods._unsync()
        self.constraints._unsync()
        if self.rigid is not None:
            self.rigid._detach()
        super()._detach()

    def _remove(self):
        if self.rigid is not None:
            self.rigid._detach()
        super()._remove()

    def _add(self, simulation):
        super()._add(simulation)
        if self.rigid is not None:
            self.rigid._add(simulation)

    @property
    def forces(self):
        return self._forces

    @forces.setter
    def forces(self, value):
        _set_synced_list(self._forces, value)

    @property
    def constraints(self):
        return self._constraints

    @constraints.setter
    def constraints(self, value):
        _set_synced_list(self._constraints, value)

    @property
    def methods(self):
        return self._methods

    @methods.setter
    def methods(self, value):
        _set_synced_list(self._methods, value)

    @property
    def _children(self):
        children = list(self.forces)
        children.extend(self.constraints)
        children.extend(self.methods)

        for child in itertools.chain(self.forces, self.constraints,
                                     self.methods):
            children.extend(child._children)

        return children

    def _getattr_param(self, attr):
        if attr == "rigid":
            return self._param_dict["rigid"]
        return super()._getattr_param(attr)

    def _setattr_param(self, attr, value):
        if attr == "rigid":
            self._set_rigid(value)
            return
        super()._setattr_param(attr, value)

    def _set_rigid(self, value):
        """Handles the adding and detaching of potential Rigid objects."""
        # this generally only happens when attaching and we can ignore it since
        # we attach the rigid body in _attach.
        if value is self.rigid:
            return

        old_rigid = self.rigid
        self._param_dict["rigid"] = value

        if self.rigid is not None and self.rigid._added:
            raise ValueError("Cannot add Rigid object to multiple integrators.")

        if old_rigid is not None and self._attached:
            old_rigid._detach()

        if self._added:
            if old_rigid is not None:
                old_rigid._remove()
            self.rigid._add(self._simulation)

        if self._attached:
            self.rigid._attach()
            self._cpp_obj.rigid = value._cpp_obj

class Integrator(_DynamicIntegrator):
    """Enables a variety of standard integration methods.

    Args:
        dt (float): Integrator time step size :math:`[\\mathrm{time}]`.

        methods (Sequence[hoomd.md.methods.Method]): Sequence of integration
            methods. Each integration method can be applied to only a specific
            subset of particles. The intersection of the subsets must be null.
            The default value of ``None`` initializes an empty list.

        forces (Sequence[hoomd.md.force.Force]): Sequence of forces applied to
            the particles in the system. All the forces are summed together.
            The default value of ``None`` initializes an empty list.

        aniso (str or bool): Whether to integrate rotational degrees of freedom
            (bool), default 'auto' (autodetect if there is anisotropic factor
            from any defined active or constraint forces).

        constraints (Sequence[hoomd.md.constrain.Constraint]): Sequence of
            constraint forces applied to the particles in the system.
            The default value of ``None`` initializes an empty list. Rigid body
            objects (i.e. `hoomd.md.constrain.Rigid`) are not allowed in the
            list.

        rigid (hoomd.md.constrain.Rigid): A rigid bodies object defining the
            rigid bodies in the simulation.

    The following classes can be used as elements in `methods`

    - `hoomd.md.methods.Brownian`
    - `hoomd.md.methods.Langevin`
    - `hoomd.md.methods.NVE`
    - `hoomd.md.methods.NVT`
    - `hoomd.md.methods.NPT`

    The classes of following modules can be used as elements in `forces`

    - `hoomd.md.angle`
    - `hoomd.md.bond`
    - `hoomd.md.charge`
    - `hoomd.md.dihedral`
    - `hoomd.md.external.field`
    - `hoomd.md.force`
    - `hoomd.md.improper`
    - `hoomd.md.pair`
    - `hoomd.md.wall`
    - `hoomd.md.special_pair`

    The classes of the following module can be used as elements in `constraints`

    - `hoomd.md.constrain`

    Examples::

        nlist = hoomd.md.nlist.Cell()
        lj = hoomd.md.pair.LJ(nlist=nlist)
        lj.params.default = dict(epsilon=1.0, sigma=1.0)
        lj.r_cut[('A', 'A')] = 2**(1/6)
        nve = hoomd.md.methods.NVE(filter=hoomd.filter.All())
        integrator = hoomd.md.Integrator(dt=0.001, methods=[nve], forces=[lj])
        sim.operations.integrator = integrator

    Attributes:
        dt (float): Integrator time step size :math:`[\\mathrm{time}]`.

        methods (list[hoomd.md.methods.Method]): List of integration methods.
            Each integration method can be applied to only a specific subset of
            particles.

        forces (list[hoomd.md.force.Force]): List of forces applied to
            the particles in the system. All the forces are summed together.

        aniso (str): Whether rotational degrees of freedom are integrated.

        constraints (list[hoomd.md.constrain.Constraint]): List of
            constraint forces applied to the particles in the system.

        rigid (hoomd.md.constrain.Rigid): The rigid body definition for the
            simulation associated with the integrator.
    """

    def __init__(self,
                 dt,
                 aniso='auto',
                 forces=None,
                 constraints=None,
                 methods=None,
                 rigid=None):

        super().__init__(forces, constraints, methods, rigid)

        self._param_dict.update(
            ParameterDict(dt=float(dt),
                          aniso=OnlyFrom(['true', 'false', 'auto'],
                                         preprocess=_preprocess_aniso),
                          _defaults={"aniso": "auto"}))
        if aniso is not None:
            self.aniso = aniso

    def _attach(self):
        # initialize the reflected c++ class
        self._cpp_obj = _md.IntegratorTwoStep(
            self._simulation.state._cpp_sys_def, self.dt)
        # Call attach from DynamicIntegrator which attaches forces,
        # constraint_forces, and methods, and calls super()._attach() itself.
        super()._attach()
<|endoftext|>