Blame view

src/scheduler/models.py 25.9 KB
7a1effdd   haribo   scheduler app cre...
1
from django.db import models
7a79e25b   haribo   Date: 19/05/2016
2
from pyrosapp.models import Schedule, Sequence, ScheduleHasSequences
06241f05   haribo   Class scheduler f...
3
4
from operator import attrgetter
from decimal import *
7a79e25b   haribo   Date: 19/05/2016
5
6
import time
from DateTime import DateTime
7a1effdd   haribo   scheduler app cre...
7

7a79e25b   haribo   Date: 19/05/2016
8
9
DEFAULT_PLAN_START = Decimal(2457485.250000)  # April 6th 2016, 18:00:00.0 UT
DEFAULT_PLAN_END = Decimal(2457485.916667)  # April 7th 2016, 10:00:00.0 UT
06241f05   haribo   Class scheduler f...
10

715fabb7   haribo   #3430 (100%)
11
12
13
14
PRECISION = Decimal(0.0000000001)

SIMULATION = False

7a79e25b   haribo   Date: 19/05/2016
15
16
17
MAX_OVERHEAD = 25
MAX_OVERHEAD_JD = Decimal(MAX_OVERHEAD / (24 * 60 * 60))

eecfb779   haribo   Date: 26/05/2016
18
19
20
REJECTED_QUOTA = "Insufficient quota"
REJECTED_ROOM = "Insufficient room for this sequence"

8e4ab234   haribo   #3485: Creation a...
21
22
23
'''
    Note : the following functions are necessary due to a too-high precision of Decimal objects
'''
7a79e25b   haribo   Date: 19/05/2016
24
25
26


def is_nearby_equal(a: Decimal, b: Decimal, precision: Decimal=PRECISION):
715fabb7   haribo   #3430 (100%)
27
28
29
30
31
32
    '''
        Compare the two decimal, according to the given precision
    '''
    return (True if abs(b - a) < PRECISION else False)


7a79e25b   haribo   Date: 19/05/2016
33
def is_nearby_sup_or_equal(a: Decimal, b: Decimal, precision: Decimal=PRECISION):
715fabb7   haribo   #3430 (100%)
34
35
36
37
38
39
40
41
    '''
        Compare the two decimal, according to the given precision
    '''
    if (a > b):
        return True
    return (True if abs(b - a) < PRECISION else False)


7a79e25b   haribo   Date: 19/05/2016
42
def is_nearby_less_or_equal(a: Decimal, b: Decimal, precision: Decimal=PRECISION):
715fabb7   haribo   #3430 (100%)
43
44
45
46
47
48
49
50
    '''
        Compare the two decimal, according to the given precision
    '''
    if (a < b):
        return True
    return (True if abs(b - a) < PRECISION else False)


06241f05   haribo   Class scheduler f...
51
52
53
54
55
class Interval:
    """
    Simple class that represents an interval of time
    Julian days should be used
    """
7a79e25b   haribo   Date: 19/05/2016
56

06241f05   haribo   Class scheduler f...
57
58
59
60
61
    def __init__(self, start, end):
        self._start = Decimal(start)
        self._end = Decimal(end)
        self.duration = Decimal(end - start)

06241f05   haribo   Class scheduler f...
62
    def __str__(self):
7a79e25b   haribo   Date: 19/05/2016
63
        print("[" + str(self.start) + " - " + str(self.end) + "]")
06241f05   haribo   Class scheduler f...
64

b87b6d9b   haribo   Finished tests fo...
65
66
67
    def _get_start(self):
        return self._start

06241f05   haribo   Class scheduler f...
68
69
    def _set_start(self, start):
        if start > self._end:
7a79e25b   haribo   Date: 19/05/2016
70
71
            raise ValueError(
                "Cannot set start (%d): must be lower than end (%d)" % (start, self._end))
06241f05   haribo   Class scheduler f...
72
73
        self._start = start
        self.duration = self._end - self._start
7a79e25b   haribo   Date: 19/05/2016
74

b87b6d9b   haribo   Finished tests fo...
75
76
77
    def _get_end(self):
        return self._end

06241f05   haribo   Class scheduler f...
78
79
    def _set_end(self, end):
        if end < self._start:
7a79e25b   haribo   Date: 19/05/2016
80
81
            raise ValueError(
                "Cannot set end (%d): must be bigger than start (%d)" % (end, self._start))
06241f05   haribo   Class scheduler f...
82
83
        self._end = end
        self.duration = self._end - self._start
