[cig-commits] r11763 - in cs/portal/trunk/seismo/SeismoWebPortal: . templates/SeismoWebPortal

leif at geodynamics.org leif at geodynamics.org
Mon Apr 7 18:59:03 PDT 2008


Author: leif
Date: 2008-04-07 18:59:03 -0700 (Mon, 07 Apr 2008)
New Revision: 11763

Removed:
   cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/specfem3dgloberequest_form.html
Modified:
   cs/portal/trunk/seismo/SeismoWebPortal/forms.py
   cs/portal/trunk/seismo/SeismoWebPortal/models.py
   cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/eventworkspace_form.html
   cs/portal/trunk/seismo/SeismoWebPortal/views.py
Log:
Request object POST, query, and matching.


Modified: cs/portal/trunk/seismo/SeismoWebPortal/forms.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/forms.py	2008-04-07 22:33:23 UTC (rev 11762)
+++ cs/portal/trunk/seismo/SeismoWebPortal/forms.py	2008-04-08 01:59:03 UTC (rev 11763)
@@ -319,6 +319,7 @@
         # Create a new workspace for this event.
         workspace = EventWorkspace(event = event,
                                    stations = StationList.favorite(),
+                                   zero_half_duration = True,
                                    )
         workspace.save()
         
@@ -517,8 +518,12 @@
             Source.saveSource(event, cmtSolution)
 
         # Create a new workspace for this event.
+        zero_half_duration = False
+        if event.singleSource:
+            zero_half_duration = True
         workspace = EventWorkspace(event = event,
                                    stations = StationList.favorite(),
+                                   zero_half_duration = zero_half_duration,
                                    )
         workspace.save()
         

Modified: cs/portal/trunk/seismo/SeismoWebPortal/models.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/models.py	2008-04-07 22:33:23 UTC (rev 11762)
+++ cs/portal/trunk/seismo/SeismoWebPortal/models.py	2008-04-08 01:59:03 UTC (rev 11763)
@@ -528,13 +528,21 @@
             self.fsNode.save() # touch
         return
 
-    def snapshot(self):
+    def snapshot(self, workspace):
         return dict(
             mesh = self.mesh.snapshot(),
             model = self.model.snapshot(),
             receivers_can_be_buried = self.receivers_can_be_buried,
+            zero_half_duration = workspace.zero_half_duration,
             )
 
+    code = 1  # cf. CODE_CHOICES
+    offering = "3D Synthetics by Specfem 3D Globe"
+
+    @classmethod
+    def canHandleEvent(cls, event):
+        return True
+
     class Admin:
         pass
 
@@ -668,7 +676,7 @@
             self.fsNode.save() # touch
         return
 
-    def snapshot(self):
+    def snapshot(self, workspace):
         return dict(
             catalog = self.catalog.snapshot(),
             model = self.model.snapshot(),
@@ -681,7 +689,15 @@
             step = self.step,
             )
 
+    code = 2  # cf. CODE_CHOICES
+    offering = "1D Synthetics by Mineos"
 
+    @classmethod
+    def canHandleEvent(cls, event):
+        return event.singleSource is not None
+
+
+
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Event Workspaces
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -734,25 +750,72 @@
     name = models.CharField(maxlength=100, primary_key=True)
 
     @classmethod
-    def get(cls, name):
+    def getStatus(cls, name):
         status, created = cls.objects.get_or_create(name = name,
                                                     defaults = dict(name = name))
         return status
 
     @classmethod
-    def new(cls):    return cls.get('new')
+    def statusNew(cls):     return cls.getStatus('new')
 
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# Requests
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CODE_CHOICES = (
+    (1, 'Specfem 3D Globe'),
+    (2, 'Mineos'),
+)
+
+
+class Request(models.Model):
+
+    # Multi-source Events are immutable.  Point-source Events are
+    # mutable, but the underlying CMTSolution is not.  Therefore:
+    #     event > 0: a CMTSolution.id for a point-source event
+    #     event < 0: a (negated) Event.id for a multi-source event
+    event = models.IntegerField(db_index=True)
+    
+    stations = models.ForeignKey(StationList)
+    record_length = models.FloatField(max_digits=19, decimal_places=10, core=True, default=20.0,
+                                      validator_list=[isValidRecordLength])
+
+    code = models.IntegerField(choices=CODE_CHOICES)
+    parameterData = models.TextField()
+
+    def _getParameters(self):
+        if not hasattr(self, '_parameters'):
+            import base64
+            import cPickle as pickle
+            p = base64.decodestring(self.parameterData)
+            self._parameters = pickle.loads(p)
+        return self._parameters
+    parameters = property(lambda self: self._getParameters())
+
+    @classmethod
+    def encodeParameters(cls, parameters):
+        import base64
+        import cPickle as pickle
+        p = pickle.dumps(parameters)
+        return base64.encodestring(p)
+
+
+class Foo:
+    
+    def nsamples(self):
+        from math import ceil
+        return int(ceil(self.record_length * 60.0 / self.parameters.step))
+
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Runs, Jobs
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
 class Run(models.Model):
     # each request may have multiple runs
