def trap_int(self, dataValue, dataLoc, start, stop): """ function utilizes trapezoidal integration to integrate from start Index to stop Index :param dataValue: Array Values to integrate :param dataLoc: Array of Locations corresponding to Values :param start: index to start integration :param stop: index to stop integration :param f: function to integrate :param f_const_args: constant argument list to be passed to function f :return: value of 1/2 SUM[k = 1 : N] ( f(k+1) + f(k) ds ) """ i_list = [] for x in range(start, stop): try: if not self.is_bifurcated: i_list.append((ih.mag( np.array(dataLoc[x + 1]) - np.array(dataLoc[x]))) * (np.sqrt(1 - ih.mag(dataValue[x + 1]) / ih.mag(dataValue[stop])) + np.sqrt(1 - ih.mag(dataValue[x]) / ih.mag(dataValue[stop])))) except: print "ERROR OF SOME KIND" print "start: ", start print "stop: ", stop print "Current: ", x print "Current+1: ", x + 1 print "Size of Data: ", len(dataValue) print "Size of Points: ", len(dataLoc) # sys.exit(10) break return 0.5 * np.sum(i_list)
def get_new_phi_for_localtime(self, localtime, RE=1): """ returns the intersection location of RE and field line searched for from localtime :param localtime: :param RE: :return: """ # TODO: change this to work with spherical rotation interpolation (great circle) start_lines_old = self.get_phi_locations(RE=RE) start_lines = dict() start_lt = sorted(start_lines.keys()) # normalize the starting vectors (so we have unit vectors to work with) # TODO: Basing this off the keys is wrong, as the field line might be found on a localtime, # TODO: but may not intersect anywhere near that line. for key in start_lines_old: # Need to build new keys based on actual local-time of intersection mag_start = start_lines_old[key]/ih.mag(start_lines_old[key]) new_key = ih.get_local_time_from_location(mag_start) start_lines[new_key] = mag_start if np.isclose(new_key, 24.0, rtol=0.0, atol=self.error_tol): # print "Found 2400: ", new_key start_lines[0.0] = mag_start elif np.isclose(new_key, 0.0, rtol=0.0, atol=self.error_tol): # print "Found 0000: ", new_key start_lines[24.0] = mag_start # TODO: How to loop if we dont have 2400/0000 as a key? start_lt = sorted(start_lines.keys()) # print start_lt index_high = bs.bisect_left(start_lt, localtime) index_low = index_high -1 # adjust to circular if index_high is len(start_lt): index_high = 0 latitude_high = np.arcsin(start_lines[start_lt[index_high]][2]) latitude_low = np.arcsin(start_lines[start_lt[index_low]][2]) w = (float(localtime) - float(start_lt[index_low])) / (float(start_lt[index_high]) - float(start_lt[index_low])) latitude_new = latitude_low + (latitude_high - latitude_low) * w loc_localtime = ih.get_location_from_localtime(localtime) longitude_new = (np.arctan2(loc_localtime[1],loc_localtime[0])) ret = tuple([np.cos(longitude_new) * np.cos(latitude_new)*RE, np.sin(longitude_new) * np.cos(latitude_new)*RE, np.sin(latitude_new)*RE]) return ret
def _integrate_i(self, B_mirror): """ integrates a specific I for a given B_mirror :param B_mirror: :return: Value of I """ if not self.is_bifurcated: if B_mirror in self.get_b_mag_values(): # 1) locate B_mirror index b_f_mag = [ih.mag(x) for x in self.fieldLineData_f] b_mir_ind = b_f_mag.index(B_mirror) # 2) Integrate FORWARD to B_mirror int_forward = self.trap_int(dataValue=self.fieldLineData_f, dataLoc=self.fieldLinePoints_f, start=0, stop=b_mir_ind) # 3) Integrate BACKWARD to B_mirror int_backward = self.trap_int(dataValue=self.fieldLineData_b, dataLoc=self.fieldLinePoints_b, start=0, stop=b_mir_ind) # 4) Return BACKWARD + FORWARD return int_forward + int_backward else: b_mags = self.get_b_mag_values() hi_ind = bs.bisect_left(b_mags, B_mirror) if hi_ind == len(b_mags) or hi_ind == 0: return None else: bmir, Iall = ih.dict_to_x_y(self.get_i_integrals()) return ih.cub_interp(Iall, bmir, B_mirror) else: return None
def build_grid(self): # Dimensions nx, ny, nz = self._dims_[0], self._dims_[1], self._dims_[ 2] # Grid Extent resolution lx, ly, lz = self._extents_[0], self._extents_[2], self._extents_[4] ux, uy, uz = self._extents_[1], self._extents_[3], self._extents_[5] # Coordinates X = np.linspace(lx, ux, nx) Y = np.linspace(ly, uy, ny) Z = np.linspace(lz, uz, nz) # Build the Grid x = np.zeros((nx, ny, nz)) y = np.zeros((nx, ny, nz)) z = np.zeros((nx, ny, nz)) for k in range(len(Z)): for j in range(len(Y)): for i in range(len(X)): x[i, j, k] = X[i] y[i, j, k] = Y[j] z[i, j, k] = Z[k] if (-self._exclusion_distance_ < X[i] < self._exclusion_distance_) and ( -self._exclusion_distance_ < Y[j] < self._exclusion_distance_) and ( -self._exclusion_distance_ < Z[k] < self._exclusion_distance_): if ih.mag([X[i], Y[j], Z[k] ]) < self._exclusion_distance_: self.origin_exclusion.append((i, j, k)) print "Excluding: ", (i, j, k) return x, y, z
def __init__(self, PV_dataObject=None, local_times=None, K=None, b_mirror=None, start_line=None, mode='K', error_tol=None): """ Initialization routine for driftShell class. Sets up the intial configuration of a drift shell :param PV_dataObject: Paraview Data object that contains the grid :param local_times: array like object of starting local times for finding starting lines (mode='K', K, b_mirror) required. :param K: value of K used to define the particle :param b_mirror: b_mirror (nT) used to define the particle :param start_line: (x,y,z) coordinates for starting line (requires b_mirror) :param mode: 'location' or 'K'. 'location': starts with a specific location and traces first line there. Uses the given b_mirror. 'K': utilizes local time and K to itterate and find the requested b_mirror """ self.data = PV_dataObject self.is_valid = True self.analytic = False if error_tol is None: self.error_tol = 1e-5 else: self.error_tol = error_tol if mode is 'location_k': print "Location (K) based mode" if start_line is None or K is None: print "ERROR: start_line and K are both required in this mode" sys.exit() self.start_location = start_line self.start_RE = ih.mag(start_line) self.K = K self.field_lines = col.OrderedDict() localtime2 = ih.get_local_time_from_location(start_line) self.field_lines[localtime2] = fl.fieldLine(self.data, start=start_line) self.b_mirror = self.field_lines[localtime2].get_B_mirror_for_K(self.K) for lt in local_times: print "Processing Local Time: ", lt self.add_field_line_from_K(local_time=lt) if not self.field_lines[lt] is None: self.start_RE = ih.mag(self.field_lines[lt].startLoc) elif mode is 'location_b': print "Location (b_mirror) based mode" if start_line is None or b_mirror is None: print "ERROR: start_line and b_mirror are both required in this mode" sys.exit() self.start_location = start_line self.start_RE = ih.mag(start_line) self.b_mirror = b_mirror self.field_lines = col.OrderedDict() localtime2 = ih.get_local_time_from_location(start_line) self.field_lines[localtime2] = fl.fieldLine(self.data, start=start_line) self.K = self.field_lines[localtime2].get_K(self.b_mirror) for lt in local_times: print "Processing Local Time: ", lt self.add_field_line_from_K(local_time=lt) if not self.field_lines[lt] is None: self.start_RE = ih.mag(self.field_lines[lt].startLoc) elif mode is 'K': print "K search based mode" if K is None or b_mirror is None or local_times is None: print "ERROR: local_times, K, and b_mirror are all required in this mode" sys.exit() self.start_RE = 5.0 self.b_mirror = b_mirror self.K = K self.field_lines = col.OrderedDict() for lt in local_times: print "Processing Local Time: ", lt self.add_field_line_from_K(local_time=lt) if not self.field_lines[lt] is None: self.start_RE = ih.mag(self.field_lines[lt].startLoc) elif mode is 'analytic_K': print "Analytic (K) based mode" self.analytic = True if start_line is None or K is None: print "ERROR: start_line and K are both required in this mode" sys.exit() self.start_location = start_line self.start_RE = ih.mag(start_line) self.K = K self.field_lines = col.OrderedDict() localtime2 = ih.get_local_time_from_location(start_line) self.field_lines[localtime2] = fl.fieldLine(start=start_line, error_tol=self.error_tol) self.b_mirror = self.field_lines[localtime2].get_B_mirror_for_K(self.K) for lt in local_times: print "Processing Local Time: ", lt self.add_field_line_from_K(local_time=lt) if not self.field_lines[lt] is None: self.start_RE = ih.mag(self.field_lines[lt].startLoc) else: print "Mode ", mode, " is not understood. Exiting." sys.exit()
def get_location_for_RE(self, RE): """ Return the coordinates on the Line where it crosses the given RE distance from Earth. Returns None if no such crossing occurs. :param RE: Distance (in RE) for where we want the coordinates on the line. :return: list of x,y,z coordinates for where the line crosses the RE distance specified. None otherwise. """ # Get the line in RE format RE_f = [ih.mag(x) for x in self.fieldLinePoints_f] #if was registerd as bifrucated, we have to do a little extra work if self.is_bifurcated: print "Caution: This line is registering as bifurcated.\nAttempting to find the intersection point" print "monotonically decreasing test: {}".format(ih.mon_dec(RE_f)) if not ih.mon_dec(RE_f): print "Need to adjust trace" print "exporting Data Dump" pos = np.asarray(self.fieldLinePoints_f) dat = np.asarray(self.fieldLineData_f) dpos = np.diff(self.fieldLinePoints_f, axis=0) ddat = np.diff(self.fieldLineData_f, axis=0) np.savetxt("errors/pos_{}.csv".format(self.startLoc), pos, delimiter=",") np.savetxt("errors/dat_{}.csv".format(self.startLoc), dat, delimiter=",") np.savetxt("errors/dpos_{}.csv".format(self.startLoc), dpos, delimiter=",") np.savetxt("errors/ddat_{}.csv".format(self.startLoc), dpos, delimiter=",") ind_f = None loc_f = None # reverse the list RE_f.reverse() if RE < RE_f[0] or RE > RE_f[-1]: print "Out of bounds:" print "RE: ", RE print "RE_f: ", RE_f[0], ":", RE_f[-1] else: ind_f = bs.bisect_left(RE_f, RE) # print "Index: ", ind_f bound_f = vb.valBounds( lowerVal=RE_f[ind_f - 1], lowerLoc=self.fieldLinePoints_f[-ind_f], upperVal=RE_f[ind_f], upperLoc=self.fieldLinePoints_f[-(ind_f + 1)]) wa = 0.0 loc_f = bound_f.get_location(RE, weight_adjust=wa) loc_RE = ih.mag(loc_f) # TODO: make this a percentage... or don't do it at all, as this can cause an infinite loop like behaviour. # while not np.isclose(loc_RE, RE): # if loc_RE < RE: # wa += 0.0001 # loc_f = bound_f.get_location(RE, weight_adjust=wa) # loc_RE = ih.mag(loc_f) # print "Adjusting: ", wa, # print "new RE: ", loc_RE # # if loc_RE > RE: # wa -= 0.0001 # loc_f = bound_f.get_location(RE, weight_adjust=wa) # loc_RE = ih.mag(loc_f) # print "Adjusting: ", wa, # print "new RE: ", loc_RE # print "Location for ", RE, " RE: ",loc_f # print "Verification: ", RE, " = ", ih.mag(loc_f) # TODO: calculate and return the backward location as well. (if needed) return loc_f
def get_b_mag_backward(self): return [ih.mag(x) for x in self.fieldLineData_b]
def get_b_mag_values(self): """ returns a list of discreete b_mag values in the field trace :return: list containing [|B|] contained in trace. """ return [ih.mag(x) for x in self.fieldLineData_f]