7a79e25b   haribo   Date: 19/05/2016
84

b87b6d9b   haribo   Finished tests fo...
85
86
    start = property(fget=_get_start, fset=_set_start)
    end = property(fget=_get_end, fset=_set_end)
06241f05   haribo   Class scheduler f...
87

77816f10   haribo   Workflow implemen...
88

06241f05   haribo   Class scheduler f...
89
90
91
class Scheduler():
    """
   Role : create a planning for the following/current night
7a79e25b   haribo   Date: 19/05/2016
92
93
94

   Read in DB : Sequence, PyrosUser and parents
   Create in DB : Schedule
06241f05   haribo   Class scheduler f...
95
96
   Update in DB : Schedule, Sequence
   Delete in DB : None
7a79e25b   haribo   Date: 19/05/2016
97

06241f05   haribo   Class scheduler f...
98
99
   Entry point(s) :
           - make_schedule
715fabb7   haribo   #3430 (100%)
100
           - simulate_schedule
06241f05   haribo   Class scheduler f...
101
102
103
104
    """

    """
    TODO:
715fabb7   haribo   #3430 (100%)
105
106
107
108
        - définition de plan_start et plan_end
        - calcul de la priorité
        - calcul des quotas
        - définir l'attribut 'flag' de Schedule
06241f05   haribo   Class scheduler f...
109
        - remplissage des espaces libres
06241f05   haribo   Class scheduler f...
110
111
112
113

    """

    def __init__(self):
b87b6d9b   haribo   Finished tests fo...
114
        self.schedule = Schedule.objects.create()
06241f05   haribo   Class scheduler f...
115
        # TODO: quel est le "flag" dans le schedule ??
b87b6d9b   haribo   Finished tests fo...
116
        self.intervals = []
7a79e25b   haribo   Date: 19/05/2016
117
118
        self.max_overhead = MAX_OVERHEAD_JD

06241f05   haribo   Class scheduler f...
119
120
121
122
    def get_night_limits(self):
        '''
        determines and set plan_start and plan_end (beginning & end of the observation night)        
        '''
7a79e25b   haribo   Date: 19/05/2016
123
124
125
126
127
128

        # TODO: définir comment on calcule plan_start et plan_end (via quels
        # moyens)
        self.schedule.plan_start = DEFAULT_PLAN_START  # default value
        self.schedule.plan_end = DEFAULT_PLAN_END  # default value

77816f10   haribo   Workflow implemen...
129
130
131
132
133
134
    def set_night_limits(self, plan_start, plan_end):
        '''
        Sets given schedule start & end (in julian day)
        '''
        self.schedule.plan_start = Decimal(plan_start)
        self.schedule.plan_end = Decimal(plan_end)
7a79e25b   haribo   Date: 19/05/2016
135
136

    def make_schedule(self, first_schedule):
06241f05   haribo   Class scheduler f...
137
138
139
140
        '''
        ENTRY POINT

        Check all 'OBSERVABLE' sequences to create the most optimized planning for the following/current night
7a79e25b   haribo   Date: 19/05/2016
141

eecfb779   haribo   Date: 26/05/2016
142
        It is assumed that all sequences that MUST and CAN be analyse have the OBSERVABLE status        
7a79e25b   haribo   Date: 19/05/2016
143
144
145
146
147

        shs means 'ScheduleHasSequences'
        self.sequences is a list of tuples (sequence, shs)
        
        :returns : The new schedule
06241f05   haribo   Class scheduler f...
148
149
150
151
        
        :side-effect :
            - modify sequences status and dates in DB
        '''
7a79e25b   haribo   Date: 19/05/2016
152

715fabb7   haribo   #3430 (100%)
153
154
        global SIMULATION
        SIMULATION = False
7a79e25b   haribo   Date: 19/05/2016
155
156
157
158
159
160

        if first_schedule is False:
            self.copy_from_previous_schedule()
        else:
            self.schedule.plan_night_start = self.schedule.plan_start

06241f05   haribo   Class scheduler f...
161
        self.sequences = list(Sequence.objects.filter(status=Sequence.OBSERVABLE))
7a79e25b   haribo   Date: 19/05/2016
162
163
164
165
        shs_list = []
        for sequence in self.sequences:
            shs_list.append(ScheduleHasSequences(sequence=sequence, schedule=self.schedule))
        self.sequences = [(sequence, shs_list[index]) for index, sequence in enumerate(self.sequences)]
715fabb7   haribo   #3430 (100%)
166
        self.compute_schedule()
