pdbid:chain added
[django_unres.git] / django_simple / todo / forms.py
1 from django import forms
2 from .models import Task
3 from .models import MIN_CHOICE
4 from .models import MD_START
5 from .models import MD_LANG
6 from .models import FF_CHOICE
7 import json
8 import urllib
9
10 def pdb_code_chain(pdbid):
11
12     msg=''
13     chain=''
14     if len(pdbid)>4:
15        if pdbid[4]!=':':
16          return('use : between pdb code and chain id, like 5G3Q:B to select single chain')
17        chain=pdbid[5]
18        pdbid=pdbid[:4]    
19     
20     test=urllib.urlopen('http://files.rcsb.org/download/'+pdbid+'.pdb')     
21     if test.code != 200:
22           msg = 'wrong pdb code'
23     else:
24           msg=pdb_missing_res_chain(test,chain)
25     test.close()
26     return(msg)
27
28 def pdb_missing_res_chain(file,chain):
29    msg=''
30    newchain = True
31    ires=[]
32    for line in file:
33       if line[0:6] == 'ATOM  ' and line[13:15] == 'CA' and (line[21] == chain or chain==''):
34                i = int(line[22:26])
35                ch = line[21]
36                if ires and i==ires[-1]:
37                  continue
38                if newchain or i==ires[-1]+1:
39                  ires.append(i)
40                  newchain = False
41                else:
42                  msg = 'chain breaks between residues '+\
43                    str(ires[-1])+' and '+str(i)+' of chain '+ch+\
44                    ', server cannot add missing residues to PDB file - please repair the structure using e.g. Modeller'
45                  break
46       if line[0:3] == 'TER':
47                newchain = True
48       if line[0:3] == 'END':
49                break
50    
51    if len(ires) == 0:
52                msg='wrong chain id'
53    return(msg)
54
55
56 def code_2d(line):
57    msg=''
58    set ='HEC-'
59    line2 = ''.join([c for c in line if c in set])
60    if line2 != line:
61     msg='use only H,E,C or - letters'
62    return(msg)
63
64 def pdb_missing_res(file):
65    msg=''
66    newchain = True
67    ires=[]
68    for line in file:
69       if line[0:6] == 'ATOM  ' and line[13:15] == 'CA':
70                i = int(line[22:26])
71                if ires and i==ires[-1]:
72                  continue
73                if newchain or i==ires[-1]+1:
74                  ires.append(i)
75                  newchain = False
76                else:
77                  msg = 'chain breaks between residues '+\
78                    str(ires[-1])+' and '+str(i)+\
79                    ', server cannot add missing residues to PDB file - please repair the structure using e.g. Modeller'
80                  break
81       if line[0:3] == 'TER':
82                newchain = True
83       if line[0:3] == 'END':
84                break
85    
86    return(msg)
87
88 class MultiWidgetBasic(forms.MultiWidget):
89     def __init__(self, count, attrs=None):
90         self.count=count
91         widgets = []
92         for i in range(self.count):
93            widgets.append(forms.TextInput())
94         super(MultiWidgetBasic, self).__init__(widgets, attrs)
95
96     template_name = 'multi.html'
97
98     def decompress(self, value):
99         if value:
100             return json.loads(value)
101         else:
102             return ['', '']
103
104
105 class MultiExampleField(forms.fields.MultiValueField):
106     def __init__(self, count, *args, **kwargs):
107         self.count=count
108         self.widget = MultiWidgetBasic(self.count)
109         list_fields = []
110         for i in range(self.count):
111            list_fields.append(forms.fields.CharField(max_length=15))
112         super(MultiExampleField, self).__init__(list_fields, *args, **kwargs)
113
114     def compress(self, values):
115         ## compress list to single object                                               
116         return json.dumps(values)
117
118
119 class TaskForm(forms.Form):
120     name = forms.CharField(max_length=20)
121
122
123 class TaskForm_min(forms.Form):
124      name = forms.CharField(max_length=20)
125      file1 = forms.FileField(label='Upload a PDB file',required=False,
126       help_text='continuous (without breaks) protein chains,use TER to divide chains')
127      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
128       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
129       label='or PDB code (:chain)')                   
130
131      def clean(self):
132              cleaned_data = super(TaskForm_min, self).clean()
133
134              pdbid = cleaned_data.get("pdbid") 
135              file1 = cleaned_data.get("file1")
136               
137              if not pdbid and not file1:
138                 msg = 'provide pdb file or pdb code'
139                 self.add_error('file1', msg)
140               
141              if pdbid:
142                msg=pdb_code_chain(pdbid)
143                if msg != '':
144                    self.add_error('pdbid',msg)
145                
146              if file1:
147                  msg=pdb_missing_res(file1)
148                  if msg != '':
149                    self.add_error('file1',msg)
150
151             
152 class TaskForm_min_a(forms.Form):
153      name = forms.CharField(max_length=20)
154
155      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
156                            label='Force Field',initial='FF2')
157 #     min_choice = forms.ChoiceField(choices=MIN_CHOICE,label='minimization algorithm')
158      min_overlap = forms.BooleanField(required=False,label='remove overlap')
159      min_searchsc = forms.BooleanField(required=False,label='MC for sidechain overlap')
160      min_maxmin = forms.IntegerField(label='MAXMIN',initial=10000,
161                   help_text='maximum number of iterations')
162      min_maxfun = forms.IntegerField(label='MAXFUN',initial=15000,
163                   help_text='maximum number of function evaluations')
164      file1 = forms.FileField(label='Upload a PDB file',required=False,
165         help_text='continuous (without breaks) protein chains,use TER to divide chains')
166      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
167       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
168       label='or PDB code (:chain)')                   
169
170      min_unres_pdb = forms.BooleanField(required=False,label='uploaded input unres PDB',
171                   help_text='(CA and CB atoms only, CB represents SC in UNRES)')
172      min_pdbout = forms.BooleanField(required=False,label='output PDB',initial='true')
173      boxx = forms.FloatField(label='Box X',initial=1000.0,
174                        help_text='box x dimension')
175      boxy = forms.FloatField(label='Box Y',initial=1000.0,
176                        help_text='box y dimension')
177      boxz = forms.FloatField(label='Box Z',initial=1000.0,
178                        help_text='box z dimension')
179
180      def clean(self):
181              cleaned_data = super(TaskForm_min_a, self).clean()
182
183              pdbid = cleaned_data.get("pdbid") 
184              file1 = cleaned_data.get("file1")
185               
186              if not pdbid and not file1:
187                 msg = 'provide pdb file or pdb code'
188                 self.add_error('file1', msg)
189               
190              if pdbid:
191                  msg=pdb_code_chain(pdbid)
192                  if msg != '':
193                    self.add_error('pdbid',msg)
194                
195              if file1:
196                  msg=pdb_missing_res(file1)
197                  if msg != '':
198                    self.add_error('file1',msg)
199
200
201 class TaskForm_md(forms.Form):
202      name = forms.CharField(max_length=20)
203
204      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
205                       label='starting structure',initial='extconf')
206      md_seq = forms.CharField(label='Sequence',
207                      help_text='aminoacid sequence using one letter code<br>'+
208                      'field is ignored when uploading starting/reference PDB file',
209                      required=False,
210                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
211      file1 = forms.FileField(label='Upload a PDB file',required=False,
212                   help_text='starting structure for pdbstart/reference structure')
213      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
214       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
215       label='or PDB code (:chain)')                   
216      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')
217      md_temp = forms.FloatField(label='temperature',initial=300,
218                   help_text='bath temperature')
219      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
220                   help_text='total number of steps')
221      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
222                   help_text='seed for random number generator')
223                   
224      def clean(self):
225              cleaned_data = super(TaskForm_md, self).clean()
226
227              md_start = cleaned_data.get("md_start") 
228              file1 = cleaned_data.get("file1")
229              pdbid = cleaned_data.get("pdbid")
230              md_seq = cleaned_data.get("md_seq")
231              md_pdbref = cleaned_data.get("md_pdbref")
232               
233              if md_start == 'pdbstart' and not (file1 or pdbid):
234                 msg = 'pdbstart with no PDB file or code'
235                 self.add_error('file1', msg)
236
237              if md_pdbref and not (file1 or pdbid):
238                 msg = 'pdbref with no PDB file or code'
239                 self.add_error('file1', msg)
240
241
242              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
243                 msg = 'extended/random chain with no sequence'
244                 self.add_error('md_seq', msg)
245
246              if pdbid:
247                  msg=pdb_code_chain(pdbid)
248                  if msg != '':
249                    self.add_error('pdbid',msg)
250                
251              if file1:
252                  msg=pdb_missing_res(file1)
253                  if msg != '':
254                    self.add_error('file1',msg)
255
256                         
257 class TaskForm_md_a(forms.Form):
258      name = forms.CharField(max_length=20)
259
260      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
261                            label='Force Field',initial='FF2')
262      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
263                       label='starting structure',initial='extconf')
264      md_seq = forms.CharField(label='Sequence',
265                      help_text='aminoacid sequence using one letter code<br>'+
266                      'field is ignored when uploading starting/reference PDB file',
267                      required=False,
268                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
269      md_2d = forms.CharField(label='Secondary structure restraints',
270                      help_text='single letter code: H - helix, E - extended/beta, C or - no restraints',
271                      required=False,
272                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
273
274      file1 = forms.FileField(label='Upload a PDB file',required=False,
275                   help_text='starting structure for pdbstart/reference structure')
276      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
277       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
278       label='or PDB code (:chain)')                   
279      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
280      md_temp = forms.FloatField(label='temperature',initial=300,
281                   help_text='bath temperature')
282      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
283                   help_text='total number of steps')
284      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
285                   help_text='seed for random number generator')
286
287      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
288                help_text='write statfile every ntwe steps')
289      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
290                help_text='write trajectory every ntwe steps')
291      md_dt = forms.FloatField(label='DT',initial=0.2,
292                   help_text='time step [mtu=48.9 fs]')
293      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
294      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
295                   help_text='coupling to the thermal bath (Berendsen)')
296      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
297                   help_text='scaling of the friction coefficients (Langevin)')
298      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
299      md_mdpdb = forms.BooleanField(required=False,label='trajectory as PDB')
300
301      boxx = forms.FloatField(label='Box X',initial=1000.0,
302                        help_text='box x dimension')
303      boxy = forms.FloatField(label='Box Y',initial=1000.0,
304                        help_text='box y dimension')
305      boxz = forms.FloatField(label='Box Z',initial=1000.0,
306                        help_text='box z dimension')
307
308      def clean(self):
309              cleaned_data = super(TaskForm_md_a, self).clean()
310
311              md_start = cleaned_data.get("md_start") 
312              file1 = cleaned_data.get("file1")
313              pdbid = cleaned_data.get("pdbid")
314              md_seq = cleaned_data.get("md_seq")
315              md_pdbref = cleaned_data.get("md_pdbref")
316              md_2d = cleaned_data.get("md_2d")
317               
318              if md_start == 'pdbstart' and not (file1 or pdbid):
319                 msg = 'pdbstart with no PDB file or code'
320                 self.add_error('file1', msg)
321
322              if md_pdbref and not (file1 or pdbid):
323                 msg = 'pdbref with no PDB file or code'
324                 self.add_error('file1', msg)
325
326
327              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
328                 msg = 'extended/random chain with no sequence'
329                 self.add_error('md_seq', msg)
330
331              if pdbid:
332                  msg=pdb_code_chain(pdbid)
333                  if msg != '':
334                    self.add_error('pdbid',msg)
335                
336              if file1:
337                  msg=pdb_missing_res(file1)
338                  if msg != '':
339                    self.add_error('file1',msg)
340              
341              if md_2d:
342                  msg=code_2d(md_2d)
343                  if msg != '':
344                    self.add_error('md_2d',msg)
345
346 class TaskForm_remd(forms.Form):
347      name = forms.CharField(max_length=20)
348
349      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
350                       label='starting structure',initial='extconf')
351      md_seq = forms.CharField(label='Sequence',
352                      help_text='aminoacid sequence using one letter code<br>'+
353                         'field is ignored when uploading starting/reference PDB file',
354                      required=False,
355                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
356      file1 = forms.FileField(label='Upload a PDB file',required=False,
357                   help_text='starting structure for pdbstart/reference structure')
358      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
359       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
360       label='or PDB code (:chain)')                   
361      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
362      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
363                   help_text='total number of steps')
364      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
365                   help_text='seed for random number generator')
366                   
367      def clean(self):
368              cleaned_data = super(TaskForm_remd, self).clean()
369
370              md_start = cleaned_data.get("md_start") 
371              file1 = cleaned_data.get("file1")
372              pdbid = cleaned_data.get("pdbid")
373              md_seq = cleaned_data.get("md_seq")
374              md_pdbref = cleaned_data.get("md_pdbref")
375               
376              if md_start == 'pdbstart' and not (file1 or pdbid):
377                 msg = 'pdbstart with no PDB file or code'
378                 self.add_error('file1', msg)
379
380              if md_pdbref and not (file1 or pdbid):
381                 msg = 'pdbref with no PDB file or code'
382                 self.add_error('file1', msg)
383
384              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
385                 msg = 'extended/random chain with no sequence'
386                 self.add_error('md_seq', msg)
387
388              if pdbid:
389                  msg=pdb_code_chain(pdbid)
390                  if msg != '':
391                    self.add_error('pdbid',msg)
392                
393              if file1:
394                  msg=pdb_missing_res(file1)
395                  if msg != '':
396                    self.add_error('file1',msg)
397
398                              
399 class TaskForm_remd_a(forms.Form):
400      name = forms.CharField(max_length=20)
401
402      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
403                            label='Force Field',initial='FF2')
404      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
405                       label='starting structure',initial='extconf')
406      md_seq = forms.CharField(label='Sequence',
407                      help_text='aminoacid sequence using one letter code<br>'+
408                       'field is ignored when uploading starting/reference PDB file',
409                      required=False,
410                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
411      md_2d = forms.CharField(label='Secondary structure restraints',
412                      help_text='single letter code: H - helix, E - extended/beta, C or - no restraints',
413                      required=False,
414                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
415      file1 = forms.FileField(label='Upload a PDB file',required=False,
416                   help_text='starting structure for pdbstart/reference structure')
417      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
418       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
419       label='or PDB code (:chain)')                   
420      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
421      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
422                   help_text='total number of steps')
423      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
424                   help_text='seed for random number generator')
425      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
426                help_text='write statfile every ntwe steps')
427      md_dt = forms.FloatField(label='DT',initial=0.2,
428                   help_text='time step [mtu = 48.9 fs]')
429      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
430      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
431                   help_text='coupling to the thermal bath (Berendsen)')
432      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
433                   help_text='scaling of the friction coefficients (Langevin)')
434      remd_nrep = forms.IntegerField(label='NREP',initial=8,
435                   help_text='number of replicas')
436      remd_nstex = forms.IntegerField(label='NSTEX',initial=1000,
437                   help_text='exchange and write trajectory every nstex steps')
438      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
439                help_text='write trajectory every ntwx steps')
440      remd_cluter_temp = forms.FloatField(label='TEMPER',
441                   help_text='temperature for cluster analysis',initial=280)                  
442 #     remd_traj1file = forms.BooleanField(required=False,label='single trajectory file',initial='true')
443 #     remd_rest1file = forms.BooleanField(required=False,label='single restart file',initial='true')
444
445      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
446
447      boxx = forms.FloatField(label='Box X',initial=1000.0,
448                        help_text='box x dimension')
449      boxy = forms.FloatField(label='Box Y',initial=1000.0,
450                        help_text='box y dimension')
451      boxz = forms.FloatField(label='Box Z',initial=1000.0,
452                        help_text='box z dimension')
453
454
455      wsaxs = forms.FloatField(label='SAXS weight',initial=100.0,
456                             help_text='weight for SAXS restraint term')
457      scal_rad = forms.FloatField(label='Scal_rad (SAXS)',initial=1.0,
458                             help_text='downscaling factor of residue radii used in SAXS restraints')
459      saxs_data = forms.CharField(label='P(r) SAXS data',
460                      help_text='distance distribution from SAXS, two columns: r and P(r)',
461                      required=False,
462                      widget=forms.Textarea(attrs={'cols': 25, 'rows': 20}))
463
464
465      def clean(self):
466              cleaned_data = super(TaskForm_remd_a, self).clean()
467
468              md_start = cleaned_data.get("md_start") 
469              file1 = cleaned_data.get("file1")
470              pdbid = cleaned_data.get("pdbid")
471              md_seq = cleaned_data.get("md_seq")
472              md_pdbref = cleaned_data.get("md_pdbref")
473              md_2d = cleaned_data.get("md_2d")
474               
475              if md_start == 'pdbstart' and not (file1 or pdbid):
476                 msg = 'pdbstart with no PDB file or code'
477                 self.add_error('file1', msg)
478
479              if md_pdbref and not (file1 or pdbid):
480                 msg = 'pdbref with no PDB file or code'
481                 self.add_error('file1', msg)
482
483
484              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
485                 msg = 'extended/random chain with no sequence'
486                 self.add_error('md_seq', msg)
487
488              if pdbid:
489                  msg=pdb_code_chain(pdbid)
490                  if msg != '':
491                    self.add_error('pdbid',msg)
492                
493              if file1:
494                  msg=pdb_missing_res(file1)
495                  if msg != '':
496                    self.add_error('file1',msg)
497
498              if md_2d:
499                  msg=code_2d(md_2d)
500                  if msg != '':
501                    self.add_error('md_2d',msg)
502
503
504
505 class TaskForm_list(forms.Form):
506     name = forms.CharField(max_length=20,disabled=True,required=False)
507     nrep = forms.IntegerField(disabled=True,required=False,label='NREP')
508
509     def __init__(self, count, *args, **kwargs):
510         super(TaskForm_list, self).__init__(*args, **kwargs)
511         self.count=count
512         self.fields['temperatures'] = MultiExampleField(self.count)
513         self.fields['multiplexing'] = MultiExampleField(self.count)        
514      
515
516