예제 #1
0
 def findOverlap(self, a, b, dur):
     """Utility for returning the fraction of given duration that
     is spent in the overlap of the two given tuples.
     """
     a1, a2 = a
     b1, b2 = b
     # what's the overlap between them (like the Galactice Center)?
     if AnalogSet.overlaps(a, b):
         ints = AnalogSet.intersect(a, b)
         # if our range is entirely in overlap, avoid calculations
         if self.fltEqual(ints[0], a1) \
             and self.fltEqual(ints[1], a2):
             overlap = dur
             nonOverlap = 0
         else:    
            # otherwise we need to convert back to duration - 
            # one way to do this is via fractions
            frac = (ints[1] - ints[0]) / (a2 - a1)
            overlap = dur * frac
            nonOverlap = (1.0 - frac) * dur
     else:
         overlap = 0
         nonOverlap = dur
         
     return (overlap, nonOverlap)
예제 #2
0
 def electivesResolvable(self, p1, p2):
 
     # must be electives
     if not p1.session.isElective() or not p2.session.isElective():
         self.annotate( "Not electives: %s %s" % (p1, p2))
         return False
 
     # one of their elective groups must have another period we can choose
     p1total = len(p1.elective.periods.all())
     p2total = len(p2.elective.periods.all())
     if p1total + p2total < 3:
         # no options!
         self.annotate( "Not enough periods in elective groups: %s %s" % (p1, p2))
         return False
 
     # Okay, so, one of the elective groups must choose it's first period,
     # and the other elective group must choose it's second period.
     # But make sure you choose periods that actually exist
     p1choosen, p2choosen = (0, 1) if p2total > 1 else (1, 0)
     ep1 = p1.elective.periods.all().order_by('start')[p1choosen]
     ep2 = p2.elective.periods.all().order_by('start')[p2choosen]
 
     # if these don't overlap, we're good
     return AnalogSet.overlaps((ep1.start, ep1.end())
                             , (ep2.start, ep2.end())
                              )
예제 #3
0
파일: Period.py 프로젝트: mmccarty/nell
    def get_prescheduled_times(start, end, project = None):
        """
        Returns a list of binary tuples of the form (start, end) that
        describe when this project cannot observe because other 
        projects already have scheduled telescope periods during
        the time range specified by the start and end arguments.
        NOTE: this is functionally identical to 
        Project.get_prescheduled_times, but uses a DB query to
        improve performance; Project cannot do this becuase the query
        causes circular references.
        """

        def truncatePeriodRange(p, start, end):
            "we don't care about periods outside of range"
            s = max(p.start, start)
            e = min(p.end(), end)
            return (s, e) 

        # first query DB simply by the time range
        minutes = timedelta2minutes(end - start)
        ps1 = Period.get_periods(start, minutes)

        # now filter out other stuff
        pId = None
        if project is not None:
            pId = project.id
        scheduled = Period_State.get_state('S')
        times = [truncatePeriodRange(p, start, end) for p in ps1 \
            if p.session.project.id != pId \
            and p.state == scheduled \
            and AnalogSet.overlaps((p.start, p.end()), (start, end))]
        return sorted(AnalogSet.unions(times))
예제 #4
0
파일: Window.py 프로젝트: mmccarty/nell
 def isInWindow(self, period):
     "Does the given period overlap at all in window (endpoints)"
     if len(self.ranges()) > 0:
         return AnalogSet.overlaps((self.start_datetime(), self.end_datetime())
                                 , (period.start, period.end()))
     else:
         # how can the period be in the window, when the window isn't
         # properly defined?
         return False
예제 #5
0
파일: Window.py 프로젝트: mmccarty/nell
 def isInRanges(self, period):
     """
     Does the given period overlap with any of the window ranges?
     This is more rigourous then isInWindow.
     """
     for wr in self.windowrange_set.all():
         if AnalogSet.overlaps((wr.start_datetime(), wr.end_datetime())
                             , (period.start, period.end())):
             return True
     return False # no overlaps at all!        
