"""
Handles requests and outputs rendered html.
"""
import os
import csv
import warnings
import codecs
import time
# These imports and the setup() call is recuired for multiprocessing, see
# https://stackoverflow.com/questions/46908035/apps-arent-loaded-yet-
# exception-occurs-when-using-multi-processing-in-django
import django
django.setup()
from django.shortcuts import redirect
from django.shortcuts import render, get_object_or_404, HttpResponseRedirect
from django.core.exceptions import ValidationError
from django.contrib import messages
from django.urls import reverse
from multiprocessing import TimeoutError
from urllib import request
from abc import abstractmethod
from . import forms
from . import models
from . import plot
from . import settings
from viroconweb.settings import RUN_MODE
from .models import User, MeasureFileModel, EnvironmentalContour, ContourPath, \
ExtremeEnvDesignCondition, EEDCScalar, AdditionalContourOption, \
ProbabilisticModel, DistributionModel, ParameterModel, PlottedFigure
from .compute_interface import ComputeInterface
from .validators import validate_contour_coordinates
from viroconcom import distributions, params
from .settings import MAX_COMPUTING_TIME, DO_SAVE_CONTOUR_COORDINATES_IN_DB
CONTOUR_CALCULATION_ERROR_MSG = 'Please consider different settings for the ' \
'contour or think about your probabilistic ' \
'model. Feel free to contact us if you ' \
'think this error is caused by a bug: ' \
'virocon@uni-bremen.de'
CONTOUR_REPORT_ERROR_MSG = 'An error occured when trying to generate ' \
'the report for the contour. ' \
'Feel free to contact us if you ' \
'think this error is caused by a bug: ' \
'virocon@uni-bremen.de'
FITTING_ERROR_MSG = 'Feel free to contact us if you ' \
'think this error is caused by a bug: ' \
'virocon@uni-bremen.de'
[docs]def index(request):
"""
Renders the landing page, i.e. the 'Dashboard'.
"""
return render(request, 'contour/home.html')
[docs]class Handler:
[docs] @staticmethod
def overview(request, model_class):
"""
Renders an overview about all objects of a Django Model (all data base
entries).
Parameters
----------
request : HttpRequest,
Request to show the overview.
model_class : class of models.Model,
The class of a Django Model as defined in models.py, e.g.
MeasurementFileModel or EnvironmentalContour.
Returns
-------
HttpResponse,
The rendered overview.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
objects = model_class.objects.all()
context = set()
for object in objects:
bool_ = False
for secUser in object.secondary_user.all():
if secUser == request.user:
bool_ = True
if bool_:
context.add(object)
elif object.primary_user == request.user:
context.add(object)
base = 'contour:' + model_class.url_str()
html = 'contour/' + model_class.url_str() + '_overview.html'
update = base + '_update'
delete = base + '_delete'
add = base + '_add'
calc = base + '_calc'
return render(request, html, {'context': context,
'name': model_class,
'update': update,
'delete': delete,
'add': add,
'calc': calc})
[docs] @staticmethod
def delete(request, pk, model_class):
"""
Deletes an object from the data base.
Parameters
----------
request : HttpRequest,
The request to delete the object.
pk : int,
The object's primary key.
model_class: class of models.Model,
The class of the Django Model (as defined in models.py).
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
object = get_object_or_404(model_class, pk=pk)
if hasattr(object, 'primary_user'):
if object.primary_user == request.user:
object.delete()
else:
object.secondary_user.remove(request.user)
else:
object.delete()
redirection = 'contour:' + model_class.url_str() + '_overview'
return redirect(redirection)
[docs] @staticmethod
def update(request, pk, model_class):
"""
Updates an object in the data base.
Parameters
----------
request : HttpRequest,
The request to update the object.
pk : int,
The object's primary key.
model_class: class of models.Model,
The class of the Django Model (as defined in models.py).
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
redirection = 'contour:' + model_class.url_str() + '_overview'
template = 'contour/update_sec_user.html'
if request.method == 'POST':
object = get_object_or_404(model_class, pk=pk)
username = request.POST.get('username', '')
username = username.replace(",", " ")
username = username.replace(";", " ")
username = username.replace(".", " ")
users = username.split()
for name in users:
try:
user = User.objects.get(username=name)
object.secondary_user.add(user)
except:
messages.add_message(request, messages.ERROR,
'Error. The user name you entered'
', ' + name + ', does not exist.')
return redirect('contour:index')
else:
object.save()
return redirect(redirection)
else:
return render(request, template, {'form': forms.SecUserForm})
[docs] @staticmethod
@abstractmethod
def add(request, *args):
"""
Adds an object to the data base.
Must be overwritten by the Handler specific to one Django Model.
Parameters
----------
request : HttpRequest,
The request to add the object to the data base.
"""
[docs] @staticmethod
@abstractmethod
def select(request):
"""
A reduced overview of all objects to guide the user through the work
flow shown at the Dashboard.
Parameters
----------
request : HttpRequest,
Request to render the select view.
Returns
-------
"""
[docs] @staticmethod
def show(request, pk, model_class):
"""
Shows an object from the data base, e.g. an EnvironmentalContour object.
Parameters
----------
request : HttpRequest,
The HttpRequest to show the object.
pk : int,
Primary key of the object in the data base.
model_class : models.Model,
The class of the Django model, which should be shown. For example
the class models.EnvronmentalContour.
Returns
-------
response : HttpResponse,
Renders an html response showing the object.
"""
if request.user.is_anonymous:
return HttpResponseRedirect(reverse('contour:index'))
else:
html = 'contour/' + model_class.url_str() + '_show.html'
object = model_class.objects.get(pk=pk)
return render(request, html, {'object': object})
[docs]class MeasureFileHandler(Handler):
[docs] @staticmethod
def overview(request, model_class=MeasureFileModel):
return Handler.overview(request, model_class)
[docs] @staticmethod
def delete(request, pk, model_class=MeasureFileModel):
return Handler.delete(request, pk, model_class)
[docs] @staticmethod
def update(request, pk, model_class=MeasureFileModel):
return Handler.update(request, pk, model_class)
[docs] @staticmethod
def select(request):
if request.user.is_anonymous:
return redirect('contour:index')
else:
model_class = MeasureFileModel
objects = model_class.objects.all()
context = set()
for object in objects:
bool_ = False
for secUser in object.secondary_user.all():
if secUser == request.user:
bool_ = True
if bool_:
context.add(object)
elif object.primary_user == request.user:
context.add(object)
return render(request,
'contour/measure_file_model_select.html',
{'context': context}
)
[docs] @staticmethod
def add(request):
"""
Adds a MeasurementFileModel to the data base.
Parameters
----------
request : HttpRequest,
Request to add the model to the data base.
Returns
-------
HttpResponse,
Renders the a response to the user after she/he added the model.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
measure_file_form = forms.MeasureFileForm()
if request.method == 'POST':
measure_file_form = forms.MeasureFileForm(
data=request.POST,
files=request.FILES
)
if measure_file_form.is_valid():
measure_model = MeasureFileModel(
primary_user=request.user,
title=measure_file_form.cleaned_data['title']
)
measure_model.save()
measure_model.measure_file.save(
measure_file_form.cleaned_data['measure_file'].name,
measure_file_form.cleaned_data['measure_file'].file
)
measure_model.save()
path = settings.PATH_MEDIA + \
settings.PATH_USER_GENERATED + \
str(request.user) + \
'/measurement/' + str(measure_model.pk)
measure_model.path_of_statics = path
measure_model.save(
update_fields=['path_of_statics'])
return redirect(
'contour:measure_file_model_plot',
measure_model.pk
)
else:
return render(
request,
'contour/measure_file_model_add.html',
{'form': measure_file_form}
)
else:
return render(
request,
'contour/measure_file_model_add.html',
{'form': measure_file_form}
)
[docs] @staticmethod
def fit_file(request, pk):
"""
Fits a probabilistic model to a measurement file and renders the result.
Parameters
----------
request : HttpRequest,
Request to peform a fit.
pk : int,
Primary key of the measurement file.
Returns
-------
HttpResponse,
Renders the fitting result.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
mfm_item = MeasureFileModel.objects.get(pk=pk)
var_names, var_symbols = get_info_from_file(mfm_item.measure_file.url)
var_number = len(var_names)
fit_form = forms.MeasureFileFitForm(
variable_count=var_number,
variable_names=var_names
)
if request.method == 'POST':
fit_form = forms.MeasureFileFitForm(
data=request.POST,
variable_count=var_number,
variable_names=var_names
)
if fit_form.is_valid():
ci = ComputeInterface()
try:
fit = ci.fit_curves(mfm_item=mfm_item,
fit_settings=fit_form.cleaned_data,
var_number=var_number
)
except (ValueError, RuntimeError, IndexError, TypeError,
NameError, KeyError, TimeoutError) as err:
if RUN_MODE == 'production' and err.__class__.__name__ == 'TimeoutError':
fitting_error_message = \
'<p>Consider running a copy of ViroCon locally ' \
'to allow a longer computation time. See the ' \
'instruction at <a href="https://github.com/' \
'virocon-organization/viroconweb#how-to-use-virocon">' \
'https://github.com/' \
'virocon-organization/viroconweb#how-to-use-virocon' \
'</a> on ' \
'how to do that.</p>' + FITTING_ERROR_MSG
else:
fitting_error_message = FITTING_ERROR_MSG
return render(
request,
'contour/error.html',
{'error_message': err,
'text': fitting_error_message,
'header': 'Fit measurement file to probabilistic '
'model',
'return_url': 'contour:measure_file_model_select'
}
)
directory_prefix = settings.PATH_MEDIA
directory_after_static = settings.PATH_USER_GENERATED + \
str(request.user) + '/prob_model/'
directory = directory_prefix + directory_after_static
prob_model = save_fitted_prob_model(fit,
fit_form.cleaned_data[
'title'],
var_names,
var_symbols,
request.user,
mfm_item)
plot.plot_fit(fit, var_names, var_symbols, directory,
prob_model)
multivariate_distribution = plot.setup_mul_dist(
prob_model
)
latex_string_list = multivariate_distribution.latex_repr(
var_symbols
)
figure_collections = plot.sort_plotted_figures(prob_model)
return render(request,
'contour/fit_results.html',
{'pk': prob_model.pk,
'figure_collections': figure_collections,
'latex_string_list': latex_string_list
}
)
else:
return render(request,
'contour/measure_file_model_fit.html',
{'form': fit_form}
)
return render(request,
'contour/measure_file_model_fit.html',
{'form': fit_form}
)
[docs] @staticmethod
def new_fit(request, pk):
"""
Deletes the previous fit and returns the form to define a new fit.
Parameters
----------
request : HttpRequest,
Request to perform a new fit.
pk : int,
Primary key of the previous fit, which will be deleted.
Returns
-------
HttpResponse,
Renders the view to select a measurement file for fitting.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
plot.ProbabilisticModel.objects.all().filter(pk=pk).delete()
user_files = MeasureFileModel.objects.all().filter(
primary_user=request.user
)
return render(request,
'contour/measure_file_model_select.html',
{'context': user_files}
)
[docs] @staticmethod
def plot_file(request, pk):
"""
Plots and renders a measurement file.
Parameters
----------
request : HttpRequest,
Request to plot a measurement file.
pk : int,
Primary key of the measurement file, which will be plotted.
Returns
-------
HttpResponse,
Renders the plotted measurement file.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
measure_file_model = MeasureFileModel.objects.get(pk=pk)
var_names, var_symbols = get_info_from_file(
measure_file_model.measure_file.url
)
directory_prefix = settings.PATH_MEDIA
directory_after_static = settings.PATH_USER_GENERATED + \
str(request.user) + \
'/measurement/' + str(pk)
plot.plot_data_set_as_scatter(measure_file_model, var_names)
return render(request,
'contour/measure_file_model_plot.html',
{'user': request.user,
'measure_file_model':measure_file_model,
'directory': directory_after_static}
)
[docs]class ProbabilisticModelHandler(Handler):
[docs] @staticmethod
def overview(request, model_class=models.ProbabilisticModel):
return Handler.overview(request, model_class)
[docs] @staticmethod
def delete(request, pk, model_class=models.ProbabilisticModel):
return Handler.delete(request, pk, model_class)
[docs] @staticmethod
def update(request, pk, model_class=models.ProbabilisticModel):
return Handler.update(request, pk, model_class)
[docs] @staticmethod
def select(request):
"""
Renders an overview of the probabilistic models with the option to
select one to calculate an environmental contour.
Parameters
----------
request : HttpRequest,
Request to select a probabilistic model to calculate a contour.
Returns
-------
HttpResponse,
Renders an overview of the probabilistic models with the option to
select one to calculate an environmental contour.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
user_pm = models.ProbabilisticModel.objects.all().filter(
primary_user=request.user
)
return render(request,
'contour/probabilistic_model_select.html',
{'context': user_pm}
)
[docs] @staticmethod
def add(request, *args):
"""
Adds a ProbabilisticModel to the data base.
Parameters
----------
request : HttpRequest,
Request to add the model to the data base.
Returns
-------
HttpResponse,
Renders feedback to the user based on whether she/he is:
* logged in (normal behaviour)
* Sent a defined probabilistic model as a POST request (normal
behaviour)
* Requested a form with a GET request or (unexpected beavhiour)
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
var_num = args[0]
var_num_int = int(var_num)
variable_form = forms.VariablesForm(variable_count=var_num_int)
var_num_form = forms.VariableNumber()
if request.method == 'POST':
variable_form = forms.VariablesForm(data=request.POST,
variable_count=var_num_int)
if variable_form.is_valid():
is_valid_probabilistic_model = True
probabilistic_model = models.ProbabilisticModel(
primary_user=request.user,
collection_name=variable_form.cleaned_data[
'collection_name'],
measure_file_model=None)
probabilistic_model.save()
for i in range(var_num_int):
distribution = models.DistributionModel(
name=variable_form.cleaned_data[
'variable_name_' + str(i)
],
distribution=variable_form.cleaned_data[
'distribution_' + str(i)
],
symbol=variable_form.cleaned_data[
'variable_symbol_' + str(i)
],
probabilistic_model=probabilistic_model
)
distribution.save()
params = ['shape', 'location', 'scale']
if i == 0:
for param in params:
parameter = models.ParameterModel(
function='None',
x0=variable_form.cleaned_data[
param + '_' + str(i) + '_0'
],
dependency='!',
name=param,
distribution=distribution
)
try:
parameter.clean()
except ValidationError as e:
messages.add_message(request,
messages.ERROR,
e.message)
is_valid_probabilistic_model = False
else:
parameter.save()
else:
for param in params:
parameter = models.ParameterModel(
function=variable_form.cleaned_data[param + '_dependency_' + str(i)][1:],
x0=variable_form.cleaned_data[param + '_' + str(i) + '_0'],
x1=variable_form.cleaned_data[param + '_' + str(i) + '_1'],
x2=variable_form.cleaned_data[param + '_' + str(i) + '_2'],
dependency=variable_form.cleaned_data[param + '_dependency_' + str(i)][0],
name=param, distribution=distribution)
try:
parameter.clean()
except ValidationError as e:
messages.add_message(
request,
messages.ERROR,
e.message
)
is_valid_probabilistic_model = False
else:
parameter.save()
if is_valid_probabilistic_model:
return redirect('contour:probabilistic_model_select')
else:
probabilistic_model.delete()
return render(request,
'contour/probabilistic_model_add.html',
{'form': variable_form,
'var_num_form': var_num_form})
else:
return render(request,
'contour/probabilistic_model_add.html',
{'form': variable_form,
'var_num_form': var_num_form})
return render(request, 'contour/probabilistic_model_add.html',
{'form': variable_form, 'var_num_form': var_num_form})
[docs] @staticmethod
def calculate(request, pk, method):
"""
Handles requests to calculate an environmental contour.
This method handles both requests, for an IFORM contour and for a
highest density contour.
Parameters
----------
request : HttpRequest,
Request to calculate a contour.
pk : int,
Primary key of the probabilistic model, which the contour should be
based on.
method : str,
Defines, which method should be used. Must be either 'I' form IFORM
contour or 'H' for highest density contour.
Returns
-------
HttpResponse,
Renders the form for inputing all preprocessing options to calculate
a contour.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
item = models.ProbabilisticModel.objects.get(pk=pk)
var_names = []
var_symbols = []
dists_model = models.DistributionModel.objects.filter(
probabilistic_model=item
)
for dist in dists_model:
var_names.append(dist.name)
var_symbols.append(dist.symbol)
if method == 'I':
return ProbabilisticModelHandler.iform_calc(
request,
var_names,
var_symbols,
item
)
elif method == 'H':
return ProbabilisticModelHandler.hdc_calc(
request,
var_names,
var_symbols,
item
)
else:
KeyError('{} no matching calculation method')
)
[docs] @staticmethod
def hdc_calc(request, var_names, var_symbols, probabilistic_model):
"""
Calls the HDC calculation and handles errors if they occur.
Parameters
----------
request : HttpRequest,
The HttpRequest to either show the calculation settings page or to
calculate the contour (differentiated by POST or GET request).
var_names : list of str
Names of the variables.
var_symbols : list of str
Names of the symbols of the probabilistic model's variables.
probabilistic_model : models.ProbabilisticModel
Probabilistic model, which should be used for the environmental
contour calculation.
Returns
-------
response : HttpResponse,
Renders an html response showing contour or the error message.
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
hdc_form = forms.HDCForm(var_names=var_names)
cs = ComputeInterface()
if request.method == 'POST':
hdc_form = forms.HDCForm(data=request.POST, var_names=var_names)
if hdc_form.is_valid():
limits = []
deltas = []
warn = None
contour_coordinates = None
for i in range(len(var_names)):
limits.append(
(float(hdc_form.cleaned_data['limit_%s' % i + '_1']),
float(hdc_form.cleaned_data['limit_%s' % i + '_2'])))
deltas.append(float(hdc_form.cleaned_data['delta_%s' % i]))
try:
with warnings.catch_warnings(record=True) as warn:
contour_coordinates = cs.hdc(
probabilistic_model,
float(hdc_form.cleaned_data['n_years']),
float(hdc_form.cleaned_data['sea_state']),
limits, deltas)
validate_contour_coordinates(contour_coordinates)
environmental_contour = EnvironmentalContour(
primary_user=request.user,
fitting_method="",
contour_method="Highest density contour (HDC) "
"method",
return_period=float(
hdc_form.cleaned_data['n_years']),
state_duration=float(
hdc_form.cleaned_data['sea_state']),
probabilistic_model=probabilistic_model
)
# Save the environmental contour here that it gets
# a primary key.
environmental_contour.save()
additional_contour_options = []
additional_contour_option = AdditionalContourOption(
option_key="Limits of the grid",
option_value=" ".join(map(str, limits)),
environmental_contour=environmental_contour
)
additional_contour_options.append(
additional_contour_option)
additional_contour_option = AdditionalContourOption(
option_key="Grid cell size ($\Delta x_i$)",
option_value=" ".join(map(str, deltas)),
environmental_contour=environmental_contour
)
additional_contour_options.append(
additional_contour_option)
save_environmental_contour(
environmental_contour,
additional_contour_options,
contour_coordinates,
str(request.user))
# Catch and allocate errors caused by calculating a HDC.
except (TimeoutError, ValidationError, RuntimeError,
IndexError, TypeError, NameError, KeyError) as err:
return render(
request,
'contour/error.html',
{'error_message': err,
'text': CONTOUR_CALCULATION_ERROR_MSG,
'header': 'Calculate contour',
'return_url': 'contour:probabilistic_model_select'}
)
try:
plot.create_latex_report(contour_coordinates,
str(request.user),
environmental_contour,
var_names,
var_symbols)
except (ValueError) as err:
return render(
request,
'contour/error.html',
{'error_message': err,
'text': CONTOUR_REPORT_ERROR_MSG,
'header': 'Report of the contour',
'return_url': 'contour:probabilistic_model_select'}
)
response = ProbabilisticModelHandler.render_calculated_contour(
request, environmental_contour, contour_coordinates,
probabilistic_model, warn)
return response
else:
return render(request, 'contour/contour_settings.html',
{'form': hdc_form}
)
else:
return render(request, 'contour/contour_settings.html',
{'form': hdc_form}
)
[docs] @staticmethod
def render_calculated_contour(request, environmental_contour,
contour_coordinates, probabilistic_model,
warn):
"""
Parameters
----------
request : HttpRequest,
The HttpRequest to calculate the contour. It is a POST request.
environmental_contour : EnvironmentalContour,
The EnvironmentalContour that just got computed.
contour_coordinates : list of list of np.ndarray,
The contour's coordinates.
The format is defined in viroconcom.contours.Contour.
probabilistic_model : ProbabilisticModel,
The ProbabilisticModel, which was used to calculate the
EnvironmentalContour
warn : list of warning,
Warnings can get raised during the calculation of the contour.
Then the user will be presented these warnings.
Returns
-------
response : HttpResponse,
The rendered template 'evnironmental_contour_show.html' with the
calculated EnvironmentalContour.
"""
# If the probabilistic model is 4-dimensional send data to create a 4D
# interactive plot.
if len(contour_coordinates[0]) == 4:
dists = models.DistributionModel.objects.filter(
probabilistic_model=probabilistic_model
)
labels = []
for dist in dists:
labels.append('{} [{}]'.format(dist.name, dist.symbol))
response = render(request,
'contour/environmental_contour_show.html',
{'object': environmental_contour,
'x': contour_coordinates[0][0].tolist(),
'y': contour_coordinates[0][1].tolist(),
'z': contour_coordinates[0][2].tolist(),
'u': contour_coordinates[0][3].tolist(),
'dim': 4,
'labels': labels}
)
# If the probabilistic model is 3-dimensional send data for a 3D
# interactive plot
elif len(contour_coordinates[0]) == 3:
dists = models.DistributionModel.objects.filter(
probabilistic_model=probabilistic_model
)
labels = []
for dist in dists:
labels.append('{} [{}]'.format(dist.name, dist.symbol))
response = render(request,
'contour/environmental_contour_show.html',
{'object': environmental_contour,
'x': contour_coordinates[0][0].tolist(),
'y': contour_coordinates[0][1].tolist(),
'z': contour_coordinates[0][2].tolist(),
'dim': 3,
'labels': labels})
elif len(contour_coordinates) < 3:
response = render(request,
'contour/environmental_contour_show.html',
{'object': environmental_contour, 'dim': 2}
)
return response
[docs] @staticmethod
def set_variables_number(request):
"""
Sets the number of variables when a probabilistc model is defined
directly.
Parameters
----------
request : HttpRequest,
Request to set the number of variables of the probabilistic model.
Returns
-------
HttpResponse,
Either adds the probabilistic model to the data base (POST request)
or renders the form to add a probabilistic model (GET request).
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
var_num_str = str()
if request.method == 'POST':
var_num_form = forms.VariableNumber(request.POST)
if var_num_form.is_valid():
var_num = var_num_form.cleaned_data['variable_number']
var_num_str = str(var_num)
if int(var_num) < 10:
var_num_str = '0' + var_num_str
return redirect('contour:probabilistic_model_add', var_num_str)
else:
variable_form = forms.VariablesForm()
var_num_form = forms.VariableNumber()
return render(request, 'contour/probabilistic_model_add.html',
{'form': variable_form, 'var_num_form': var_num_form})
[docs] @staticmethod
def show_model(request, pk):
"""
Shows a probabilistic model.
Parameters
----------
request : HttpRequest,
Request to show a probabilistic model.
pk : int,
Primary key of the probabilistic model.
Returns
-------
HttpResponse,
Renders the definition of the probabilistic model (its name,
the probability density function, information about the fit)
"""
if request.user.is_anonymous:
return redirect('contour:index')
else:
probabilistic_model = models.ProbabilisticModel.objects.get(pk=pk)
dists_model = models.DistributionModel.objects.filter(
probabilistic_model=probabilistic_model
)
var_symbols = []
for dist in dists_model:
var_symbols.append(dist.symbol)
multivariate_distribution = plot.setup_mul_dist(probabilistic_model)
latex_string_list = multivariate_distribution.latex_repr(var_symbols)
figure_collections = plot.sort_plotted_figures(probabilistic_model)
return render(
request,
'contour/probabilistic_model_show.html',
{'user': request.user,
'probabilistic_model': probabilistic_model,
'latex_string_list': latex_string_list,
'figure_collections': figure_collections})
[docs]class EnvironmentalContourHandler(Handler):
"""
Handler for EnvironmentalContour objects.
"""
[docs] @staticmethod
def overview(request, model_class=models.EnvironmentalContour):
return Handler.overview(request, model_class)
@staticmethod
def delete(request, pk, model_class=models.EnvironmentalContour):
return Handler.delete(request, pk, model_class)
[docs] @staticmethod
def update(request, pk, model_class=models.EnvironmentalContour):
return Handler.update(request, pk, model_class)
[docs] @staticmethod
def show(request, pk, model_class=models.EnvironmentalContour):
return Handler.show(request, pk, model_class)
[docs] @staticmethod
def delete(request, pk, collection=models.EnvironmentalContour):
return Handler.delete(request, pk, collection)
[docs]def save_fitted_prob_model(fit, model_title, var_names, var_symbols, user,
measure_file):
"""
Saves a probabilistic model which was fitted to measurement data.
Parameters
----------
fit : Fit,
Calculated fit results of a measurement file.
model_title : str,
Title of the probabilistic model.
var_names : list of str,
Names of the variables.
var_symbols : list of str,
Names of the symbols of the probabilistic model's variables.
user : str,
Name of a user.
measure_file : MeasureFileModel,
MeasureFileModel object linked to the probabilistic model.
Returns
-------
ProbabilisticModel
ProbabilisticModel that was fitted to the measurement file.
"""
probabilistic_model = ProbabilisticModel(primary_user=user,
collection_name=model_title,
measure_file_model=measure_file)
probabilistic_model.save()
for i, dist in enumerate(fit.mul_var_dist.distributions):
if dist.name == 'Lognormal':
dist_name = 'Lognormal_SigmaMu'
distribution_model = DistributionModel(name=var_names[i],
symbol=var_symbols[i],
probabilistic_model=probabilistic_model,
distribution=dist_name)
distribution_model.save()
save_parameter(dist.shape, distribution_model,
fit.mul_var_dist.dependencies[i][0], 'shape')
save_parameter(dist.loc, distribution_model,
fit.mul_var_dist.dependencies[i][1], 'loc')
save_parameter(dist.mu, distribution_model,
fit.mul_var_dist.dependencies[i][2], 'scale')
else:
distribution_model = DistributionModel(
name=var_names[i],
symbol=var_symbols[i],
probabilistic_model=probabilistic_model,
distribution=dist.name
)
distribution_model.save()
save_parameter(dist.shape, distribution_model,
fit.mul_var_dist.dependencies[i][0], 'shape')
save_parameter(dist.loc, distribution_model,
fit.mul_var_dist.dependencies[i][1], 'loc')
save_parameter(dist.scale, distribution_model,
fit.mul_var_dist.dependencies[i][2], 'scale')
return probabilistic_model
[docs]def save_environmental_contour(environmental_contour,
additional_contour_options,
contour_coordinates,
user):
"""
Saves an EnvironmentalContour object and its depending models to the data
base.
Parameters
----------
environmental_contour : EnvironmentalContour,
The environmental contour obect that should be saved.
additional_contour_options : list of AdditionalContourOption,
Options, whch are specific to the contour and are not general
environmental contour options.
contour_coordinates : list of list of numpy.ndarray,
Contains the coordinates of points on the contour.
The outer list contains can hold multiple contour paths if the
distribution is multimodal. The inner list contains multiple
numpy arrays of the same length, one per dimension.
The values of the arrays are the coordinates in the corresponding
dimension.
user : str,
The user who should own the environmental contour.
Returns
-------
EnvironmentalContour,
The saved environmental contour object.
"""
# Only save the object if it has not been saved yet.
if environmental_contour.pk is None:
environmental_contour.save()
path = settings.PATH_MEDIA + \
settings.PATH_USER_GENERATED + \
user + \
'/contour/' + str(environmental_contour.pk)
environmental_contour.path_of_statics = path
environmental_contour.save(
update_fields=['path_of_statics'])
for additional_contour_option in additional_contour_options:
# It is necessary to create a new AdditionalContourObject because the
# original object was created with an environmental contour, which has
# been saved yet and consequently does not have a primary key.
additional_contour_option_w_pk = AdditionalContourOption(
option_key=additional_contour_option.option_key,
option_value=additional_contour_option.option_value,
environmental_contour=environmental_contour)
additional_contour_option_w_pk.save()
# Saving all coordinates to the database is slow since a lot of operations
# might be necessary. Consequenetly, this can be turned off.
if DO_SAVE_CONTOUR_COORDINATES_IN_DB:
for i in range(len(contour_coordinates)):
contour_path = ContourPath(
environmental_contour=environmental_contour)
contour_path.save()
for j in range(len(contour_coordinates[i])):
EEDC = ExtremeEnvDesignCondition(
contour_path=contour_path)
EEDC.save()
for k in range(len(contour_coordinates[i][j])):
eedc_scalar = EEDCScalar(
x=float(contour_coordinates[i][j][k]),
EEDC=EEDC)
eedc_scalar.save()
return environmental_contour
[docs]def save_parameter(parameter, distribution_model, dependency, name):
"""
Saves a fitted parameter and links it to a DistributionModel.
Parameters
----------
parameter : ConstantParam or FunctionParam
ConstantParam is a float value. FunctionParam contains a whole function
like power function or exponential.
distribution_model : DistributionModel
The parameter will be linked to this DistributionModel.
dependency : int
The dimension the dependency is based on.
name : str
Name of the parameter ('shape', 'loc' or 'scale')
"""
if type(parameter) == params.ConstantParam:
parameter_model = ParameterModel(function='None',
x0=parameter(0),
dependency='!',
distribution=distribution_model,
name=name)
parameter_model.save()
elif type(parameter) == params.FunctionParam:
parameter_model = ParameterModel(function=parameter.func_name,
x0=parameter.a,
x1=parameter.b,
x2=parameter.c,
dependency=dependency,
distribution=distribution_model,
name=name)
parameter_model.save()
else:
parameter_model = ParameterModel(function='None',
x0=0,
dependency='!',
distribution=distribution_model,
name=name)
parameter_model.save()
[docs]def get_info_from_file(url):
"""
Reads the variable names and symbols form a csv file.
Parameters
----------
url : str,
Path to the csv file.
Returns
-------
var_names : list of str,
Names of the environmental variables used in csv file,
e.g. ['wind speed [m/s]', 'significant wave height [m]']
var_symbols : list of str,
Symbols of the environental variables used in the csv file,
e.g. ['V', 'Hs']
"""
if url[0] == '/':
url = url[1:]
if url[0:8] == 'https://':
req = request.Request(url)
print('Trying to urlopen the url: ' + str(url))
with request.urlopen(req) as response:
reader = csv.reader(codecs.iterdecode(response, 'utf-8'), delimiter=';')
var_names, var_symbols = get_header_info_from_reader(reader)
else:
with open(url, 'r') as file:
reader = csv.reader(file, delimiter=';')
var_names, var_symbols = get_header_info_from_reader(reader)
return var_names, var_symbols
return var_names, var_symbols