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

Source Code for Module pipe_control.opendx

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2003-2014 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, median, zeros 
 28  from time import asctime, localtime 
 29   
 30  # relax module imports. 
 31  from lib.errors import RelaxError 
 32  from lib.io import open_write_file 
 33  from extern.numpy_future import percentile 
 34  from lib.software.opendx.files import write_config, write_general, write_point, write_program 
 35  from pipe_control import value 
 36  from specific_analyses.api import return_api 
 37   
38 -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", chi_surface=None):
39 """Map the space corresponding to the spin identifier and create the OpenDX files. 40 41 @keyword params: 42 @type params: 43 @keyword map_type: The type of map to create. The available options are: 44 - 'Iso3D', a 3D isosurface visualisation of the space. 45 @type map_type: str 46 @keyword spin_id: The spin identification string. 47 @type spin_id: str 48 @keyword inc: The resolution of the plot. This is the number of increments per 49 dimension. 50 @type inc: int 51 @keyword lower: The lower bounds of the space to map. If supplied, this should be a 52 list of floats, its length equal to the number of parameters in the 53 model. 54 @type lower: None or list of float 55 @keyword upper: The upper bounds of the space to map. If supplied, this should be a 56 list of floats, its length equal to the number of parameters in the 57 model. 58 @type upper: None or list of float 59 @keyword axis_incs: The number of tick marks to display in the OpenDX plot in each 60 dimension. 61 @type axis_incs: int 62 @keyword file_prefix: The file prefix for all the created files. 63 @type file_prefix: str 64 @keyword dir: The directory to place the files into. 65 @type dir: str or None 66 @keyword point: If supplied, a red sphere will be placed at these coordinates. 67 @type point: None or list of float 68 @keyword point_file: The file prefix for the point output files. 69 @type point_file: str or None 70 """ 71 72 # Check the args. 73 if inc <= 1: 74 raise RelaxError("The increment value needs to be greater than 1.") 75 if axis_incs <= 1: 76 raise RelaxError("The axis increment value needs to be greater than 1.") 77 78 # Space type. 79 if map_type.lower() == "iso3d": 80 if len(params) != 3: 81 raise RelaxError("The 3D isosurface map requires a 3 parameter model.") 82 83 # Create the map. 84 Map(params, spin_id, inc, lower, upper, axis_incs, file_prefix, dir, point, point_file, chi_surface) 85 else: 86 raise RelaxError("The map type '" + map_type + "' is not supported.")
87 88 89
90 -class Map:
91 """The space mapping base class.""" 92
93 - def __init__(self, params, spin_id, inc, lower, upper, axis_incs, file_prefix, dir, point, point_file, chi_surface):
94 """Map the space upon class instantiation.""" 95 96 # Initialise. 97 ############# 98 99 # Function arguments. 100 self.params = params 101 self.spin_id = spin_id 102 self.n = len(params) 103 self.inc = inc 104 self.axis_incs = axis_incs 105 self.file_prefix = file_prefix 106 self.dir = dir 107 self.point_file = point_file 108 109 # The specific analysis API object. 110 self.api = return_api() 111 112 # Points. 113 if point != None: 114 # Check if list is a nested list of lists. 115 if isinstance(point[0], float): 116 self.point = array(point, float64) 117 self.num_points = 1 118 else: 119 point_list = [] 120 for i in range(len(point)): 121 point_list.append(array(point[i], float64)) 122 self.point = point_list 123 self.num_points = i + 1 124 else: 125 self.num_points = 0 126 127 # Get the default map bounds. 128 self.bounds = zeros((self.n, 2), float64) 129 for i in range(self.n): 130 # Get the bounds for the parameter i. 131 bounds = self.api.map_bounds(self.params[i], self.spin_id) 132 133 # No bounds found. 134 if not bounds: 135 raise RelaxError("No bounds for the parameter " + repr(self.params[i]) + " could be determined.") 136 137 # Assign the bounds to the global data structure. 138 self.bounds[i] = bounds 139 140 # Lower bounds. 141 if lower != None: 142 self.bounds[:, 0] = array(lower, float64) 143 144 # Upper bounds. 145 if upper != None: 146 self.bounds[:, 1] = array(upper, float64) 147 148 # Setup the step sizes. 149 self.step_size = zeros(self.n, float64) 150 self.step_size = (self.bounds[:, 1] - self.bounds[:, 0]) / self.inc 151 152 153 # Create all the OpenDX data and files. 154 ####################################### 155 156 # Get the date. 157 self.get_date() 158 159 # Create the strings associated with the map axes. 160 self.map_axes() 161 162 # Generate the map. 163 self.create_map() 164 165 # Default the chi2 surface values, for Innermost, Inner, Middle and Outer Isosurface. 166 if chi_surface == None: 167 all_chi2 = array(self.all_chi, float64) 168 innermost = percentile(all_chi2, 10) 169 inner = percentile(all_chi2, 20) 170 middle = percentile(all_chi2, 50) 171 outer = percentile(all_chi2, 90) 172 chi_surface = [innermost, inner, middle, outer] 173 174 # Create the OpenDX .net program file. 175 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, chi_surface = chi_surface) 176 177 # Create the OpenDX .cfg program configuration file. 178 write_config(file_prefix=self.file_prefix, dir=self.dir, date=self.date) 179 180 # Create the OpenDX .general file. 181 write_general(file_prefix=self.file_prefix, dir=self.dir, inc=self.inc) 182 183 # Create the OpenDX .general and data files for the given point. 184 if self.num_points > 1: 185 write_point(file_prefix=self.point_file, dir=self.dir, inc=self.inc, point=self.point, num_points=self.num_points, bounds=self.bounds, N=self.n)
186 187
188 - def create_map(self):
189 """Function for creating the map.""" 190 191 # Print out. 192 print("\nCreating the map.") 193 194 # Open the file. 195 map_file = open_write_file(file_name=self.file_prefix, dir=self.dir, force=True) 196 197 # Generate and write the text of the map. 198 self.map_3D_text(map_file) 199 200 # Close the file. 201 map_file.close()
202 203
204 - def get_date(self):
205 """Function for creating a date string.""" 206 207 self.date = asctime(localtime())
208 209
210 - def map_3D_text(self, map_file):
211 """Function for creating the text of a 3D map.""" 212 213 # Initialise. 214 values = zeros(3, float64) 215 percent = 0.0 216 percent_inc = 100.0 / (self.inc + 1.0)**(self.n - 1.0) 217 print("%-10s%8.3f%-1s" % ("Progress:", percent, "%")) 218 219 # Collect all chi2, to help finding a reasobale chi level for the Innermost, Inner, Middle and Outer Isosurface. 220 all_chi = [] 221 222 # Fix the diffusion tensor. 223 unfix = False 224 if hasattr(cdp, 'diff_tensor') and not cdp.diff_tensor.fixed: 225 cdp.diff_tensor.fixed = True 226 unfix = True 227 228 # Initial value of the first parameter. 229 values[0] = self.bounds[0, 0] 230 231 # Loop over the first parameter. 232 for i in range((self.inc + 1)): 233 # Initial value of the second parameter. 234 values[1] = self.bounds[1, 0] 235 236 # Loop over the second parameter. 237 for j in range((self.inc + 1)): 238 # Initial value of the third parameter. 239 values[2] = self.bounds[2, 0] 240 241 # Loop over the third parameter. 242 for k in range((self.inc + 1)): 243 # Set the parameter values. 244 if self.spin_id: 245 value.set(val=values, param=self.params, spin_id=self.spin_id, force=True) 246 else: 247 value.set(val=values, param=self.params, force=True) 248 249 # Calculate the function values. 250 if self.spin_id: 251 self.api.calculate(spin_id=self.spin_id, verbosity=0) 252 else: 253 self.api.calculate(verbosity=0) 254 255 # Get the minimisation statistics for the model. 256 if self.spin_id: 257 k, n, chi2 = self.api.model_statistics(spin_id=self.spin_id) 258 else: 259 k, n, chi2 = self.api.model_statistics(model_info=0) 260 261 # Set maximum value to 1e20 to stop the OpenDX server connection from breaking. 262 if chi2 > 1e20: 263 map_file.write("%30f\n" % 1e20) 264 else: 265 map_file.write("%30f\n" % chi2) 266 267 # Save all values of chi2. To help find reasonale level for the Innermost, Inner, Middle and Outer Isosurface. 268 all_chi.append(chi2) 269 270 # Increment the value of the third parameter. 271 values[2] = values[2] + self.step_size[2] 272 273 # Progress incrementation and printout. 274 percent = percent + percent_inc 275 print("%-10s%8.3f%-8s%-8g" % ("Progress:", percent, "%, " + repr(values) + ", f(x): ", chi2)) 276 277 # Increment the value of the second parameter. 278 values[1] = values[1] + self.step_size[1] 279 280 # Increment the value of the first parameter. 281 values[0] = values[0] + self.step_size[0] 282 283 # Unfix the diffusion tensor. 284 if unfix: 285 cdp.diff_tensor.fixed = False 286 287 # Save all chi2 values. 288 self.all_chi = all_chi
289
290 - def map_axes(self):
291 """Function for creating labels, tick locations, and tick values for an OpenDX map.""" 292 293 # Initialise. 294 self.labels = "{" 295 self.tick_locations = [] 296 self.tick_values = [] 297 loc_inc = float(self.inc) / float(self.axis_incs) 298 299 # Loop over the parameters 300 for i in range(self.n): 301 # Parameter conversion factors. 302 factor = self.api.return_conversion_factor(self.params[i]) 303 304 # Parameter units. 305 units = self.api.return_units(self.params[i]) 306 307 # Labels. 308 if units: 309 self.labels = self.labels + "\"" + self.params[i] + " (" + units + ")\"" 310 else: 311 self.labels = self.labels + "\"" + self.params[i] + "\"" 312 313 if i < self.n - 1: 314 self.labels = self.labels + " " 315 else: 316 self.labels = self.labels + "}" 317 318 # Tick values. 319 vals = self.bounds[i, 0] / factor 320 val_inc = (self.bounds[i, 1] - self.bounds[i, 0]) / (self.axis_incs * factor) 321 322 string = "" 323 for j in range(self.axis_incs + 1): 324 string = string + "\"" + "%.2f" % vals + "\" " 325 vals = vals + val_inc 326 self.tick_values.append("{" + string + "}") 327 328 # Tick locations. 329 string = "" 330 val = 0.0 331 for j in range(self.axis_incs + 1): 332 string = string + " " + repr(val) 333 val = val + loc_inc 334 self.tick_locations.append("{" + string + " }")
335