Package pipe_control :: Module opendx
[hide private]
[frames] | no frames]

Source Code for Module pipe_control.opendx

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2013 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program is free software: you can redistribute it and/or modify        # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation, either version 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program is distributed in the hope that it will be useful,             # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """Module containing the base class for the OpenDX space mapping classes.""" 
 24   
 25   
 26  # Python module imports. 
 27  from numpy import float64, array, zeros 
 28  from time import asctime, localtime 
 29   
 30  # relax module imports. 
 31  from lib.errors import RelaxError, RelaxUnknownParamError 
 32  from lib.io import open_write_file 
 33  from lib.software.opendx.files import write_config, write_general, write_point, write_program 
 34  from pipe_control import diffusion_tensor 
 35  from pipe_control import pipes 
 36  from pipe_control import value 
 37  from specific_analyses.setup import get_specific_fn 
 38   
 39   
40 -def map(params=None, map_type='Iso3D', spin_id=None, inc=20, lower=None, upper=None, axis_incs=10, file_prefix="map", dir="dx", point=None, point_file="point", remap=None):
41 """Map the space corresponding to the spin identifier and create the OpenDX files. 42 43 @keyword params: 44 @type params: 45 @keyword map_type: The type of map to create. The available options are: 46 - 'Iso3D', a 3D isosurface visualisation of the space. 47 @type map_type: str 48 @keyword spin_id: The spin identification string. 49 @type spin_id: str 50 @keyword inc: The resolution of the plot. This is the number of increments per 51 dimension. 52 @type inc: int 53 @keyword lower: The lower bounds of the space to map. If supplied, this should be a 54 list of floats, its length equal to the number of parameters in the 55 model. 56 @type lower: None or list of float 57 @keyword upper: The upper bounds of the space to map. If supplied, this should be a 58 list of floats, its length equal to the number of parameters in the 59 model. 60 @type upper: None or list of float 61 @keyword axis_incs: The number of tick marks to display in the OpenDX plot in each 62 dimension. 63 @type axis_incs: int 64 @keyword file_prefix: The file prefix for all the created files. 65 @type file_prefix: str 66 @keyword dir: The directory to place the files into. 67 @type dir: str or None 68 @keyword point: If supplied, a red sphere will be placed at these coordinates. 69 @type point: None or list of float 70 @keyword point_file: The file prefix for the point output files. 71 @type point_file: str or None 72 @keyword remap: A function which is used to remap the space. The function should accept 73 the parameter array (list of float) and return an array of equal length 74 (again list of float). 75 @type remap: None or func 76 """ 77 78 # Check the args. 79 if inc <= 1: 80 raise RelaxError("The increment value needs to be greater than 1.") 81 if axis_incs <= 1: 82 raise RelaxError("The axis increment value needs to be greater than 1.") 83 84 # Space type. 85 if map_type.lower() == "iso3d": 86 if len(params) != 3: 87 raise RelaxError("The 3D isosurface map requires a 3 parameter model.") 88 89 # Create the map. 90 Map(params, spin_id, inc, lower, upper, axis_incs, file_prefix, dir, point, point_file, remap) 91 else: 92 raise RelaxError("The map type '" + map_type + "' is not supported.")
93 94 95
96 -class Map:
97 """The space mapping base class.""" 98
99 - def __init__(self, params, spin_id, inc, lower, upper, axis_incs, file_prefix, dir, point, point_file, remap):
100 """Map the space upon class instantiation.""" 101 102 # Initialise. 103 ############# 104 105 # Function arguments. 106 self.params = params 107 self.spin_id = spin_id 108 self.n = len(params) 109 self.inc = inc 110 self.axis_incs = axis_incs 111 self.file_prefix = file_prefix 112 self.dir = dir 113 self.point_file = point_file 114 self.remap = remap 115 116 # Specific function setup. 117 self.calculate = get_specific_fn('calculate', cdp.pipe_type) 118 self.model_stats = get_specific_fn('model_stats', cdp.pipe_type) 119 self.return_data_name = get_specific_fn('return_data_name', cdp.pipe_type) 120 self.map_bounds = [] 121 self.return_conversion_factor = [] 122 self.return_units = [] 123 for i in range(self.n): 124 self.map_bounds.append(get_specific_fn('map_bounds', cdp.pipe_type)) 125 self.return_conversion_factor.append(get_specific_fn('return_conversion_factor', cdp.pipe_type)) 126 self.return_units.append(get_specific_fn('return_units', cdp.pipe_type)) 127 128 # Diffusion tensor parameter flag. 129 self.diff_params = zeros(self.n) 130 131 # Get the parameter names. 132 self.get_param_names() 133 134 # Specific function setup (for diffusion tensor parameters). 135 for i in range(self.n): 136 if self.diff_params[i]: 137 self.map_bounds[i] = diffusion_tensor.map_bounds 138 self.return_conversion_factor[i] = diffusion_tensor.return_conversion_factor 139 self.return_units[i] = diffusion_tensor.return_units 140 141 # Points. 142 if point != None: 143 self.point = array(point, float64) 144 self.num_points = 1 145 else: 146 self.num_points = 0 147 148 # Get the default map bounds. 149 self.bounds = zeros((self.n, 2), float64) 150 for i in range(self.n): 151 # Get the bounds for the parameter i. 152 bounds = self.map_bounds[i](self.param_names[i], self.spin_id) 153 154 # No bounds found. 155 if not bounds: 156 raise RelaxError("No bounds for the parameter " + repr(self.params[i]) + " could be determined.") 157 158 # Assign the bounds to the global data structure. 159 self.bounds[i] = bounds 160 161 # Lower bounds. 162 if lower != None: 163 self.bounds[:, 0] = array(lower, float64) 164 165 # Upper bounds. 166 if upper != None: 167 self.bounds[:, 1] = array(upper, float64) 168 169 # Setup the step sizes. 170 self.step_size = zeros(self.n, float64) 171 self.step_size = (self.bounds[:, 1] - self.bounds[:, 0]) / self.inc 172 173 174 # Create all the OpenDX data and files. 175 ####################################### 176 177 # Get the date. 178 self.get_date() 179 180 # Create the strings associated with the map axes. 181 self.map_axes() 182 183 # Create the OpenDX .net program file. 184 write_program(file_prefix=self.file_prefix, point_file=self.point_file, dir=self.dir, inc=self.inc, N=self.n, num_points=self.num_points, labels=self.labels, tick_locations=self.tick_locations, tick_values=self.tick_values, date=self.date) 185 186 # Create the OpenDX .cfg program configuration file. 187 write_config(file_prefix=self.file_prefix, dir=self.dir, date=self.date) 188 189 # Create the OpenDX .general file. 190 write_general(file_prefix=self.file_prefix, dir=self.dir, inc=self.inc) 191 192 # Create the OpenDX .general and data files for the given point. 193 if self.num_points == 1: 194 write_point(file_prefix=self.point_file, dir=self.dir, inc=self.inc, point=self.point, bounds=self.bounds, N=self.n) 195 196 # Generate the map. 197 self.create_map()
198 199
200 - def create_map(self):
201 """Function for creating the map.""" 202 203 # Print out. 204 print("\nCreating the map.") 205 206 # Open the file. 207 map_file = open_write_file(file_name=self.file_prefix, dir=self.dir, force=True) 208 209 # Generate and write the text of the map. 210 self.map_3D_text(map_file) 211 212 # Close the file. 213 map_file.close()
214 215
216 - def get_date(self):
217 """Function for creating a date string.""" 218 219 self.date = asctime(localtime())
220 221
222 - def get_param_names(self):
223 """Function for retrieving the parameter names.""" 224 225 # Initialise. 226 self.param_names = [] 227 228 # Loop over the parameters. 229 for i in range(self.n): 230 # Get the parameter name. 231 name = self.return_data_name(self.params[i]) 232 233 # Diffusion tensor parameter. 234 if pipes.get_type() == 'mf': 235 # The diffusion tensor parameter name. 236 diff_name = diffusion_tensor.return_data_name(self.params[i]) 237 238 # Replace the model-free parameter with the diffusion tensor parameter if it exists. 239 if diff_name: 240 name = diff_name 241 242 # Set the flag indicating if there are diffusion tensor parameters. 243 self.diff_params[i] = 1 244 245 # Bad parameter name. 246 if not name: 247 raise RelaxUnknownParamError(self.params[i]) 248 249 # Append the parameter name. 250 self.param_names.append(name)
251 252
253 - def map_3D_text(self, map_file):
254 """Function for creating the text of a 3D map.""" 255 256 # Initialise. 257 values = zeros(3, float64) 258 percent = 0.0 259 percent_inc = 100.0 / (self.inc + 1.0)**(self.n - 1.0) 260 print("%-10s%8.3f%-1s" % ("Progress:", percent, "%")) 261 262 # Fix the diffusion tensor. 263 unfix = False 264 if hasattr(cdp, 'diff_tensor') and not cdp.diff_tensor.fixed: 265 cdp.diff_tensor.fixed = True 266 unfix = True 267 268 # Initial value of the first parameter. 269 values[0] = self.bounds[0, 0] 270 271 # The model identifier. 272 273 # Loop over the first parameter. 274 for i in range((self.inc + 1)): 275 # Initial value of the second parameter. 276 values[1] = self.bounds[1, 0] 277 278 # Loop over the second parameter. 279 for j in range((self.inc + 1)): 280 # Initial value of the third parameter. 281 values[2] = self.bounds[2, 0] 282 283 # Loop over the third parameter. 284 for k in range((self.inc + 1)): 285 # Set the parameter values. 286 if self.spin_id: 287 value.set(val=values, param=self.params, spin_id=self.spin_id, force=True) 288 else: 289 value.set(val=values, param=self.params, force=True) 290 291 # Calculate the function values. 292 if self.spin_id: 293 self.calculate(spin_id=self.spin_id, verbosity=0) 294 else: 295 self.calculate(verbosity=0) 296 297 # Get the minimisation statistics for the model. 298 if self.spin_id: 299 k, n, chi2 = self.model_stats(spin_id=self.spin_id) 300 else: 301 k, n, chi2 = self.model_stats(model_info=0) 302 303 # Set maximum value to 1e20 to stop the OpenDX server connection from breaking. 304 if chi2 > 1e20: 305 map_file.write("%30f\n" % 1e20) 306 else: 307 map_file.write("%30f\n" % chi2) 308 309 # Increment the value of the third parameter. 310 values[2] = values[2] + self.step_size[2] 311 312 # Progress incrementation and printout. 313 percent = percent + percent_inc 314 print("%-10s%8.3f%-8s%-8g" % ("Progress:", percent, "%, " + repr(values) + ", f(x): ", chi2)) 315 316 # Increment the value of the second parameter. 317 values[1] = values[1] + self.step_size[1] 318 319 # Increment the value of the first parameter. 320 values[0] = values[0] + self.step_size[0] 321 322 # Unfix the diffusion tensor. 323 if unfix: 324 cdp.diff_tensor.fixed = False
325 326
327 - def map_axes(self):
328 """Function for creating labels, tick locations, and tick values for an OpenDX map.""" 329 330 # Initialise. 331 self.labels = "{" 332 self.tick_locations = [] 333 self.tick_values = [] 334 loc_inc = float(self.inc) / float(self.axis_incs) 335 336 # Loop over the parameters 337 for i in range(self.n): 338 # Parameter conversion factors. 339 factor = self.return_conversion_factor[i](self.param_names[i]) 340 341 # Parameter units. 342 units = self.return_units[i](self.param_names[i]) 343 344 # Labels. 345 if units: 346 self.labels = self.labels + "\"" + self.params[i] + " (" + units + ")\"" 347 else: 348 self.labels = self.labels + "\"" + self.params[i] + "\"" 349 350 if i < self.n - 1: 351 self.labels = self.labels + " " 352 else: 353 self.labels = self.labels + "}" 354 355 # Tick values. 356 vals = self.bounds[i, 0] / factor 357 val_inc = (self.bounds[i, 1] - self.bounds[i, 0]) / (self.axis_incs * factor) 358 359 string = "" 360 for j in range(self.axis_incs + 1): 361 string = string + "\"" + "%.2f" % vals + "\" " 362 vals = vals + val_inc 363 self.tick_values.append("{" + string + "}") 364 365 # Tick locations. 366 string = "" 367 val = 0.0 368 for j in range(self.axis_incs + 1): 369 string = string + " " + repr(val) 370 val = val + loc_inc 371 self.tick_locations.append("{" + string + " }")
372