61b9144134ae57ae0fb38c04296ab83d328d84ab
[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      remd_nrep = forms.IntegerField(label='NREP',initial=8,
426                   help_text='number of replicas')
427      remd_nstex = forms.IntegerField(label='NSTEX',initial=1000,
428                   help_text='exchange and write trajectory every nstex steps')
429      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
430                help_text='write trajectory every ntwx steps')
431      remd_cluter_temp = forms.FloatField(label='TEMPER',
432                   help_text='temperature for cluster analysis',initial=280)                  
433 #     remd_traj1file = forms.BooleanField(required=False,label='single trajectory file',initial='true')
434 #     remd_rest1file = forms.BooleanField(required=False,label='single restart file',initial='true')
435
436      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
437
438      boxx = forms.FloatField(label='Box X',initial=1000.0,
439                        help_text='box x dimension')
440      boxy = forms.FloatField(label='Box Y',initial=1000.0,
441                        help_text='box y dimension')
442      boxz = forms.FloatField(label='Box Z',initial=1000.0,
443                        help_text='box z dimension')
444
445
446      wsaxs = forms.FloatField(label='SAXS weight',initial=100.0,
447                             help_text='weight for SAXS restraint term')
448      scal_rad = forms.FloatField(label='Scal_rad (SAXS)',initial=1.0,
449                             help_text='downscaling factor of residue radii used in SAXS restraints')
450      saxs_data = forms.CharField(label='P(r) SAXS data',
451                      help_text='distance distribution from SAXS, two columns: r and P(r)',
452                      required=False,
453                      widget=forms.Textarea(attrs={'cols': 25, 'rows': 20}))
454
455
456      def clean(self):
457              cleaned_data = super(TaskForm_remd_a, self).clean()
458
459              md_start = cleaned_data.get("md_start") 
460              file1 = cleaned_data.get("file1")
461              pdbid = cleaned_data.get("pdbid")
462              md_seq = cleaned_data.get("md_seq")
463              md_pdbref = cleaned_data.get("md_pdbref")
464              md_2d = cleaned_data.get("md_2d")
465               
466              if md_start == 'pdbstart' and not (file1 or pdbid):
467                 msg = 'pdbstart with no PDB file or code'
468                 self.add_error('file1', msg)
469
470              if md_pdbref and not (file1 or pdbid):
471                 msg = 'pdbref with no PDB file or code'
472                 self.add_error('file1', msg)
473
474
475              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
476                 msg = 'extended/random chain with no sequence'
477                 self.add_error('md_seq', msg)
478
479              if pdbid:
480                  msg=pdb_code_chain(pdbid)
481                  if msg != '':
482                    self.add_error('pdbid',msg)
483                
484              if file1:
485                  msg=pdb_missing_res_chain(file1,'')
486                  if msg != '':
487                    self.add_error('file1',msg)
488
489              if md_2d:
490                  msg=code_2d(md_2d)
491                  if msg != '':
492                    self.add_error('md_2d',msg)
493
494
495
496 class TaskForm_list(forms.Form):
497     name = forms.CharField(max_length=20,disabled=True,required=False)
498     nrep = forms.IntegerField(disabled=True,required=False,label='NREP')
499
500     def __init__(self, count, *args, **kwargs):
501         super(TaskForm_list, self).__init__(*args, **kwargs)
502         self.count=count
503         self.fields['temperatures'] = MultiExampleField(self.count)
504         self.fields['multiplexing'] = MultiExampleField(self.count)        
505      
506
507