serialization fix for duplicate vars
[qcg-portal.git] / qcg / utils.py
1 # coding=utf-8
2
3 from functools import wraps
4
5 import os
6 import string
7 import random
8
9 from django.contrib.auth.decorators import login_required
10 from django.core.cache import caches
11 from django.core.paginator import Paginator
12 from django.utils.formats import date_format
13 from django.utils.timezone import localtime
14 from django.views.decorators.cache import cache_control
15 from pyqcg import QCG
16 from pyqcg.description import JobDescription
17
18 from filex.ftp import FTPOperation
19 from qcg import constants
20
21
22 from django.utils import encoding
23
24 resources_cache = caches['resources']
25
26
27 def get_attributes(obj, attrs):
28     return {name: getattr(obj, name) for name in attrs if getattr(obj, name) is not None}
29
30
31 def username_from_dn(dn):
32     _, username = dn.rsplit('=', 1)
33
34     return username
35
36
37 def try_parse_int(s, default=None, base=10):
38     try:
39         return int(s, base)
40     except (TypeError, ValueError):
41         return default
42
43
44 def paginator_context(request, objects, per_page=constants.PER_PAGE):
45     paginator = Paginator(objects, per_page)
46
47     page_num = try_parse_int(request.GET.get('page'), 1)
48     if not (1 <= page_num <= paginator.num_pages):
49         page_num = 1
50
51     pages_range = range(max(2, min(page_num - 2, paginator.num_pages - 4)),
52                         min(max(page_num + 2, 5), paginator.num_pages) + 1)
53
54     return {'page': paginator.page(page_num), 'num_pages': paginator.num_pages, 'pages_range': pages_range}
55
56
57 def localtime_str(datetime):
58     return date_format(localtime(datetime), 'DATETIME_FORMAT')
59
60
61 def random_id(size=8, chars=string.ascii_uppercase + string.digits):
62     return ''.join(random.choice(chars) for _ in range(size))
63
64
65 def chunks(seq, size):
66     return (seq[pos:pos + size] for pos in xrange(0, len(seq), size))
67
68 def generate_md_inputfile(params):
69     md_input = list()
70     # Opis pliku wyjsciowego
71     opis=params['note'][:80]
72     md_input.append(encoding.smart_str(opis, encoding='ascii', errors='ignore'))
73     # Dane kontrolne obliczen
74     md_input.append('SEED=-3059743 PDBREF ONE_LETTER MD EXTCONF RESCALE_MODE=2')
75     ctl_data='nstep='+str(params['nstep'])+' ntwe='+str(params['ntwe'])
76     ctl_data+=' ntwx='+str(params['ntwx'])+' dt='+str(params['dt'])+' damax='+str(params['damax'])+'lang=1 scal_fric=0.01'
77     md_input.append('{:<79}&'.format(ctl_data))
78     md_input.append('tau_bath=1.0 t_bath=300 reset_vel=0 respa ntime_split=1 maxtime_split=512 mdpdb')
79     # Paramatry pól siłowych
80     if params['force_field'] == 'GAB':
81         # Wagi pola GAB
82         md_input.append('WLONG=1.35279 WSCP=1.59304 WELEC=0.71534 WBOND=1.00000 WANG=1.13873            &')
83         md_input.append('WSCLOC=0.16258 WTOR=1.98599 WTORD=1.57069 WCORRH=0.42887 WCORR5=0.00000        &')
84         md_input.append('WCORR6=0.00000 WEL_LOC=0.16036 WTURN3=1.68722 WTURN4=0.66230 WTURN6=0.00000    &')
85         md_input.append('WVDWPP=0.11371 WHPB=1.00000                                                    &')
86         md_input.append('CUTOFF=7.00000 WCORR4=0.00000 WSCCOR=0.0')
87     else:
88         # Wagi pola E0LLY
89         md_input.append('WLONG=1.00000 WSCP=1.23315 WELEC=0.84476 WBOND=1.00000 WANG=0.62954            &')
90         md_input.append('WSCLOC=0.10554 WTOR=1.84316 WTORD=1.26571 WCORRH=0.19212 WCORR5=0.00000        &')
91         md_input.append('WCORR6=0.00000 WEL_LOC=0.37357 WTURN3=1.40323 WTURN4=0.64673 WTURN6=0.00000    &')
92         md_input.append('WVDWPP=0.23173 WHPB=1.00000 WSCCOR=0.0                                         &')
93         md_input.append('CUTOFF=7.00000 WCORR4=0.00000')
94     # Plik PDB    
95     md_input.append(params['pdb_file'].split('/')[-1])
96     # Sekwencja aminokwasów
97     md_input.append(len(params['sequence']))
98     seq_str=params['sequence']
99     while seq_str:
100         md_input.append(seq_str[:80])
101         seq_str=seq_str[80:]
102     md_input.append(' 0')
103     md_input.append(' 0')
104     
105     return md_input
106
107
108 def to_job_desc(params, proxy):
109     QCG.start()
110     desc = JobDescription()
111
112
113     direct_map = ('env_variables', 'executable', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs',
114                   'wall_time', 'memory', 'memory_per_slot', 'modules', 'input', 'stage_in', 'native', 'notify',
115                   'preprocess', 'postprocess', 'persistent')
116
117     for name in direct_map:
118         if params[name]:
119             setattr(desc, name, params[name])
120
121
122     if params['application']:
123         desc.set_application(*params['application'])
124         desc.stage_in += [params['master_file']]
125         desc.arguments.insert(0, os.path.basename(params['master_file']))
126     if params['script']:
127         ftp = FTPOperation(proxy)
128
129         ftp.mkdir(constants.QCG_DATA_URL, parents=True)
130         url = os.path.join(constants.QCG_DATA_URL, 'script.{}.sh'.format(random_id()))
131         ftp.put(url)
132
133         for chunk in chunks(params['script'], 4096):
134             ftp.stream.put(chunk)
135         ftp.stream.put(None)
136         ftp.wait()
137
138         desc.executable = url
139     if params['nodes']:
140         desc.set_nodes(*params['nodes'])
141     if params['reservation']:
142         desc.set_reservation(params['reservation'])
143     if params['watch_output']:
144         desc.set_watch_output(params['watch_output'], params['watch_output_pattern'])
145
146     przemytnik = [] 
147     kontrabanda =( (u'UNRESPORTAL_FORCEFIELD', 'force_field'), (u'UNRESPORTAL_SEQUENCE', 'sequence'),
148                 (u'UNRESPORTAL_PDBFILE','pdb_file'), (u'UNRESPORTAL_NSTEP','nstep'),
149                 (u'UNRESPORTAL_NTWE', 'ntwe'), (u'UNRESPORTAL_NTWX','ntwx'),
150                 (u'UNRESPORTAL_DT', 'dt'), (u'UNRESPORTAL_DAMAX', 'damax'))
151  
152     upvar=False
153     for p in params['env_variables']:
154         for k in kontrabanda:
155             if p[0]==k[0]:
156                 upvar=True 
157                 break
158         if not upvar:
159             przemytnik.append(p)
160         else:
161             upvar=False
162         
163     for k in kontrabanda:
164         if params[k[1]]:
165             przemytnik.append( [ k[0], params[k[1]] ] )
166
167     setattr(desc, 'env_variables', przemytnik)
168
169     # TODO monitoring
170     
171     return desc
172
173
174 def to_form_data(xml):
175     # prevent circular import errors
176     from forms import JobDescriptionForm
177
178     QCG.start()
179     desc = JobDescription()
180     desc.xml_description = xml
181
182     direct_map = ('env_variables', 'executable', 'arguments', 'note', 'grant', 'hosts', 'properties', 'queue', 'procs',
183                   'wall_time', 'modules', 'input', 'stage_in', 'native', 'persistent')
184
185     params = {}
186     for name in direct_map:
187         attr = getattr(desc, name)
188         if isinstance(attr, bool) or attr:
189             params[name] = attr
190
191     if desc.application is not None:
192         app_name, app_ver = desc.application
193         params['application'] = app_name if app_ver is None else app_name + '/' + app_name
194         stage_in = params['stage_in']
195         params['stage_in'], params['master_file'] = stage_in[:-1], stage_in[-1]
196         params['arguments'] = params['arguments'][1:]
197     if desc.nodes is not None:
198         params['nodes'] = ':'.join(map(str, desc.nodes))
199     if desc.reservation is not None:
200         res_id, res_type = desc.reservation
201         params['reservation'] = res_id
202     if desc.notify is not None:
203         params['notify_type'], params['notify_address'] = desc.notify.split(':')
204     if desc.watch_output is not None:
205         watch_output, params['watch_output_pattern'] = desc.watch_output
206         params['watch_output_type'], params['watch_output_address'] = watch_output.split(':')
207     if desc.preprocess is not None:
208         if desc.preprocess.startswith('gsiftp://'):
209             params['preprocess_type'] = JobDescriptionForm.Process.SCRIPT
210             params['preprocess_script'] = desc.preprocess
211         else:
212             params['preprocess_type'] = JobDescriptionForm.Process.CMD
213             params['preprocess_cmd'] = desc.preprocess
214     if desc.postprocess is not None:
215         if desc.postprocess.startswith('gsiftp://'):
216             params['postprocess_type'] = JobDescriptionForm.Process.SCRIPT
217             params['postprocess_script'] = desc.postprocess
218         else:
219             params['postprocess_type'] = JobDescriptionForm.Process.CMD
220             params['postprocess_cmd'] = desc.postprocess
221     if desc.memory:
222         params['memory'] = int(desc.memory)
223     if desc.memory_per_slot:
224         params['memory_per_slot'] = int(desc.memory_per_slot)
225
226     kontrabanda =( (u'UNRESPORTAL_FORCEFIELD', 'force_field'), (u'UNRESPORTAL_SEQUENCE', 'sequence'),
227                 (u'UNRESPORTAL_PDBFILE','pdb_file'), (u'UNRESPORTAL_NSTEP','nstep'),
228                 (u'UNRESPORTAL_NTWE', 'ntwe'), (u'UNRESPORTAL_NTWX','ntwx'),
229                 (u'UNRESPORTAL_DT', 'dt'), (u'UNRESPORTAL_DAMAX', 'damax'))
230
231     for item in desc.env_variables:
232         for k in kontrabanda:
233             if item[0] == k[0]:
234                 params[k[1]] = item[1]
235                 break
236         '''    
237         if item[0] == u'UNRESPORTAL_FORCEFIELD':
238             params['force_field'] = item[1]
239         if item[0] == u'UNRESPORTAL_SEQUENCE':
240             params['sequence'] = item[1]
241         if item[0] == u'UNRESPORTAL_PDBFILE':
242             params['pdb_file'] = item[1]
243         if item[0] == u'UNRESPORTAL_NSTEP':
244             params['nstep'] = item[1]
245         if item[0] == u'UNRESPORTAL_NTWE':
246             params['ntwe'] = item[1]
247         if item[0] == u'UNRESPORTAL_NTWX':
248             params['ntwx'] = item[1]
249         if item[0] == u'UNRESPORTAL_DT':
250             params['dt'] = item[1]
251         if item[0] == u'UNRESPORTAL_DAMAX':
252             params['damax'] = item[1]
253         '''
254     return params
255
256
257 def restricted(view):
258     return wraps(view)(cache_control(no_cache=True, must_revalidate=True, no_store=True)(login_required(view)))
259
260
261 def cached_resources(proxy):
262     hosts = resources_cache.get('hosts')
263     if hosts is None:
264         # prevent circular import errors
265         from qcg.service import fetch_resources
266
267         hosts, _, applications, modules = map(make_choices, fetch_resources(proxy))
268         resources_cache.set('hosts', hosts)
269         resources_cache.set('applications', applications)
270         resources_cache.set('modules', modules)
271     else:
272         applications = resources_cache.get('applications')
273         modules = resources_cache.get('modules')
274
275     return hosts, applications, modules
276
277
278 def make_choices(iterable):
279     return ((None, ''),) + tuple((item, item) for item in sorted(iterable))