Source code for reporting.reduction.forms
# pylint: disable=bare-except, line-too-long, invalid-name
"""
Forms for auto-reduction configuration
@author: M. Doucet, Oak Ridge National Laboratory
@copyright: 2014 Oak Ridge National Laboratory
"""
import logging
import re
from django import forms
from django.core.exceptions import ValidationError
import reporting.reduction.view_util
from reporting.reduction.models import Choice, ReductionProperty
from reporting.report.models import Instrument
def _get_choices(instrument):
"""
Pull the grouping choices from the database
:param instrument: short name of the instrument
"""
form_choices = []
try:
instrument_id = Instrument.objects.get(name=instrument.lower())
grp_property = ReductionProperty.objects.get(key="grouping", instrument=instrument_id)
choices = Choice.objects.filter(instrument=instrument_id, property=grp_property)
for item in choices:
form_choices.append((item.value, item.description))
except: # noqa: E722
logging.exception("_get_choices: %s instrument or grouping does not exist", instrument.upper())
return sorted(form_choices, key=lambda x: x[1])
[docs]
def validate_integer_list(value):
"""
Allow for "1,2,3" and "1-3"
:param value: string value to parse
"""
# Look for a list of ranges
range_list = value.split(",")
for value_range in range_list:
for item in value_range.split("-"):
if item.strip():
try:
int(item.strip())
except: # noqa: E722
raise ValidationError("Error parsing %s for a range of integers" % value)
[docs]
def validate_float_list(value):
"""
:param value: string value to parse
"""
# Look for a list of ranges
range_list = value.split(",")
for value_range in range_list:
for item in value_range.split("-"):
if item.strip():
try:
float(item.strip())
except: # noqa: E722
raise ValidationError("Error parsing %s for a list of numbers" % value)
[docs]
class BaseReductionConfigurationForm(forms.Form):
"""
Base class for reduction form
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
[docs]
def set_instrument(self, instrument):
"""
Populate instrument-specific options.
:param instrument: instrument short name
"""
pass
[docs]
def to_db(self, instrument_id, user=None):
"""
Store the form data
:param instrument_id: Instrument object
:param user: user that made the change
"""
for key in self._template_list:
try:
if key in self.cleaned_data:
# Make sure we treat booleans properly
if isinstance(self.cleaned_data[key], bool) and self.cleaned_data[key] is False:
value = ""
else:
value = str(self.cleaned_data[key])
else:
value = ""
reporting.reduction.view_util.store_property(instrument_id, key, value, user=user)
except: # noqa: E722
logging.exception("BaseReductionConfigurationForm.to_db:")
[docs]
def to_template(self):
"""
Return a dictionary
"""
template_dict = {}
for key in self._template_list:
if key in self.cleaned_data:
template_dict[key] = str(self.cleaned_data[key])
else:
template_dict[key] = ""
return template_dict
[docs]
class ReductionConfigurationCNCSForm(BaseReductionConfigurationForm):
"""
Generic form for DGS reduction instruments
"""
mask = forms.CharField(required=False, initial="")
sub_directory = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
raw_vanadium = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
processed_vanadium = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
vanadium_integration_min = forms.FloatField(required=True, initial=84000)
vanadium_integration_max = forms.FloatField(required=True, initial=94000)
grouping = forms.ChoiceField(choices=[])
e_pars_in_mev = forms.BooleanField(required=False)
e_min = forms.FloatField(required=True, initial=-0.2)
e_step = forms.FloatField(required=True, initial=0.015)
e_max = forms.FloatField(required=True, initial=0.95)
tib_min = forms.CharField(required=False, initial="", validators=[validate_float_list])
tib_max = forms.CharField(required=False, initial="", validators=[validate_float_list])
do_tib = forms.BooleanField(required=False)
t0 = forms.CharField(required=False, initial="", validators=[validate_float_list])
motor_names = forms.CharField(
required=False,
initial="huber,SERotator2,OxDilRot,CCR13VRot,SEOCRot,CCR10G2Rot,Ox2WeldRot,ThreeSampleRot",
)
temperature_names = forms.CharField(
required=False,
initial="SampleTemp,sampletemp,SensorC,SensorB,SensorA,temp5,temp8",
)
create_elastic_nxspe = forms.BooleanField(required=False)
create_md_nxs = forms.BooleanField(required=False)
a = forms.FloatField(required=True, initial=7.76)
b = forms.FloatField(required=True, initial=7.76)
c = forms.FloatField(required=True, initial=7.02)
alpha = forms.FloatField(required=True, initial=90)
beta = forms.FloatField(required=True, initial=90)
gamma = forms.FloatField(required=True, initial=90)
u_vector = forms.CharField(required=False, initial="1,0,0", validators=[validate_float_list])
v_vector = forms.CharField(required=False, initial="0,0,1", validators=[validate_float_list])
auto_tzero_flag = forms.BooleanField(required=False)
# List of field that are used in the template
_template_list = [
"mask",
"sub_directory",
"raw_vanadium",
"processed_vanadium",
"grouping",
"vanadium_integration_min",
"vanadium_integration_max",
"tib_min",
"tib_max",
"do_tib",
"t0",
"motor_names",
"temperature_names",
"create_elastic_nxspe",
"create_md_nxs",
"alpha",
"beta",
"gamma",
"auto_tzero_flag",
"u_vector",
"v_vector",
"e_pars_in_mev",
"e_min",
"e_step",
"e_max",
"a",
"b",
"c",
]
[docs]
def set_instrument(self, instrument):
"""
Populate instrument-specific options.
:param instrument: instrument short name
"""
self.fields["grouping"].choices = _get_choices(instrument)
[docs]
class ReductionConfigurationDGSForm(BaseReductionConfigurationForm):
"""
Generic form for DGS reduction instruments
"""
mask = forms.CharField(required=False, initial="")
raw_vanadium = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
processed_vanadium = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
grouping = forms.ChoiceField(choices=[])
e_min = forms.FloatField(required=True, initial=-0.2)
e_step = forms.FloatField(required=True, initial=0.015)
e_max = forms.FloatField(required=True, initial=0.95)
# List of field that are used in the template
_template_list = [
"mask",
"raw_vanadium",
"processed_vanadium",
"grouping",
"e_min",
"e_step",
"e_max",
]
[docs]
def set_instrument(self, instrument):
"""
Populate instrument-specific options.
:param instrument: instrument short name
"""
self.fields["grouping"].choices = _get_choices(instrument)
[docs]
class ReductionConfigurationSEQForm(ReductionConfigurationDGSForm):
"""
Reduction form for SEQ
"""
create_elastic_nxspe = forms.BooleanField(required=False)
_template_list = ReductionConfigurationDGSForm._template_list + ["create_elastic_nxspe"]
[docs]
class ReductionConfigurationCorelliForm(BaseReductionConfigurationForm):
"""
Generic form for Corelli reduction instruments
"""
mask = forms.CharField(required=False, initial="")
plot_requests = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
ub_matrix_file = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
vanadium_flux_file = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
vanadium_SA_file = forms.CharField(
required=False,
initial="",
widget=forms.TextInput(attrs={"class": "font_resize"}),
)
useCC = forms.BooleanField(required=False)
# List of field that are used in the template
_template_list = [
"mask",
"plot_requests",
"ub_matrix_file",
"vanadium_flux_file",
"vanadium_SA_file",
"useCC",
]
[docs]
class ReductionConfigurationREF_MForm(BaseReductionConfigurationForm):
"""
Generic form for REF_M reduction instruments
"""
skip_quicknxs = forms.BooleanField(required=False, initial=False)
# Options for all peaks in the run
use_const_q = forms.BooleanField(required=False, initial=False)
q_step = forms.FloatField(required=False, initial=-0.02)
use_sangle = forms.BooleanField(required=False, initial=True)
fit_peak_in_roi = forms.BooleanField(required=False, initial=False)
peak_count = forms.IntegerField(
required=True, min_value=1, initial=1, widget=forms.NumberInput(attrs={"size": "2"})
)
# Options for first peak
force_peak = forms.BooleanField(required=False, initial=False)
peak_min = forms.IntegerField(required=True, initial=160, widget=forms.NumberInput(attrs={"size": "5"}))
peak_max = forms.IntegerField(required=True, initial=170, widget=forms.NumberInput(attrs={"size": "5"}))
use_roi_bck = forms.BooleanField(required=False, initial=False)
force_background = forms.BooleanField(required=False, initial=False)
bck_min = forms.IntegerField(required=True, initial=5, widget=forms.NumberInput(attrs={"size": "5"}))
bck_max = forms.IntegerField(required=True, initial=100, widget=forms.NumberInput(attrs={"size": "5"}))
use_side_bck = forms.BooleanField(required=False, initial=False)
bck_width = forms.IntegerField(required=True, initial=10, widget=forms.NumberInput(attrs={"size": "4"}))
force_low_res = forms.BooleanField(required=False, initial=False)
low_res_min = forms.IntegerField(required=True, initial=20, widget=forms.NumberInput(attrs={"size": "5"}))
low_res_max = forms.IntegerField(required=True, initial=236, widget=forms.NumberInput(attrs={"size": "5"}))
# Options for second peak
force_peak_s2 = forms.BooleanField(required=False, initial=False)
peak_min_s2 = forms.IntegerField(required=True, initial=160, widget=forms.NumberInput(attrs={"size": "5"}))
peak_max_s2 = forms.IntegerField(required=True, initial=170, widget=forms.NumberInput(attrs={"size": "5"}))
use_roi_bck_s2 = forms.BooleanField(required=False, initial=False)
force_background_s2 = forms.BooleanField(required=False, initial=False)
bck_min_s2 = forms.IntegerField(required=True, initial=5, widget=forms.NumberInput(attrs={"size": "5"}))
bck_max_s2 = forms.IntegerField(required=True, initial=100, widget=forms.NumberInput(attrs={"size": "5"}))
use_side_bck_s2 = forms.BooleanField(required=False, initial=False)
bck_width_s2 = forms.IntegerField(required=True, initial=10, widget=forms.NumberInput(attrs={"size": "4"}))
force_low_res_s2 = forms.BooleanField(required=False, initial=False)
low_res_min_s2 = forms.IntegerField(required=True, initial=20, widget=forms.NumberInput(attrs={"size": "5"}))
low_res_max_s2 = forms.IntegerField(required=True, initial=236, widget=forms.NumberInput(attrs={"size": "5"}))
# Options for third peak
force_peak_s3 = forms.BooleanField(required=False, initial=False)
peak_min_s3 = forms.IntegerField(required=True, initial=160, widget=forms.NumberInput(attrs={"size": "5"}))
peak_max_s3 = forms.IntegerField(required=True, initial=170, widget=forms.NumberInput(attrs={"size": "5"}))
use_roi_bck_s3 = forms.BooleanField(required=False, initial=False)
force_background_s3 = forms.BooleanField(required=False, initial=False)
bck_min_s3 = forms.IntegerField(required=True, initial=5, widget=forms.NumberInput(attrs={"size": "5"}))
bck_max_s3 = forms.IntegerField(required=True, initial=100, widget=forms.NumberInput(attrs={"size": "5"}))
use_side_bck_s3 = forms.BooleanField(required=False, initial=False)
bck_width_s3 = forms.IntegerField(required=True, initial=10, widget=forms.NumberInput(attrs={"size": "4"}))
force_low_res_s3 = forms.BooleanField(required=False, initial=False)
low_res_min_s3 = forms.IntegerField(required=True, initial=20, widget=forms.NumberInput(attrs={"size": "5"}))
low_res_max_s3 = forms.IntegerField(required=True, initial=236, widget=forms.NumberInput(attrs={"size": "5"}))
# List of fields are used in the template
_template_list = [
# Options for all peaks in the run
"use_const_q",
"q_step",
"use_sangle",
"fit_peak_in_roi",
"peak_count",
# Options for first peak
"force_peak",
"peak_min",
"peak_max",
"use_roi_bck",
"force_background",
"bck_min",
"bck_max",
"use_side_bck",
"bck_width",
"force_low_res",
"low_res_min",
"low_res_max",
# Options for second peak
"force_peak_s2",
"peak_min_s2",
"peak_max_s2",
"use_roi_bck_s2",
"force_background_s2",
"bck_min_s2",
"bck_max_s2",
"use_side_bck_s2",
"bck_width_s2",
"force_low_res_s2",
"low_res_min_s2",
"low_res_max_s2",
# Options for third peak
"force_peak_s3",
"peak_min_s3",
"peak_max_s3",
"use_roi_bck_s3",
"force_background_s3",
"bck_min_s3",
"bck_max_s3",
"use_side_bck_s3",
"bck_width_s3",
"force_low_res_s3",
"low_res_min_s3",
"low_res_max_s3",
]
[docs]
class MaskForm(forms.Form):
"""
Simple form for a mask entry.
A combination of banks, tubes, pixels can be specified.
"""
bank = forms.CharField(required=False, initial="", validators=[validate_integer_list])
tube = forms.CharField(required=False, initial="", validators=[validate_integer_list])
pixel = forms.CharField(required=False, initial="", validators=[validate_integer_list])
remove = forms.BooleanField(required=False, initial=False)
[docs]
@classmethod
def to_tokens(cls, value):
"""
Takes a block of Mantid script and extract the
dictionary argument. The template should be like
MaskBTPParameters({'Bank':'', 'Tube':'', 'Pixel':''})
:param value: string value for the code snippet
"""
mask_list = []
try:
lines = value.split("\n")
for line in lines:
if "MaskBTPParameters" in line:
mask_strings = re.findall(r"append\((.+)\)", line.strip())
for item in mask_strings:
mask_list.append(eval(item.lower()))
except: # noqa: E722
logging.exception("MaskForm count not parse a command line:")
return mask_list
[docs]
@classmethod
def to_python(cls, mask_list, indent=" "):
"""
Take a block of Mantid script from a list of mask forms
:param mask_list: list of MaskForm objects
:param indent: string indentation to add to each line
"""
command_list = ""
for mask in mask_list:
if "remove" in mask.cleaned_data and mask.cleaned_data["remove"]:
continue
command_str = str(mask)
if len(command_str) > 0:
command_list += "%s%s\n" % (indent, command_str)
return command_list
[docs]
@classmethod
def to_dict_list(cls, mask_list):
"""
Create a list of mask dictionary from a set of mask forms
:param mask_list: list of MaskForm objects
"""
mask_info = []
for mask in mask_list:
entry_dict = {}
if "bank" in mask.cleaned_data and len(mask.cleaned_data["bank"].strip()) > 0:
entry_dict["Bank"] = str(mask.cleaned_data["bank"])
if "tube" in mask.cleaned_data and len(mask.cleaned_data["tube"].strip()) > 0:
entry_dict["Tube"] = str(mask.cleaned_data["tube"])
if "pixel" in mask.cleaned_data and len(mask.cleaned_data["pixel"].strip()) > 0:
entry_dict["Pixel"] = str(mask.cleaned_data["pixel"])
if len(entry_dict) > 0:
mask_info.append(entry_dict)
return mask_info
[docs]
@classmethod
def from_dict_list(cls, param_value):
"""
Return a list of dictionaries that is compatible with our form
:param param_value: string representation of the dictionary
"""
dict_list = eval(param_value)
mask_info = []
for mask in dict_list:
entry_dict = {}
for k, v in mask.items():
entry_dict[k.lower()] = v
mask_info.append(entry_dict)
return mask_info
def __str__(self):
"""
Return a string representing the Mantid command to run
for this mask item.
"""
entry_dict = {}
if "bank" in self.cleaned_data and len(self.cleaned_data["bank"].strip()) > 0:
entry_dict["Bank"] = str(self.cleaned_data["bank"])
if "tube" in self.cleaned_data and len(self.cleaned_data["tube"].strip()) > 0:
entry_dict["Tube"] = str(self.cleaned_data["tube"])
if "pixel" in self.cleaned_data and len(self.cleaned_data["pixel"].strip()) > 0:
entry_dict["Pixel"] = str(self.cleaned_data["pixel"])
if len(entry_dict) == 0:
return ""
return "MaskBTPParameters.append(%s)" % str(entry_dict)
[docs]
class PlottingForm(forms.Form):
"""
Simple form for a mask entry.
A combination of banks, tubes, pixels can be specified.
"""
perpendicular_to = forms.ChoiceField(
required=False,
choices=[
("[H,0,0]", "[H,0,0]"),
("[0,K,0]", "[0,K,0]"),
("[0,0,L]", "[0,0,L]"),
("Q_sample_x", "Qx"),
("Q_sample_y", "Qy"),
("Q_sample_z", "Qz"),
],
)
minimum = forms.FloatField(required=False, initial=-0.05)
maximum = forms.FloatField(required=False, initial=0.05)
remove = forms.BooleanField(required=False, initial=False)
[docs]
@classmethod
def to_dict_list(cls, opt_list):
"""
Create a list of option dictionary from a set of plotting forms
:param optlist: list of PlottingForm objects
"""
plot_info = []
for item in opt_list:
if (
"perpendicular_to" in item.cleaned_data
and len(item.cleaned_data["perpendicular_to"].strip()) > 0
and "minimum" in item.cleaned_data
and "maximum" in item.cleaned_data
):
plot_info.append(
{
"PerpendicularTo": str(item.cleaned_data["perpendicular_to"]),
"Minimum": str(item.cleaned_data["minimum"]),
"Maximum": str(item.cleaned_data["maximum"]),
}
)
return plot_info
[docs]
@classmethod
def from_dict_list(cls, param_value):
"""
Return a list of dictionaries that is compatible with our form
:param param_value: string representation of the dictionary
"""
dict_list = eval(param_value)
# Protect against bad DB entry
if isinstance(dict_list, dict):
dict_list = [dict_list]
plot_info = []
for plot in dict_list:
entry_dict = {}
if "PerpendicularTo" in plot and "Minimum" in plot and "Maximum" in plot:
entry_dict["perpendicular_to"] = plot["PerpendicularTo"]
try:
entry_dict["minimum"] = float(plot["Minimum"])
except: # noqa: E722
entry_dict["minimum"] = -0.05
try:
entry_dict["maximum"] = float(plot["Maximum"])
except: # noqa: E722
entry_dict["maximum"] = 0.05
plot_info.append(entry_dict)
return plot_info