-    contentType = models.ForeignKey(ContentType, db_index=True)
-    objectId = models.PositiveIntegerField(db_index=True)
-    request = models.GenericForeignKey(ct_field='contentType', fk_field='objectId')
+    request = models.ForeignKey(Request)
 
     status = models.ForeignKey(Status, db_index=True)
     started = models.DateTimeField(auto_now_add=True, editable=False)
@@ -791,56 +854,6 @@
 
 
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Requests
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-CODE_CHOICES = (
-    (1, 'Specfem 3D Globe'),
-    (2, 'Mineos'),
-)
-
-
-class Request(models.Model):
-
-    # Multi-source Events are immutable.  Point-source Events are
-    # mutable, but the underlying CMTSolution is not.  Therefore:
-    #     event > 0: a CMTSolution.id for a point-source event
-    #     event < 0: a (negated) Event.id for a multi-source event
-    event = models.IntegerField(db_index=True)
-    
-    stations = models.ForeignKey(StationList)
-    record_length = models.FloatField(max_digits=19, decimal_places=10, core=True, default=20.0,
-                                      validator_list=[isValidRecordLength])
-
-    code = models.IntegerField(choices=CODE_CHOICES)
-    parameterData = models.TextField()
-
-    runs = models.ForeignKey(Run, db_index=True)
-    status = models.ForeignKey(Status, db_index=True)
-
-    def _getParameters(self):
-        import base64
-        import cPickle as pickle
-        p = base64.decodestring(self.parameterData)
-        return pickle.loads(p)
-    parameters = property(lambda self: self._getParameters())
-
-    @classmethod
-    def encodeParameters(cls, parameters):
-        import base64
-        import cPickle as pickle
-        p = pickle.dumps(parameters)
-        return base64.encodestring(p)
-
-
-class Foo:
-    
-    def nsamples(self):
-        from math import ceil
-        return int(ceil(self.record_length * 60.0 / self.parameters.step))
-
-
-# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 # Registration
 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

Modified: cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/eventworkspace_form.html
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/eventworkspace_form.html	2008-04-07 22:33:23 UTC (rev 11762)
+++ cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/eventworkspace_form.html	2008-04-08 01:59:03 UTC (rev 11763)
@@ -22,6 +22,22 @@
         {% if help_visible %}<span class=help>Choose the desired record length of the synthetic seismograms (in minutes). This controls the length of the numerical simulation, i.e., twice the record length requires twice as much CPU time. This must be 100 minutes or less for simulations run via the web.</span>{% endif %}
     </div>
 
+    <p></p>
+
+    <fieldset><legend>3D Synthetics</legend>
+
+    <div class=checkbox>
+        {{ form.zero_half_duration }}
+        <label for="id_zero_half_duration" class=after>zero half duration</label>
+        {% if form.zero_half_duration.errors %}<span class=error>{{ form.zero_half_duration.errors|join:", " }}</span>{% endif %}
+    </div>
+
+    {% if help_visible %}
+    <dl class=help><dt>zero half duration</dt><dd>For point-source simulations, we recommend setting the source half-duration parameter <code>half duration</code> equal to zero, which corresponds to simulating a step source-time function, i.e., a moment-rate function that is a delta function. If <code>half duration</code> is not set to zero, the code will use a Gaussian (i.e., a signal with a shape similar to a 'smoothed triangle', as explained in Komatitsch and Tromp [2002a]) source-time function with half-width <code>half duration</code>. We prefer to run the solver with <code>half duration</code> set to zero and convolve the resulting synthetic seismograms in post-processing after the run, because this way it is easy to use a variety of source-time functions. Komatitsch and Tromp [2002a] determined that the noise generated in the simulation by using a step source time function may be safely filtered out afterward based upon a convolution with the desired source time function and/or low-pass filtering. Use the script <code>process_syn.pl</code> for this purpose by specifying the <code>-h</code> option (the <code>process_syn.pl</code> script can be found in the <a href="{{root}}/samples/UTILS.tar.gz">utilities package</a>). Alternatively, use signal-processing software packages such as <a href="http://www.llnl.gov/sac/">SAC</a>.<p>For finite fault simulations, it is usually not advisable to use a zero half duration and convolve afterwards, since the half duration is generally fixed by the finite fault model.</dd></dl>
+    {% endif %}
+
+    </fieldset>
+
     <div><input class=submit type="submit" name="save" value="Save" />
     </div>
 