7a79e25b   haribo   Date: 19/05/2016
167
168
        self.save_schedule()
        return self.schedule
715fabb7   haribo   #3430 (100%)
169

7a79e25b   haribo   Date: 19/05/2016
170
    def copy_from_previous_schedule(self):
8e4ab234   haribo   #3485: Creation a...
171
        '''
7a79e25b   haribo   Date: 19/05/2016
172
173
174
175
176
177
            Copy needed information from the previous schedule :
                - gets the executed sequences from the previous schedule and copy them into the new schedule
                - gets plan_start and plan_end
                - computes new plan_restart

            shs means 'ScheduleHasSequences'
8e4ab234   haribo   #3485: Creation a...
178
        '''
8e4ab234   haribo   #3485: Creation a...
179

7a79e25b   haribo   Date: 19/05/2016
180
181
182
183
184
185
186
187
        previous_sched = Schedule.objects.order_by('-created')[1]
        previous_exc_seq = previous_sched.sequences.filter(status=Sequence.EXECUTED)
        for seq in previous_exc_seq:
            shs = seq.shs
            shs.pk = None
            shs.schedule = self.schedule
            if SIMULATION == False:
                shs.save()
8e4ab234   haribo   #3485: Creation a...
188

7a79e25b   haribo   Date: 19/05/2016
189
190
191
192
        self.schedule.plan_night_start = previous_sched.plan_night_start
        self.schedule.plan_end = previous_sched.plan_end

        ''' Schedule starts in MAX_OVERHEAD seconds '''
9774228b   haribo   Date: 22/06/2016
193
        self.schedule.plan_start = DateTime(time.time()).JulianDay() + self.max_overhead
8e4ab234   haribo   #3485: Creation a...
194

715fabb7   haribo   #3430 (100%)
195
196
197
    def simulate_schedule(self, sequences):
        '''
        ENTRY POINT - SIMULATION
7a79e25b   haribo   Date: 19/05/2016
198

715fabb7   haribo   #3430 (100%)
199
        Do the same as make_schedule but do not touch the DB
7a79e25b   haribo   Date: 19/05/2016
200

715fabb7   haribo   #3430 (100%)
201
202
203
204
205
        :type sequences : list of Sequence
        :param sequences : sequences to plan

        :returns : a tuple (Schedule, list of sequences)
        '''
7a79e25b   haribo   Date: 19/05/2016
206

715fabb7   haribo   #3430 (100%)
207
208
        global SIMULATION
        SIMULATION = True
7a79e25b   haribo   Date: 19/05/2016
209
210

        self.schedule.plan_night_start = self.schedule.plan_start
715fabb7   haribo   #3430 (100%)
211
        self.sequences = sequences
7a79e25b   haribo   Date: 19/05/2016
212
213
214
215
        shs_list = []
        for sequence in self.sequences:
            shs_list.append(ScheduleHasSequences(sequence=sequence, schedule=self.schedule))
        self.sequences = [(sequence, shs_list[index]) for index, sequence in enumerate(self.sequences)]
715fabb7   haribo   #3430 (100%)
216
217
        self.compute_schedule()
        return (self.schedule, self.sequences)
715fabb7   haribo   #3430 (100%)
218
219

    def compute_schedule(self):
7a79e25b   haribo   Date: 19/05/2016
220
221
        self.intervals.append(
            Interval(self.schedule.plan_start, self.schedule.plan_end))
b87b6d9b   haribo   Finished tests fo...
222
        self.check_sequences_validity()
06241f05   haribo   Class scheduler f...
223
224
225
226
        self.determine_priorities()
        self.remove_not_eligible_sequences()
        self.sort_by_jd2_and_priorities()
        self.organize_sequences()
b87b6d9b   haribo   Finished tests fo...
227

b87b6d9b   haribo   Finished tests fo...
228
229
230
    def check_sequences_validity(self):
        '''
        Checks come sequence attributes to validate their integrity
7a79e25b   haribo   Date: 19/05/2016
231

b87b6d9b   haribo   Finished tests fo...
232
233
234
235
        :side-effect :
            - remove invalid sequences from self.sequences
            - set INVALID status for invalid sequences in DB
        '''
7a79e25b   haribo   Date: 19/05/2016
236

b87b6d9b   haribo   Finished tests fo...
237
        ''' Note(1) '''
7a79e25b   haribo   Date: 19/05/2016
238
        for sequence, shs in list(self.sequences):
