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