Deleted: cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/specfem3dgloberequest_form.html
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/specfem3dgloberequest_form.html	2008-04-07 22:33:23 UTC (rev 11762)
+++ cs/portal/trunk/seismo/SeismoWebPortal/templates/SeismoWebPortal/specfem3dgloberequest_form.html	2008-04-08 01:59:03 UTC (rev 11763)
@@ -1,10 +0,0 @@
-
-    <div class=checkbox>
-        {{ form.zero_half_duration }}
-        <label for="id_zero_half_duration" class=after>zero half duration</label>
-        {% if form.zero_half_duration.errors %}<span class=error>{{ form.zero_half_duration.errors|join:", " }}</span>{% endif %}
-    </div>
-
-    {% if help_visible %}
-    <dl class=help><dt>zero half duration</dt><dd>For point-source simulations, we recommend setting the source half-duration parameter <code>half duration</code> equal to zero, which corresponds to simulating a step source-time function, i.e., a moment-rate function that is a delta function. If <code>half duration</code> is not set to zero, the code will use a Gaussian (i.e., a signal with a shape similar to a 'smoothed triangle', as explained in Komatitsch and Tromp [2002a]) source-time function with half-width <code>half duration</code>. We prefer to run the solver with <code>half duration</code> set to zero and convolve the resulting synthetic seismograms in post-processing after the run, because this way it is easy to use a variety of source-time functions. Komatitsch and Tromp [2002a] determined that the noise generated in the simulation by using a step source time function may be safely filtered out afterward based upon a convolution with the desired source time function and/or low-pass filtering. Use the script <code>process_syn.pl</code> for this purpose by specifying the <code>-h</code> option (the <code>process_syn.pl</code> script can be found in the <a href="{{root}}/samples/UTILS.tar.gz">utilities package</a>). Alternatively, use signal-processing software packages such as <a href="http://www.llnl.gov/sac/">SAC</a>.<p>For finite fault simulations, it is usually not advisable to use a zero half duration and convolve afterwards, since the half duration is generally fixed by the finite fault model.</dd></dl>
-    {% endif %}

Modified: cs/portal/trunk/seismo/SeismoWebPortal/views.py
===================================================================
--- cs/portal/trunk/seismo/SeismoWebPortal/views.py	2008-04-07 22:33:23 UTC (rev 11762)
+++ cs/portal/trunk/seismo/SeismoWebPortal/views.py	2008-04-08 01:59:03 UTC (rev 11763)
@@ -17,13 +17,14 @@
 from models import MineosModeCatalog, MineosModel, MineosParameters
 from models import Run, Job, OutputFile
 from models import FSNode, Folder
-from models import EventWorkspace
+from models import EventWorkspace, Request, Status
 from cmt import CMTSolution
 import config
 import gui
 
 import os, os.path
 from HTMLParser import HTMLParser
+from StringIO import StringIO
 
 
 static_media_root = os.environ.get("WEBPORTAL_MEDIA_ROOT")+'/static'
@@ -121,6 +122,7 @@
         "trash": trashFolder,
         "config": configFactory,
         "events": event_search,
+        "requests": requests,
         "profile": profile,
         "logout": logout,
         "help": help,
@@ -230,7 +232,6 @@
 
 
 def folderIconView(folder):
-    from StringIO import StringIO
 
     name = folder.fsNode.name
     items = FSNode.objects.filter(parent=folder.fsNode)
@@ -1265,7 +1266,6 @@
 
 
 def seismogramTable(workspace, url, request, path, appWindow, desktop):
-    from StringIO import StringIO
 
     event = workspace.event
     seismogramsIcon = appWindow.root.contents[0]
@@ -1277,44 +1277,93 @@
     html = StringIO()
     print >>html, '<h2>%s - Seismograms</h2>' % workspace
 
-    if event.singleSource:
-        # 1D Synthetics
-        print >>html, '<h3>1D Synthetics</h3>'
+    parameterClasses = [MineosParameters, Specfem3DGlobeParameters]
+
+    requests = {}
+    for ParameterClass in parameterClasses:
+        requests[ParameterClass.code] = []
+    for request in Request.objects.filter(event = requestEventId(event),
+                                          stations = workspace.stations,
+                                          record_length__gte = workspace.record_length):
+        requests[request.code].append(request)
+
+    for ParameterClass in parameterClasses:
+        if not ParameterClass.canHandleEvent(event):
+            continue
+        print >>html, '<h3>%s</h3>' % ParameterClass.offering
         print >>html, '<table rules="groups" class="cool">'
         print >>html, '<thead>'
         print >>html, '<tr><th>parameter set</th><th>status</th><th></th></tr>'
         print >>html, '</thead>'
         print >>html, '<tbody>'