715fabb7   haribo   #3430 (100%)
239
            if sequence.jd1 < 0 or sequence.jd2 < 0 or is_nearby_less_or_equal(sequence.duration, 0) or sequence.jd2 - sequence.jd1 < sequence.duration:
7a79e25b   haribo   Date: 19/05/2016
240
                self.sequences.remove((sequence, shs))
b87b6d9b   haribo   Finished tests fo...
241
                sequence.status = Sequence.INVALID
715fabb7   haribo   #3430 (100%)
242
243
                if SIMULATION == False:
                    sequence.save()
7a79e25b   haribo   Date: 19/05/2016
244

06241f05   haribo   Class scheduler f...
245
246
247
248
    def determine_priorities(self):
        '''
        Computes sequences priority according to the user, the scientific program, ...        
        '''
7a79e25b   haribo   Date: 19/05/2016
249

06241f05   haribo   Class scheduler f...
250
251
        # TODO: définir comment on calcule la priorité
        pass
7a79e25b   haribo   Date: 19/05/2016
252

06241f05   haribo   Class scheduler f...
253
254
255
256
257
    def remove_not_eligible_sequences(self):
        '''
        Computes overlap between [jd1; jd2] and [plan_start; plan_end]
        Removes from self.sequences all the sequences that cannot be observed between plan_start and plan_end
        Set UNPLANNABLE sequences if jd2 < plan_start
7a79e25b   haribo   Date: 19/05/2016
258

06241f05   haribo   Class scheduler f...
259
260
261
        :side-effect :
            - remove unwanted sequences from self.sequences
        '''
7a79e25b   haribo   Date: 19/05/2016
262

715fabb7   haribo   #3430 (100%)
263
        ''' Note (1) '''
7a79e25b   haribo   Date: 19/05/2016
264
265
266
        for sequence, shs in list(self.sequences):
            overlap = min(self.schedule.plan_end, sequence.jd2) - \
                max(self.schedule.plan_start, sequence.jd1) - self.max_overhead
06241f05   haribo   Class scheduler f...
267
            if overlap < sequence.duration:
b87b6d9b   haribo   Finished tests fo...
268
                if sequence.jd1 < self.schedule.plan_start:
06241f05   haribo   Class scheduler f...
269
270
                    """ Note (2) """
                    sequence.status = Sequence.UNPLANNABLE
715fabb7   haribo   #3430 (100%)
271
272
                    if SIMULATION == False:
                        sequence.save()
7a79e25b   haribo   Date: 19/05/2016
273
                self.sequences.remove((sequence, shs))
06241f05   haribo   Class scheduler f...
274

06241f05   haribo   Class scheduler f...
275
276
277
278
    def sort_by_jd2_and_priorities(self):
        '''
        Sort by priority and jd2, priority being the main sorting parameter        
        '''
7a79e25b   haribo   Date: 19/05/2016
279
280
281

        self.sequences.sort(key=lambda x: x[0].jd2)
        self.sequences.sort(key=lambda x: x[0].priority)
06241f05   haribo   Class scheduler f...
282
283
284
285
286
287
288
289
290
291
292

    def organize_sequences(self):
        '''
        Main function of the Scheduler
        Arrange a maximum of observable sequences in the planning

        Algorithm (for each sequence) :
            - check quota (remove sequence from list if quota is too low)
            - select matching intervals
            - IF matching intervals => place sequence according to tPrefered
            - IF NO matching intervals => try to move other sequences to place this one
7a79e25b   haribo   Date: 19/05/2016
293

06241f05   haribo   Class scheduler f...
294
295
296
297
        :side-effect :
            - remove unwanted sequences from self.sequences
            - change status and dates of sequences in self.sequences (but not in DB yet)
        '''
7a79e25b   haribo   Date: 19/05/2016
298
299
300

        ''' Note (1) '''
        for sequence, shs in list(self.sequences):
06241f05   haribo   Class scheduler f...
301
302
            quota = self.determine_quota(sequence)
            if quota < sequence.duration:
eecfb779   haribo   Date: 26/05/2016
303
304
                shs.status = Sequence.REJECTED
                shs.desc = REJECTED_QUOTA
06241f05   haribo   Class scheduler f...
305
306
307
308
                continue

            matching_intervals = self.get_matching_intervals(sequence)
            if len(matching_intervals) > 0:
7a79e25b   haribo   Date: 19/05/2016
309
                self.place_sequence(sequence, shs, matching_intervals)
06241f05   haribo   Class scheduler f...
310
311
                sequence_placed = True
            else:
7a79e25b   haribo   Date: 19/05/2016
312
                sequence_placed = self.try_shifting_sequences(sequence, shs)