예제 #6
0
def report_overlaps(periods, now = None):
    """
    We don't want to report on *any* overlaps in the schedule.  Apply
    some pretty complex rules to keep this more meaningful.
    """
    if now is None:
        now = datetime.utcnow()
    values  = []
    overlap = []
    not_deleted_periods = [p for p in periods if p.state.abbreviation != "D"]
    for p1 in not_deleted_periods:
        start1, end1 = p1.start, p1.end()
        for p2 in not_deleted_periods:
            start2, end2 = p2.start, p2.end()
            if p1 != p2 and p1 not in overlap and p2 not in overlap:
                # what kind of overlap?
                type = ""
                if AnalogSet.overlaps((start1, end1), (start2, end2)):
                    # in the past?
                    if p1.start < now or p2.start < now:
                        type = "Overlap in past"
                    # any scheduled?    
                    if p1.isScheduled() or p2.isScheduled():
                        type = "Overlap with scheduled period"
                    # if it's not one of the above types, see if a 3rd period
                    # is involved:
                    if type == "":
                        # check just the nearest neighbors
                        oneWeekBefore = p1.start - timedelta(days = 7)
                        oneWeekAfter  = p1.start + timedelta(days = 7)
                        neighbors = Period.objects.exclude(state__abbreviation = "D").filter(start__gt = oneWeekBefore
                                       , start__lt = oneWeekAfter)
                        for p3 in neighbors:
                            if p1 != p3 and p2 != p3 and p3 not in overlap:
                                start3, end3 = p3.start, p3.end()
                                if AnalogSet.overlaps((start1, end1), (start3, end3)) \
                                  or AnalogSet.overlaps((start2, end2), (start3, end3)):
                                    type = "Overlap of 3 periods"  
                    if type != "": 
                        values.append("%s: %s and %s" % (type, str(p1), str(p2)))
                        overlap.extend([p1, p2])
    return values
예제 #7
0
 def findOverlaps(self, periods):
     values = []
     overlap = []
     for p1 in periods:
         start1, end1 = p1.start, p1.end()
         for p2 in periods:
             start2, end2 = p2.start, p2.end()
             if p1 != p2 and p1 not in overlap and p2 not in overlap:
                 if AnalogSet.overlaps((start1, end1), (start2, end2)):
                     values.append((p1, p2))
                     overlap.extend([p1, p2])
     return (overlap, values)
예제 #8
0
파일: Project.py 프로젝트: mmccarty/nell
    def get_prescheduled_times(self, start, end):
        """
        Returns a list of binary tuples of the form (start, end) that
        describe when this project cannot observe because other 
        projects already have scheduled telescope periods during
        the time range specified by the start and end arguments.
        """

        def truncatePeriodRange(p, start, end):
            s = max(p.start, start)
            e = min(p.end(), end)
            return (s, e)

        times = [truncatePeriodRange(d, start, end) \
                 for p in Project.objects.all() \
                 # TBF: that's why this takes so long!  limit the
                 # periods by the time range a little!!!!
                 for d in p.getPeriods() \
                 if p != self and \
                    d.state.abbreviation == 'S' and \
                    AnalogSet.overlaps((d.start, d.end()), (start, end))]
        return sorted(AnalogSet.unions(times))