-        for i, ps in enumerate(MineosParameters.objects.all()):
-            print >>html, '<tr class=%s><td><a href="%s">%s</a></td><td>unavailable</td><td>%s</td></tr>' % (
-                (i % 2 and 'even' or 'odd'), ps.fsNode.url(), ps, requestForm())
+        for i, ps in enumerate(ParameterClass.objects.all()):
+            status = '<td>unavailable</td><td>%s</td>' % requestForm(workspace, ps)
+            parameters = ps.snapshot(workspace)
+            for request in requests[ParameterClass.code]:
+                if request.parameters == parameters:
+                    status = '<td colspan=2>%s</td>' % "waiting for dispatch"
+                    break
+            print >>html, '<tr class=%s><td><a href="%s">%s</a></td>%s</tr>' % (
+                (i % 2 and 'even' or 'odd'), ps.fsNode.url(), ps, status)
         print >>html, '</tbody>'
         print >>html, '</table>'
 
         print >>html, "<p></p>"
 
-    # 3D Synthetics
-    print >>html, '<h3>3D Synthetics</h3>'
-    print >>html, '<table rules=groups class=cool>'
-    print >>html, '<thead>'
-    print >>html, '<tr><th>parameter set</th><th>status</th><th></th></tr>'
-    print >>html, '</thead>'
-    for i, ps in enumerate(Specfem3DGlobeParameters.objects.all()):
-        print >>html, '<tr class=%s><td><a href="%s">%s</a></td><td>unavailable</td><td>%s</td></tr>' % (
-            (i % 2 and 'even' or 'odd'), ps.fsNode.url(), ps, requestForm())
-    print >>html, '</table>'
-    
     window.content = gui.StaticContent(html.getvalue())
     desktop.activeWindow.selectWindow(window)
     
     return desktop
 
 
-def requestForm():
-    # NYI
-    return '<form method="post" action="%s/requests/new/"><input type="submit" value="Request" /></form>' % config.root
+def requestForm(workspace, parameters):
+    html = StringIO()
+    print >>html, '<form method="post" action="%s/requests/new/">' % config.root
+    print >>html, '<input type="hidden" name="workspace" value="%d"/>' % workspace.id
+    print >>html, '<input type="hidden" name="code" value="%d"/>' % parameters.code
+    print >>html, '<input type="hidden" name="parameters" value="%d"/>' % parameters.id
+    print >>html, '<input type="submit" value="Request" />'
+    print >>html, '</form>'
+    return html.getvalue()
 
 
+def requests(request, path, desktop):
+    if not path or request.method != 'POST': raise Http404
+    name = path.pop(0)
+    if name != "new" or path: raise Http404
+
+    workspace = EventWorkspace.objects.get(id = int(request.POST['workspace']))
+    code = int(request.POST['code'])
+    if code == Specfem3DGlobeParameters.code:
+        parameters = Specfem3DGlobeParameters.objects.get(id = int(request.POST['parameters']))
+    elif code == MineosParameters.code:
+        parameters = MineosParameters.objects.get(id = int(request.POST['parameters']))
+    else:
+        raise Http404
+
+    request = Request()
+    event = workspace.event
+    request.event = requestEventId(event)
+    request.stations = workspace.stations
+    request.record_length = workspace.record_length
+
+    parameterData = parameters.snapshot(workspace)
+    request.code = code
+    request.parameterData = Request.encodeParameters(parameterData)
+
+    request.save()
+    
+    return HttpResponseRedirect(workspace.fsNode.url())
+
+
+def requestEventId(event):
+    if event.singleSource:
+        id = event.singleSource.cmtSolution.id
+    else:
+        id = -event.id
+    return id
+
+
 def eventFiles(name, event, request):
     index = Index({
         "CMTSOLUTION.txt": (event_detail_cmtsolution_txt, (), dict(event = event)),
@@ -1786,7 +1835,6 @@
             ]
 
     def get_validation_errors(self, new_data):
-        from StringIO import StringIO
         
         errors = super(UploadStationListManipulator, self).get_validation_errors(new_data)
         
@@ -1801,7 +1849,6 @@
         return errors
 
     def save(self, new_data, user):
-        from StringIO import StringIO
 
         # Create the new station list.
         stationList = StationList.objects.create()
@@ -2020,7 +2067,6 @@
             ]
 
     def get_validation_errors(self, new_data):
-        from StringIO import StringIO
         
         errors = super(UploadMineosModelManipulator, self).get_validation_errors(new_data)
         
@@ -2035,7 +2081,6 @@
         return errors
 
     def save(self, new_data, user):
-        from StringIO import StringIO
 
         # Parse the uploaded MODEL file.
         content = new_data['model']['content']



More information about the cig-commits mailing list