06241f05   haribo   Class scheduler f...
313
            if sequence_placed == True:
eecfb779   haribo   Date: 26/05/2016
314
                shs.status = Sequence.PENDING
06241f05   haribo   Class scheduler f...
315
                self.update_quota(sequence)
eecfb779   haribo   Date: 26/05/2016
316
317
318
            else:
                shs.status = Sequence.REJECTED
                shs.desc = REJECTED_ROOM
7a79e25b   haribo   Date: 19/05/2016
319
320

    def determine_quota(self, sequence: Sequence) -> float:
06241f05   haribo   Class scheduler f...
321
322
323
324
325
326
        '''
        Determines the quota (in minutes) according to the current planning duration and the quota of the user and scientific program associated

        :returns : The quota (float)
        '''
        # TODO: définir comment on calcule le quota
7a79e25b   haribo   Date: 19/05/2016
327
328
329
330

        return sequence.request.pyros_user.quota  # default value

    def get_matching_intervals(self, sequence: Sequence):
06241f05   haribo   Class scheduler f...
331
332
        '''
        Find the intervals where the sequence could be inserted
7a79e25b   haribo   Date: 19/05/2016
333

06241f05   haribo   Class scheduler f...
334
335
        :returns : list of matching Intervals
        '''
7a79e25b   haribo   Date: 19/05/2016
336

06241f05   haribo   Class scheduler f...
337
        matching_intervals = []
7a79e25b   haribo   Date: 19/05/2016
338

06241f05   haribo   Class scheduler f...
339
        for interval in self.intervals:
7a79e25b   haribo   Date: 19/05/2016
340
341
            overlap = min(sequence.jd2, interval.end) - \
                max(sequence.jd1, interval.start) - self.max_overhead
715fabb7   haribo   #3430 (100%)
342
            if overlap > sequence.duration or is_nearby_equal(overlap, sequence.duration):
06241f05   haribo   Class scheduler f...
343
                matching_intervals.append(interval)
7a79e25b   haribo   Date: 19/05/2016
344

06241f05   haribo   Class scheduler f...
345
        return matching_intervals
7a79e25b   haribo   Date: 19/05/2016
346
347

    def place_sequence(self, sequence: Sequence, shs: ScheduleHasSequences, matching_intervals):
06241f05   haribo   Class scheduler f...
348
349
        '''
        Place the sequence in the better interval, according to the t_prefered
7a79e25b   haribo   Date: 19/05/2016
350

06241f05   haribo   Class scheduler f...
351
352
353
354
355
356
357
        :type matching_intervals: list [Interval]
        :param matching_intervals: Intervals in which the sequence can be placed

        :side-effect :
            - changes self.intervals
            - change the sequence if it it placed
        '''
7a79e25b   haribo   Date: 19/05/2016
358

06241f05   haribo   Class scheduler f...
359
360
361
        if len(matching_intervals) == 0:
            raise ValueError("matching_intervals shall not be empty")

7a79e25b   haribo   Date: 19/05/2016
362
363
364
365
366
367
368
369
        prefered_interval = self.get_prefered_interval(
            sequence, matching_intervals)
        sequence_position_in_interval = self.get_sequence_position_in_interval(
            sequence, prefered_interval)
        self.insert_sequence_in_interval(
            sequence, shs, prefered_interval, sequence_position_in_interval)
        self.cut_interval(sequence, shs, prefered_interval)
        self.update_other_deltas(sequence, shs, prefered_interval)
06241f05   haribo   Class scheduler f...
370

7a79e25b   haribo   Date: 19/05/2016
371
    def get_prefered_interval(self, sequence: Sequence, matching_intervals) -> Interval:
06241f05   haribo   Class scheduler f...
372
        '''
b87b6d9b   haribo   Finished tests fo...
373
        Find the better interval, according to the t_prefered (get the nearest)
7a79e25b   haribo   Date: 19/05/2016
374

06241f05   haribo   Class scheduler f...
375
376
        :type matching_intervals: list [Interval]
        :param matching_intervals: Intervals in which the sequence can be placed
7a79e25b   haribo   Date: 19/05/2016
377

06241f05   haribo   Class scheduler f...
378
379
380
381
382
383
        :returns : An Interval that fits sequence.t_prefered at most
        '''

        if len(matching_intervals) == 0:
            raise ValueError("matching_intervals shall not be empty")

b87b6d9b   haribo   Finished tests fo...
384
        if sequence.t_prefered == 0 or len(matching_intervals) == 1:
