Rafal's code for NMR restraints
[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 from django.utils.safestring import mark_safe
8 #---v
9 from django.core.files import File
10 #---^
11 import json
12 import urllib
13
14 aa_3letter = [
15      'DPR','DLY','DAR','DHI','DAS','DGL','DSG','DGN','DSN','DTH',
16      'DAL','DTY','DTR','DVA','DLE','DIL','DPN','MED','DCY',
17      'CYS','MET','PHE','ILE','LEU','VAL','TRP','TYR','ALA','GLY','THR',
18      'SER','GLN','ASN','GLU','ASP','HIS','ARG','LYS','PRO',
19      'SME','AIB','ABU','DBZ']
20
21
22 def pdb_code_chain(pdbid):
23
24     msg=''
25     chain=''
26     if len(pdbid)>4:
27        if pdbid[4]!=':':
28          return('use : between pdb code and chain id, like 5G3Q:B to select single chain')
29        chain=pdbid[5]
30        pdbid=pdbid[:4]    
31     
32     test=urllib.urlopen('http://files.rcsb.org/download/'+pdbid+'.pdb')     
33     if test.code != 200:
34           msg = 'wrong pdb code'
35     else:
36           msg=pdb_missing_res_chain(test,chain)
37     test.close()
38     return(msg)
39
40 def pdb_missing_res_chain(file,chain):
41    msg=''
42    newchain = True
43    ires=[]
44    for line in file:
45       if line[0:6] == 'ATOM  ' and line[13:15] == 'CA' and (line[21] == chain or chain==''):
46                i = int(line[22:26])
47                ch = line[21]
48                if line[17:20] not in aa_3letter:
49                  msg='residue '+line[17:20]+' '+str(i)+' not recognized'
50                  return(msg)
51                if ires and i==ires[-1]:
52                  continue
53                if newchain or i==ires[-1]+1:
54                  ires.append(i)
55                  newchain = False
56                else:
57                  msg = 'chain breaks between residues '+\
58                    str(ires[-1])+' and '+str(i)+' of chain '+ch+\
59                    ', server cannot add missing residues to PDB file - please repair the structure using e.g. Modeller'
60                  break
61       if line[0:3] == 'TER':
62                newchain = True
63       if line[0:3] == 'END':
64                break
65    
66    if len(ires) == 0:
67         if chain == '':
68                msg='no CA atoms in this pdb'
69         else:
70                msg='wrong chain id'
71    return(msg)
72
73 #---v
74 def nmr_bad_cols(file):
75   msg=''
76   for line in file:
77     line=line.rstrip()
78     if line:
79       data = line.split()
80       for x in (0, 1, 2):
81         lg = data[x].isdigit()
82         if not lg:
83           msg = 'NMR shifts data column '+repr(x+1)+' must be integer, not: '+data[x]
84           return(msg)
85       dlug = len(data)
86       if (dlug < 5):
87         msg = 'There have to be 5 or more columns in NMR shifts data file'
88         return(msg)
89       promien = data[3].replace('.', '')
90       lg2 = promien.isdigit()
91       if not lg2:
92           msg ='NMR shifts 4th data column must be decimal or integer radius, not: '+data[3]
93           return(msg)
94       lg3 = data[4].startswith('H') or data[4].startswith('Q')
95       if not lg3:
96         msg = 'NMR shifts 5th data column must be proton designation, not: '+data[4]
97         return(msg)
98     else:
99       msg = 'NMR shifts data contains blank lines. Remove them.'
100   return(msg)
101 #---^
102
103
104 def code_2d(line):
105    msg=''
106    set ='HEC-'
107    line2 = ''.join([c for c in line if c in set])
108    if line2 != line:
109     msg='use only H,E,C or - letters'
110    return(msg)
111
112
113 class MultiWidgetBasic(forms.MultiWidget):
114     def __init__(self, count, attrs=None):
115         self.count=count
116         widgets = []
117         for i in range(self.count):
118            widgets.append(forms.TextInput())
119         super(MultiWidgetBasic, self).__init__(widgets, attrs)
120
121     template_name = 'multi.html'
122
123     def decompress(self, value):
124         if value:
125             return json.loads(value)
126         else:
127             return ['', '']
128
129
130 class MultiExampleField(forms.fields.MultiValueField):
131     def __init__(self, count, *args, **kwargs):
132         self.count=count
133         self.widget = MultiWidgetBasic(self.count)
134         list_fields = []
135         for i in range(self.count):
136            list_fields.append(forms.fields.CharField(max_length=15))
137         super(MultiExampleField, self).__init__(list_fields, *args, **kwargs)
138
139     def compress(self, values):
140         ## compress list to single object                                               
141         return json.dumps(values)
142
143
144 class TaskForm(forms.Form):
145     name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
146
147
148 class TaskForm_min(forms.Form):
149      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
150      file1 = forms.FileField(label='Upload a PDB file',required=False,
151       help_text='continuous (without breaks) protein chains,use TER to divide chains')
152      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
153       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
154       label='or PDB code (:chain)')                   
155
156      def clean(self):
157              cleaned_data = super(TaskForm_min, self).clean()
158
159              pdbid = cleaned_data.get("pdbid") 
160              file1 = cleaned_data.get("file1")
161               
162              if not pdbid and not file1:
163                 msg = 'provide pdb file or pdb code'
164                 self.add_error('file1', msg)
165               
166              if pdbid:
167                msg=pdb_code_chain(pdbid)
168                if msg != '':
169                    self.add_error('pdbid',msg)
170                
171              if file1:
172                  msg=pdb_missing_res_chain(file1,'')
173                  if msg != '':
174                    self.add_error('file1',msg)
175
176             
177 class TaskForm_min_a(forms.Form):
178      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
179
180      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
181                            label='Force Field',initial='FF2')
182 #     min_choice = forms.ChoiceField(choices=MIN_CHOICE,label='minimization algorithm')
183      min_overlap = forms.BooleanField(required=False,label='remove overlap')
184      min_searchsc = forms.BooleanField(required=False,label='MC for sidechain overlap')
185      min_maxmin = forms.IntegerField(label='MAXMIN',initial=10000,
186                   help_text='maximum number of iterations')
187      min_maxfun = forms.IntegerField(label='MAXFUN',initial=15000,
188                   help_text='maximum number of function evaluations')
189      file1 = forms.FileField(label='Upload a PDB file',required=False,
190         help_text='continuous (without breaks) protein chains,use TER to divide chains')
191      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
192       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
193       label='or PDB code (:chain)')                   
194
195      min_unres_pdb = forms.BooleanField(required=False,label='uploaded input unres PDB',
196                   help_text='(CA and CB atoms only, CB represents SC in UNRES)')
197      min_pdbout = forms.BooleanField(required=False,label='output PDB',initial='true')
198      boxx = forms.FloatField(label='Box X',initial=1000.0,
199                        help_text='box x dimension')
200      boxy = forms.FloatField(label='Box Y',initial=1000.0,
201                        help_text='box y dimension')
202      boxz = forms.FloatField(label='Box Z',initial=1000.0,
203                        help_text='box z dimension')
204
205      def clean(self):
206              cleaned_data = super(TaskForm_min_a, self).clean()
207
208              pdbid = cleaned_data.get("pdbid") 
209              file1 = cleaned_data.get("file1")
210               
211              if not pdbid and not file1:
212                 msg = 'provide pdb file or pdb code'
213                 self.add_error('file1', msg)
214               
215              if pdbid:
216                  msg=pdb_code_chain(pdbid)
217                  if msg != '':
218                    self.add_error('pdbid',msg)
219                
220              if file1:
221                  msg=pdb_missing_res_chain(file1,'')
222                  if msg != '':
223                    self.add_error('file1',msg)
224
225
226 class TaskForm_md(forms.Form):
227      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
228
229      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
230                       label='starting structure',initial='extconf')
231      md_seq = forms.CharField(label='Sequence',
232                      help_text='aminoacid sequence using one letter code<br>'+
233                      'field is ignored when uploading starting/reference PDB file',
234                      required=False,
235                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
236      file1 = forms.FileField(label='Upload a PDB file',required=False,
237                   help_text='starting structure for pdbstart/reference structure')
238      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
239       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
240       label='or PDB code (:chain)')                   
241      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')
242      md_temp = forms.FloatField(label='temperature',initial=300,
243                   help_text='bath temperature')
244      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
245                   help_text='total number of steps',max_value=10000000)
246      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
247                   help_text='seed for random number generator')
248                   
249      def clean(self):
250              cleaned_data = super(TaskForm_md, self).clean()
251
252              md_start = cleaned_data.get("md_start") 
253              file1 = cleaned_data.get("file1")
254              pdbid = cleaned_data.get("pdbid")
255              md_seq = cleaned_data.get("md_seq")
256              md_pdbref = cleaned_data.get("md_pdbref")
257               
258              if md_start == 'pdbstart' and not (file1 or pdbid):
259                 msg = 'pdbstart with no PDB file or code'
260                 self.add_error('file1', msg)
261
262              if md_pdbref and not (file1 or pdbid):
263                 msg = 'pdbref with no PDB file or code'
264                 self.add_error('file1', msg)
265
266
267              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
268                 msg = 'extended/random chain with no sequence'
269                 self.add_error('md_seq', msg)
270
271              if pdbid:
272                  msg=pdb_code_chain(pdbid)
273                  if msg != '':
274                    self.add_error('pdbid',msg)
275                
276              if file1:
277                  msg=pdb_missing_res_chain(file1,'')
278                  if msg != '':
279                    self.add_error('file1',msg)
280
281                         
282 class TaskForm_md_a(forms.Form):
283      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
284
285      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
286                            label='Force Field',initial='FF2')
287      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
288                       label='starting structure',initial='extconf')
289      md_seq = forms.CharField(label='Sequence',
290                      help_text='aminoacid sequence using one letter code<br>'+
291                      'field is ignored when uploading starting/reference PDB file',
292                      required=False,
293                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
294      md_2d = forms.CharField(label='Secondary structure restraints',
295                      help_text='single letter code: H helix, E extended/beta, C or - no restraints',
296                      required=False,
297                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
298
299 #---v
300      use_nmr = forms.BooleanField(required=False,label='use NMR restraints',
301                   help_text='this option requires the next four fields to be set.')
302      file3 = forms.FileField(label='Upload a NMR restraints file',required=False,
303                   help_text='at least 5 columns required:     49      22      1       5.0     HD2     H; <i>Hint: if you are using <u>NMR example data</u> then the field will be filled out automatically</i>')
304      nmr_scal = forms.IntegerField(label='NMR option: scal_peak',initial=20)
305      nmr_fordepth = forms.FloatField(label='NMR option: FORDEPTH_PEAK',initial=0.5)
306      nmr_slope = forms.FloatField(label='NMR option: SLOPE_PEAK',initial=0.05)
307      file1 = forms.FileField(label='Upload a PDB file',required=False,
308                   help_text='starting structure for pdbstart/reference structure; <i>Hint: if you are using <u>NMR example data</u> then the field will be filled out automatically</i>')
309 #---^
310      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
311       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
312       label='or PDB code (:chain)')                   
313      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
314      md_temp = forms.FloatField(label='temperature',initial=300,
315                   help_text='bath temperature')
316      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
317                   help_text='total number of steps',max_value=10000000)
318      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
319                   help_text='seed for random number generator')
320
321      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
322                help_text='write statfile every ntwe steps')
323      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,
324                help_text='write trajectory every ntwe steps',min_value=100)
325      md_dt = forms.FloatField(label='DT',initial=0.2,
326                   help_text='time step [mtu=48.9 fs]')
327      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
328      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
329                   help_text='coupling to the thermal bath (Berendsen)')
330      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
331                   help_text='scaling of the friction coefficients (Langevin)')
332      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
333      md_mdpdb = forms.BooleanField(required=False,label='trajectory as PDB')
334
335      boxx = forms.FloatField(label='Box X',initial=1000.0,
336                        help_text='box x dimension')
337      boxy = forms.FloatField(label='Box Y',initial=1000.0,
338                        help_text='box y dimension')
339      boxz = forms.FloatField(label='Box Z',initial=1000.0,
340                        help_text='box z dimension')
341
342      def clean(self):
343              cleaned_data = super(TaskForm_md_a, self).clean()
344
345 #---v
346              md_seq = cleaned_data.get("md_seq")
347              if (md_seq == 'TDELLERLRQLFEELHERGTEIVVEVHINGERDEIRVRNISKEELKKLLERIREKIEREGSSEVEVNVHSGGQTWTFNEK'):
348                reopn1 = open('files/6msp-from-THR.pdb', 'r')
349                file1 = File(reopn1)
350              else:
351 #---^
352                file1 = cleaned_data.get("file1")
353              md_start = cleaned_data.get("md_start") 
354              pdbid = cleaned_data.get("pdbid")
355              md_seq = cleaned_data.get("md_seq")
356              md_pdbref = cleaned_data.get("md_pdbref")
357              md_2d = cleaned_data.get("md_2d")
358               
359 #---v
360              if (md_seq == 'TDELLERLRQLFEELHERGTEIVVEVHINGERDEIRVRNISKEELKKLLERIREKIEREGSSEVEVNVHSGGQTWTFNEK'):
361                reopn = open('files/N1008_AmbiR-trunc.txt', 'r')
362                file3 = File(reopn)
363              else:
364                file3 = cleaned_data.get("file3")
365              unres_ff = cleaned_data.get("unres_ff")
366              use_nmr = cleaned_data.get("use_nmr")
367              nmr_scal = cleaned_data.get("nmr_scal")
368              nmr_fordepth = cleaned_data.get("nmr_fordepth")
369              nmr_slope = cleaned_data.get("nmr_slope")
370              if (use_nmr and file3):
371                msg=nmr_bad_cols(file3)
372                if msg != '':
373                  self.add_error('file3',msg)
374              else:
375                if (use_nmr and not file3):
376                  self.add_error('file3','"Use NMR restarints" and "Upload a NMR restr. file" must be used together')
377
378              if (use_nmr and (unres_ff != 'NEWCT-9P')):
379                self.add_error('unres_ff','"Use NMR restarints" requires NEWCT-9P force field')
380
381 #---^
382              if md_start == 'pdbstart' and not (file1 or pdbid):
383                 msg = 'pdbstart with no PDB file or code'
384                 self.add_error('file1', msg)
385
386              if md_pdbref and not (file1 or pdbid):
387                 msg = 'pdbref with no PDB file or code'
388                 self.add_error('file1', msg)
389
390
391              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
392                 msg = 'extended/random chain with no sequence'
393                 self.add_error('md_seq', msg)
394
395              if pdbid:
396                  msg=pdb_code_chain(pdbid)
397                  if msg != '':
398                    self.add_error('pdbid',msg)
399                
400              if file1:
401                  msg=pdb_missing_res_chain(file1,'')
402                  if msg != '':
403                    self.add_error('file1',msg)
404              
405              if md_2d:
406                  msg=code_2d(md_2d)
407                  if msg != '':
408                    self.add_error('md_2d',msg)
409
410 class TaskForm_remd(forms.Form):
411      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
412
413      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
414                       label='starting structure',initial='extconf')
415      md_seq = forms.CharField(label='Sequence',
416                      help_text='aminoacid sequence using one letter code<br>'+
417                         'field is ignored when uploading starting/reference PDB file',
418                      required=False,
419                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
420      file1 = forms.FileField(label='Upload a PDB file',required=False,
421                   help_text='starting structure for pdbstart/reference structure')
422      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
423       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
424       label='or PDB code (:chain)')                   
425      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
426      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
427                   help_text='total number of steps',max_value=10000000)
428      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
429                   help_text='seed for random number generator')
430                   
431      def clean(self):
432              cleaned_data = super(TaskForm_remd, self).clean()
433
434              md_start = cleaned_data.get("md_start") 
435              file1 = cleaned_data.get("file1")
436              pdbid = cleaned_data.get("pdbid")
437              md_seq = cleaned_data.get("md_seq")
438              md_pdbref = cleaned_data.get("md_pdbref")
439               
440              if md_start == 'pdbstart' and not (file1 or pdbid):
441                 msg = 'pdbstart with no PDB file or code'
442                 self.add_error('file1', msg)
443
444              if md_pdbref and not (file1 or pdbid):
445                 msg = 'pdbref with no PDB file or code'
446                 self.add_error('file1', msg)
447
448              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
449                 msg = 'extended/random chain with no sequence'
450                 self.add_error('md_seq', msg)
451
452              if pdbid:
453                  msg=pdb_code_chain(pdbid)
454                  if msg != '':
455                    self.add_error('pdbid',msg)
456                
457              if file1:
458                  msg=pdb_missing_res_chain(file1,'')
459                  if msg != '':
460                    self.add_error('file1',msg)
461
462                              
463 class TaskForm_remd_a(forms.Form):
464      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
465
466      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
467                            label='Force Field',initial='FF2')
468      md_start = forms.ChoiceField(choices=MD_START,widget=forms.RadioSelect,
469                       label='starting structure',initial='extconf')
470      md_seq = forms.CharField(label='Sequence',
471                      help_text='aminoacid sequence using one letter code<br>'+
472                       'field is ignored when uploading starting/reference PDB file',
473                      required=False,
474                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
475      md_2d = forms.CharField(label='Secondary structure restraints',
476                      help_text='single letter code: H helix, E extended/beta, C or - no restraints',
477                      required=False,
478                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
479 #---v
480      use_nmr = forms.BooleanField(required=False,label='use NMR restraints',
481                   help_text='this option requires the next four fields to be set.')
482      file3 = forms.FileField(label='Upload a NMR restraints file',required=False,
483        help_text='at least 5 columns required:     49      22      1       5.0     HD2     H; <i>Hint: if you are using <u>NMR example data</u> then the field will be filled out automatically</i>')
484      nmr_scal = forms.IntegerField(label='NMR option: scal_peak',initial=20)
485      nmr_fordepth = forms.FloatField(label='NMR option: FORDEPTH_PEAK',initial=0.5)
486      nmr_slope = forms.FloatField(label='NMR option: SLOPE_PEAK',initial=0.05)
487 #---^
488      file1 = forms.FileField(label='Upload a PDB file',required=False,
489                   help_text='starting structure for pdbstart/reference structure; <i>Hint: if you are using <u>NMR example data</u> then the field will be filled out automatically</i>')
490      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
491       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
492       label='or PDB code (:chain)')                   
493      md_pdbref = forms.BooleanField(required=False,label='PDB reference structure')                  
494      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
495                   help_text='total number of steps',max_value=10000000)
496      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
497                   help_text='seed for random number generator')
498      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
499                help_text='write statfile every ntwe steps')
500      md_dt = forms.FloatField(label='DT',initial=0.2,
501                   help_text='time step [mtu = 48.9 fs]')
502      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
503      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
504                   help_text='coupling to the thermal bath (Berendsen)')
505      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
506                   help_text='scaling of the friction coefficients (Langevin)')
507      min_maxfun = forms.IntegerField(label='MAXFUN',initial=5000,
508                   help_text='preminim maximum number of function evaluations<br>'+
509                   'used for start from pdb or random start')
510      remd_nrep = forms.IntegerField(label='NREP',initial=8,
511                   help_text='number of temperatures')
512      remd_nstex = forms.IntegerField(label='NSTEX',initial=1000,
513                   help_text='exchange and write trajectory every nstex steps')
514      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,min_value=100,
515                help_text='write trajectory every ntwx steps')
516      remd_cluter_temp = forms.FloatField(label='TEMPER',
517                   help_text='temperature for cluster analysis',initial=280)                  
518 #     remd_traj1file = forms.BooleanField(required=False,label='single trajectory file',initial='true')
519 #     remd_rest1file = forms.BooleanField(required=False,label='single restart file',initial='true')
520
521      md_respa = forms.BooleanField(required=False,initial=True,label='RESPA')
522
523      boxx = forms.FloatField(label='Box X',initial=1000.0,
524                        help_text='box x dimension')
525      boxy = forms.FloatField(label='Box Y',initial=1000.0,
526                        help_text='box y dimension')
527      boxz = forms.FloatField(label='Box Z',initial=1000.0,
528                        help_text='box z dimension')
529
530
531      wsaxs = forms.FloatField(label='SAXS weight',initial=100.0,
532                             help_text='weight for SAXS restraint term')
533      scal_rad = forms.FloatField(label='Scal_rad (SAXS)',initial=1.0,
534                             help_text='downscaling factor of residue radii used in SAXS restraints')
535      saxs_data = forms.CharField(label='P(r) SAXS data',
536                      help_text='distance distribution from SAXS, two columns: r and P(r)',
537                      required=False,
538                      widget=forms.Textarea(attrs={'cols': 25, 'rows': 20}))
539
540
541      def clean(self):
542              cleaned_data = super(TaskForm_remd_a, self).clean()
543
544              md_start = cleaned_data.get("md_start") 
545 #---v
546              md_seq = cleaned_data.get("md_seq")
547              if (md_seq == 'TDELLERLRQLFEELHERGTEIVVEVHINGERDEIRVRNISKEELKKLLERIREKIEREGSSEVEVNVHSGGQTWTFNEK'):
548                reopn1 = open('files/6msp-from-THR.pdb', 'r')
549                file1 = File(reopn1)
550              else:
551                file1 = cleaned_data.get("file1")
552 #---^
553              pdbid = cleaned_data.get("pdbid")
554              md_pdbref = cleaned_data.get("md_pdbref")
555              md_2d = cleaned_data.get("md_2d")
556 #---v
557              if (md_seq == 'TDELLERLRQLFEELHERGTEIVVEVHINGERDEIRVRNISKEELKKLLERIREKIEREGSSEVEVNVHSGGQTWTFNEK'):
558                reopn = open('files/N1008_AmbiR-trunc.txt', 'r')
559                file3 = File(reopn)
560              else:
561                file3 = cleaned_data.get("file3")
562              unres_ff = cleaned_data.get("unres_ff")
563              use_nmr = cleaned_data.get("use_nmr")
564              nmr_scal = cleaned_data.get("nmr_scal")
565              nmr_fordepth = cleaned_data.get("nmr_fordepth")
566              nmr_slope = cleaned_data.get("nmr_slope")
567              if (use_nmr and file3):
568                msg=nmr_bad_cols(file3)
569                if msg != '':
570                  self.add_error('file3',msg)
571              else:
572                if (use_nmr and not file3):
573                  self.add_error('file3','"Use NMR restarints" and "Upload a NMR restr. file" must be used together')
574
575              if (use_nmr and (unres_ff != 'NEWCT-9P')):
576                self.add_error('unres_ff','"Use NMR restarints" requires NEWCT-9P force field')
577
578 #---^
579              if md_start == 'pdbstart' and not (file1 or pdbid):
580                 msg = 'pdbstart with no PDB file or code'
581                 self.add_error('file1', msg)
582
583              if md_pdbref and not (file1 or pdbid):
584                 msg = 'pdbref with no PDB file or code'
585                 self.add_error('file1', msg)
586
587
588              if md_start != 'pdbstart' and not md_pdbref and not md_seq:
589                 msg = 'extended/random chain with no sequence'
590                 self.add_error('md_seq', msg)
591
592              if pdbid:
593                  msg=pdb_code_chain(pdbid)
594                  if msg != '':
595                    self.add_error('pdbid',msg)
596                
597              if file1:
598                  msg=pdb_missing_res_chain(file1,'')
599                  if msg != '':
600                    self.add_error('file1',msg)
601
602              if md_2d:
603                  msg=code_2d(md_2d)
604                  if msg != '':
605                    self.add_error('md_2d',msg)
606
607
608 class TaskForm_dock(forms.Form):
609      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
610
611      file1 = forms.FileField(label='Upload a PDB file1',required=False,
612                   help_text='starting structure for chain1')
613      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
614       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
615       label='or PDB code (:chain)')                   
616
617
618      md_seq = forms.CharField(label=mark_safe('Sequence of chain2 <br /> for dock peptide'),
619                      help_text='aminoacid sequence using one letter code<br>'+
620                         'field is ignored when uploading PDB file2',
621                      required=False,
622                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
623
624
625      file2 = forms.FileField(label='Upload a PDB file2',required=False,
626                   help_text='starting structure for chain2')
627      pdbid2 = forms.CharField(min_length=4,max_length=6,required=False,
628       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
629       label='or PDB code (:chain)')                   
630
631
632      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
633                   help_text='total number of steps', max_value=10000000)
634      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
635                   help_text='seed for random number generator')
636      dock_peptide = forms.BooleanField(required=False,initial=False,
637             label='dock peptide',help_text='no constraints on chain2')                  
638                   
639      def clean(self):
640              cleaned_data = super(TaskForm_dock, self).clean()
641
642              file1 = cleaned_data.get("file1")
643              pdbid = cleaned_data.get("pdbid")
644              file2 = cleaned_data.get("file2")
645              pdbid2 = cleaned_data.get("pdbid2")
646              md_seq = cleaned_data.get("md_seq")
647
648               
649              if not (file1 or pdbid):
650                 msg = 'no PDB file or code for chain1'
651                 self.add_error('file1', msg)
652
653              if not (file2 or pdbid2 or md_seq):
654                 msg = 'no PDB file or code or sequence for chain2'
655                 self.add_error('file2', msg)
656
657              if pdbid:
658                  msg=pdb_code_chain(pdbid)
659                  if msg != '':
660                    self.add_error('pdbid',msg)
661                
662              if file1:
663                  msg=pdb_missing_res_chain(file1,'')
664                  if msg != '':
665                    self.add_error('file1',msg)
666
667              if pdbid2:
668                  msg=pdb_code_chain(pdbid2)
669                  if msg != '':
670                    self.add_error('pdbid2',msg)
671                
672              if file2:
673                  msg=pdb_missing_res_chain(file2,'')
674                  if msg != '':
675                    self.add_error('file2',msg)
676
677 class TaskForm_dock_a(forms.Form):
678      name = forms.CharField(max_length=40,widget=forms.TextInput(attrs={'size':40, 'maxlength':40}))
679
680      file1 = forms.FileField(label='Upload a PDB file1',required=False,
681                   help_text='starting structure for chain1')
682      pdbid = forms.CharField(min_length=4,max_length=6,required=False,
683       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
684       label='or PDB code (:chain)')                   
685
686      md_seq = forms.CharField(label=mark_safe('Sequence of chain2 <br /> for dock peptide'),
687                      help_text='aminoacid sequence using one letter code<br>'+
688                         'field is ignored when uploading PDB file2',
689                      required=False,
690                      widget=forms.Textarea(attrs={'cols': 70, 'rows': 2}))
691
692
693      file2 = forms.FileField(label='Upload a PDB file2',required=False,
694                   help_text='starting structure for chain2')
695      pdbid2 = forms.CharField(min_length=4,max_length=6,required=False,
696       widget=forms.TextInput(attrs={'size':6, 'maxlength':6, 'title':'PDB code or PDB code:chain id'}),
697       label='or PDB code (:chain)')                   
698
699
700      md_nstep = forms.IntegerField(label='NSTEP',initial=200000,
701                   help_text='total number of steps', max_value=10000000)
702      md_seed = forms.IntegerField(label='SEED',initial=-39912345,
703                   help_text='seed for random number generator')
704      dock_peptide = forms.BooleanField(required=False,initial=False,
705             label='dock peptide',help_text='no constraints on 2nd chain')                  
706                   
707
708      unres_ff = forms.ChoiceField(choices=FF_CHOICE,widget=forms.RadioSelect,
709                            label='Force Field',initial='FF2')
710
711      md_ntwe = forms.IntegerField(label='NTWE',initial=1000,
712                help_text='write statfile every ntwe steps')
713      md_dt = forms.FloatField(label='DT',initial=0.2,
714                   help_text='time step [mtu = 48.9 fs]')
715      md_lang = forms.ChoiceField(choices=MD_LANG,label='thermostat')
716      md_tau = forms.FloatField(label='tau_bath',initial=1.0,
717                   help_text='coupling to the thermal bath (Berendsen)')
718      md_scal_fric = forms.FloatField(label='scal_froc',initial=0.02,
719                   help_text='scaling of the friction coefficients (Langevin)')
720      min_maxfun = forms.IntegerField(label='MAXFUN',initial=5000,
721                   help_text='preminim maximum number of function evaluations<br>'+
722                   'used for start from pdb or random start')
723      remd_nrep = forms.IntegerField(label='NREP',initial=8,
724                   help_text='number of temperatures')
725      remd_nstex = forms.IntegerField(label='NSTEX',initial=1000,
726                   help_text='exchange and write trajectory every nstex steps')
727      md_ntwx = forms.IntegerField(label='NTWX',initial=1000,min_value=100,
728                help_text='write trajectory every ntwx steps')
729      remd_cluter_temp = forms.FloatField(label='TEMPER',
730                   help_text='temperature for cluster analysis',initial=280)                  
731
732      remd_cluster_n = forms.IntegerField(label='NCLUST',initial=10,min_value=2,
733                     max_value=50,help_text='number of clusters')
734
735      def clean(self):
736              cleaned_data = super(TaskForm_dock_a, self).clean()
737
738              file1 = cleaned_data.get("file1")
739              pdbid = cleaned_data.get("pdbid")
740              file2 = cleaned_data.get("file2")
741              pdbid2 = cleaned_data.get("pdbid2")
742              md_seq = cleaned_data.get("md_seq")
743               
744              if not (file1 or pdbid):
745                 msg = 'no PDB file or code for chain1'
746                 self.add_error('file1', msg)
747
748              if not (file2 or pdbid2 or md_seq):
749                 msg = 'no PDB file or code or sequence for chain2'
750                 self.add_error('file2', msg)
751
752              if pdbid:
753                  msg=pdb_code_chain(pdbid)
754                  if msg != '':
755                    self.add_error('pdbid',msg)
756                
757              if file1:
758                  msg=pdb_missing_res_chain(file1,'')
759                  if msg != '':
760                    self.add_error('file1',msg)
761
762              if pdbid2:
763                  msg=pdb_code_chain(pdbid2)
764                  if msg != '':
765                    self.add_error('pdbid2',msg)
766                
767              if file2:
768                  msg=pdb_missing_res_chain(file2,'')
769                  if msg != '':
770                    self.add_error('file2',msg)
771
772
773 class TaskForm_list(forms.Form):
774     name = forms.CharField(max_length=40,disabled=True,required=False)
775     nrep = forms.IntegerField(disabled=True,required=False,label='NREP')
776
777     def __init__(self, count, *args, **kwargs):
778         super(TaskForm_list, self).__init__(*args, **kwargs)
779         self.count=count
780         self.fields['temperatures'] = MultiExampleField(self.count)
781         self.fields['multiplexing'] = MultiExampleField(self.count)        
782