예제 #9
0
    def calculate(self):
        "Calculate all the quantities needed for this report."

        self.currentSemester   = Semester.getCurrentSemester(self.start)
        self.previousSemesters = Semester.getPreviousSemesters(self.start)
        # TBF: watch for bug!
        self.previousSemesters = [s for s in self.previousSemesters if s != self.currentSemester]
        self.futureSemesters   = Semester.getFutureSemesters(self.start)

        # just those scheduled periods in the current week
        self.observed_periods = \
            sorted(set([p for p in self.periods \
                          if AnalogSet.overlaps((p.start, p.end()), (self.start, self.end))]))
        # just those scheduled periods in the upcoming week                  
        self.upcoming_periods = \
            sorted(set([p for p in self.periods \
                          if AnalogSet.overlaps((p.start, p.end())
                                    , (self.next_start, self.next_end))]))

        self.last_month   = self.start - timedelta(days = 31)
        # scheduled periods from last month
        self.last_periods = [p for p in self.periods \
                          if p.start.month == self.last_month.month and \
                             p.start.year  == self.last_month.year]
        # scheduled periods from this month                     
        self.this_periods = [p for p in self.periods \
                          if p.start.month == self.start.month and \
                             p.start.year  == self.start.year]  

        # how does the lost time break down for all the scheduled periods in the current week?
        self.lost_hours["total_time"] = sum([p.accounting.lost_time() for p in self.observed_periods])
        self.lost_hours["weather" ] = sum([p.accounting.lost_time_weather for p in self.observed_periods])
        self.lost_hours["RFI" ] = sum([p.accounting.lost_time_rfi for p in self.observed_periods])
        self.lost_hours["other" ] = sum([p.accounting.lost_time_other for p in self.observed_periods])
        self.lost_hours["billed_to_project" ] = sum([p.accounting.lost_time_bill_project for p in self.observed_periods])

        # how do the scheduled periods break down by type and this
        # and the previous month?
        self.scheduled_hours["astronomy"] = self.get_obs_time_tuple('p.session.project.project_type.type == "science"')
        self.scheduled_hours["maintenance"] = self.get_obs_time_tuple('p.session.project.pcode == "Maintenance"')
        # NOTE: is this the most robust way to determine if a project is a test or commisioning project?
        self.scheduled_hours["test_comm"] = self.get_obs_time_tuple('p.session.project.pcode[0] == "T"')
        self.scheduled_hours["shutdown"] = self.get_obs_time_tuple('p.session.project.pcode == "Shutdown"')

        # The distinction between 'backlog' and 'discharge' is that
        # 'backlog' is from only previous semesters, while discharge
        # inclues *all* semesters.
        # But they both only care about incomplete Astronomy projects
        self.backlog    = [p for p in Project.objects.all() \
            if p.semester in self.previousSemesters \
            and not p.complete \
            and p.get_category() == "Astronomy"] 
                       
        self.backlog_hours["total_time"] = sum([self.ta.getTimeLeft(p) for p in self.backlog])
        self.backlog_hours["years"] = {}
        for y in sorted(list(set([s.start().year for s in self.previousSemesters]))):
            projs = [p for p in self.backlog if p.semester.start().year == y]
            self.backlog_hours["years"]["%d" % y] = (sum([self.ta.getTimeLeft(p) for p in projs]), len(projs))
        self.backlog_hours["monitoring"] = sum([self.ta.getTimeLeft(p) for p in self.backlog \
                           if any([s.session_type.type == "windowed" \
                                   for s in p.sesshun_set.all()])])
        self.backlog_hours["vlbi"] = sum([self.ta.getTimeLeft(p) for p in self.backlog \
                           if any([s.observing_type.type == "vlbi" \
                                   for s in p.sesshun_set.all()])])                           

        self.discharge    = [p for p in Project.objects.all() \
            if not p.complete \
            and p.get_category() == "Astronomy"] 
          

        total_time = sum([self.ta.getTimeLeft(p) for p in self.discharge]) 
        monitoring = sum([self.ta.getTimeLeft(p) for p in self.discharge \
                           if any([s.session_type.type == "windowed" \
                                   for s in p.sesshun_set.all()]) and \
                              self.ta.getProjectTotalTime(p) <= 200.])
        vlbi       = sum([self.ta.getTimeLeft(p) for p in self.discharge \
                           if any([s.observing_type.type == "vlbi" \
                                   for s in p.sesshun_set.all()])])
        large      = sum([self.ta.getTimeLeft(p) for p in self.discharge \
                          if self.ta.getProjectTotalTime(p) > 200.])
        self.discharge_hours['total_time'] = total_time                  
        self.discharge_hours['monitoring'] = monitoring                  
        self.discharge_hours['vlbi']       = vlbi                  
        self.discharge_hours['large']      = large                  
        self.discharge_hours['rest']       = total_time - monitoring - vlbi - large


        self.nextWeekReservations = Reservation.objects.filter(
                                          end_date__gte = self.next_start
                                                       ).filter(
                                          start_date__lte = self.next_end)