06241f05   haribo   Class scheduler f...
385
386
387
            prefered_interval = matching_intervals[0]
        else:
            for index, interval in enumerate(matching_intervals):
715fabb7   haribo   #3430 (100%)
388
                if is_nearby_less_or_equal(interval.start, sequence.t_prefered) and is_nearby_less_or_equal(sequence.t_prefered, interval.end):
06241f05   haribo   Class scheduler f...
389
390
391
392
393
                    prefered_interval = interval
                    break
                elif sequence.t_prefered < interval.start:
                    if index == 0:
                        prefered_interval = interval
92039557   haribo   Minor fix : t_pre...
394
395
                    elif interval.start + self.max_overhead - sequence.t_prefered < sequence.t_prefered - matching_intervals[index - 1].end:
                        prefered_interval = interval
06241f05   haribo   Class scheduler f...
396
397
398
399
                    else:
                        prefered_interval = matching_intervals[index - 1]
                    break
        return prefered_interval
7a79e25b   haribo   Date: 19/05/2016
400
401

    def get_sequence_position_in_interval(self, sequence: Sequence, interval: Interval) -> str:
06241f05   haribo   Class scheduler f...
402
403
404
405
406
407
        '''
        Determines where the sequence will be inserted in the interval, regarding sequence.t_prefered

        :returns : A string in ["START", "END", "PREFERED"] describing where the sequence will be inserted in the interval
        '''

715fabb7   haribo   #3430 (100%)
408
409
        if is_nearby_less_or_equal(interval.start, sequence.t_prefered) and is_nearby_less_or_equal(sequence.t_prefered, interval.end):
            if is_nearby_less_or_equal(sequence.t_prefered - Decimal(0.5) * sequence.duration, interval.start):
06241f05   haribo   Class scheduler f...
410
                position_in_interval = "START"
715fabb7   haribo   #3430 (100%)
411
            elif is_nearby_sup_or_equal(sequence.t_prefered + Decimal(0.5) * sequence.duration, interval.end):
06241f05   haribo   Class scheduler f...
412
413
                position_in_interval = "END"
            else:
7a79e25b   haribo   Date: 19/05/2016
414
                position_in_interval = "PREFERED"
06241f05   haribo   Class scheduler f...
415
416
417
418
419
420
        else:
            if sequence.t_prefered < interval.start:
                position_in_interval = "START"
            else:
                position_in_interval = "END"
        return position_in_interval
06241f05   haribo   Class scheduler f...
421

7a79e25b   haribo   Date: 19/05/2016
422
    def insert_sequence_in_interval(self, sequence: Sequence, shs: ScheduleHasSequences, interval: Interval, position: str):
06241f05   haribo   Class scheduler f...
423
424
425
426
        '''
        Inserts the sequence in the interval:
            - sets sequence.tsp and sequence.tep
            - sets sequence.deltaTL and sequence.deltaTR
7a79e25b   haribo   Date: 19/05/2016
427

06241f05   haribo   Class scheduler f...
428
429
        :param interval: Interval in which the sequence will be inserted
        :param position: String describing where the sequence will be inserted in the interval
7a79e25b   haribo   Date: 19/05/2016
430

06241f05   haribo   Class scheduler f...
431
432
433
        :side-effect :
            - modify sequence attributes (tsp, tep, deltaTL, deltaTR)
        '''
7a79e25b   haribo   Date: 19/05/2016
434

06241f05   haribo   Class scheduler f...
435
        if position not in ["START", "END", "PREFERED"]:
7a79e25b   haribo   Date: 19/05/2016
436
437
438
            raise ValueError(
                "position must be either 'START', 'END' or 'PREFERED'")

06241f05   haribo   Class scheduler f...
439
        if position == "START":
7a79e25b   haribo   Date: 19/05/2016
440
441
442
443
444
445
            shs.tsp = max(
                interval.start + self.max_overhead, sequence.jd1)
            shs.tep = shs.tsp + sequence.duration
            shs.deltaTL = 0
            shs.deltaTR = min(
                interval.end, sequence.jd2) - shs.tep
06241f05   haribo   Class scheduler f...
446
        elif position == "END":
7a79e25b   haribo   Date: 19/05/2016
447
448
449
450
451
            shs.tep = min(interval.end, sequence.jd2)
            shs.tsp = shs.tep - sequence.duration
            shs.deltaTL = shs.tsp - \
                max(interval.start + self.max_overhead, sequence.jd1)
            shs.deltaTR = 0
06241f05