Source code for dplus.CalculationResult
from collections import OrderedDict
import pprint
from dplus.CalculationInput import CalculationInput
[docs]class CalculationResult(object):
'''
Stores the various aspects of the result for further manipulation
'''
def __init__(self, calc_data, result, job):
'''
:param calc_data: an instance of CalculationInput class
:param result: a json with the result of fit/ generate
:param job: an instance of RunningJob
'''
self._raw_result = result #a json
self._job=job #used for getting amps and pdbs
self._calc_data = calc_data #gets x for getting graph. possibly also used for fitting.
self._get_graph() #creates an ordered dict, key x val y.
self._headers = OrderedDict()
def __str__(self):
return pprint.pformat(self._raw_result)
@property
def y(self):
'''
:return: The raw list of intensity values from the results json
'''
#TODO: replace with something better
return self._raw_result['Graph']
def _get_graph(self):
graph = OrderedDict()
x=self._calc_data.x
try:
if len(x)!=len(self._raw_result['Graph']):
raise ValueError("Result graph size mismatch")
for i in range(len(x)):
graph[x[i]] = self._raw_result['Graph'][i]
except KeyError: #sometimes Fit doesn't return a graph. Also every time Generate crashes.
print("No graph returned")
self._graph=graph
@property
def graph(self):
'''
:return: an OrderedDict whose keys are x values and whose values are y values.
'''
return self._graph
@property
def headers(self):
'''
:return: an OrderDict of headers, whose keys are ModelPtrs and whose values are the header associated.
'''
return self._headers
[docs] def get_pdb(self, model_ptr, destination_folder=None):
'''
returns the file location of the pdb file for given model_ptr. \
destination_folder has a default value of None, but if provided, the pdb file will be copied to that location,\
and then have its address returned
:param model_ptr: int value of model_ptr
:param destination_folder: location to copy the pdb file of the given model_ptr
:return: File location of the pdb file
'''
return self._job._get_pdb(model_ptr, destination_folder)
[docs] def get_amp(self, model_ptr, destination_folder=None):
'''
returns the file location of the amplitude file for given model_ptr. \
destination_folder has a default value of None, but if provided, the amplitude file will be copied to that location,\
and then have its address returned.
:param model_ptr: int value of model_ptr
:param destination_folder: location to copy the amplitude file of the given model_ptr
:return: File location of the amplitude file
'''
return self._job._get_amp(model_ptr, destination_folder)
[docs] def get_amps(self, destination_folder=None):
'''
fetches all the amplitude files created by the calculation, and returns an array of their folder locations. \
destination_folder has a default value of None, but if provided, the amplitude files will be copied to that folder\
:param destination_folder: optional location to save the amplitude files to
:return: Array of file locations of the amplitude files
'''
addresses=[]
for model_ptr in self._calc_data._all_models_indices():
try:
addresses.append(self.get_amp(model_ptr, destination_folder))
except FileNotFoundError: #not every model will necessarily have an amplitude file
pass
return addresses
@property
def error(self):
'''
:return: returns the json error report from the dplus run
'''
if "error" in self._raw_result:
return self._raw_result["error"]
return {"code":0, "message":"no error"}
[docs] def save_to_out_file(self, filename):
'''
receives file name, and saves the results to the file.
:param filename: string of filename/path
'''
with open(filename, 'w') as out_file:
domain_preferences = self._calc_data.DomainPreferences
out_file.write("# Integration parameters:\n")
out_file.write("#\tqmax\t{}\n".format(domain_preferences.q_max))
out_file.write("#\tOrientation Method\t{}\n".format(domain_preferences.orientation_method))
out_file.write("#\tOrientation Iterations\t{}\n".format(domain_preferences.orientation_iterations))
out_file.write("#\tConvergence\t{}\n\n".format(domain_preferences.convergence))
for value in self.headers.values():
out_file.write(value)
for key, value in self.graph.items():
out_file.write('{:.5f}\t{:.20f}\n'.format(key,value))
out_file.close()
[docs]class GenerateResult(CalculationResult):
'''
A class for generate calculation results
'''
def __init__(self, calc_data, result, job):
super().__init__(calc_data,result, job )
self._parse_headers() #sets self._headers to a list of headers
def _parse_headers(self):
header_dict = OrderedDict()
try:
headers = self._raw_result['Headers']
for header in headers:
header_dict[header['ModelPtr']] = header['Header']
except: # TODO: headers don't appear in fit results?
pass # regardless, I'm pretty sure no one cares about headers anyway
self._headers = header_dict
[docs]class FitResult(CalculationResult):
'''
A class for fit calculation results
'''
def __init__(self, calc_data, result, job):
super().__init__(calc_data,result, job )
self._get_parameter_tree() #right now just returns value from result.
self.create_state_results()
def _get_parameter_tree(self):
try:
self._parameter_tree = self._raw_result['ParameterTree']
except KeyError:
raise Exception("ParameterTree doesn't exist")
@property
def parameter_tree(self):
'''
A json of parameters (can be used to create a new state with state's load_from_dictionary).
:return: A json of parameters
'''
return self._parameter_tree
[docs] def create_state_results(self):
'''
This function creates CalculationInput class from the parameters tree returned from a Fit calculation
:return:
'''
# Combine results returned from a Fit calculation
def combine_model_parameters(parameters):
# Combine parameters of just one model
model_ptr = parameters['ModelPtr']
model = self.__state_result.get_model(model_ptr)
mutables = model.get_mutable_params() or []
updated = 0
for param in parameters['Parameters']:
if param['isMutable']:
if updated >= len(mutables):
raise ValueError("Found more 'isMutable' params in ParameterTree than in our state")
mutables[updated].value = param['Value']
updated += 1
if updated != len(mutables):
raise ValueError(
"Found a mismatch between number of 'isMutable' params in the ParamterTree and in our state")
def recursive(parameters):
combine_model_parameters(parameters)
for sub in parameters['Submodels']:
recursive(sub)
self.__state_result = CalculationInput.copy_from_state(self._calc_data)
recursive(self.parameter_tree)
@property
def result_state(self):
return self.__state_result