|
| 1 | +import numpy as np |
| 2 | +from .colradpy_class import colradpy |
| 3 | +from .solve_matrix_exponential import * |
| 4 | + |
| 5 | +class ionization_balance(): |
| 6 | + |
| 7 | + def __init__(self,fils,metas,temp_grid, dens_grid,use_ionization=True, |
| 8 | + suppliment_with_ecip=True, use_recombination_three_body=True,use_recombination=True, |
| 9 | + keep_species_data=False): |
| 10 | + |
| 11 | + """ Sets up the dictionaries to hold the data. |
| 12 | + |
| 13 | + """ |
| 14 | + self.data = {} |
| 15 | + self.data['gcrs'] = {} |
| 16 | + |
| 17 | + self.data['user'] = {} |
| 18 | + self.data['user']['temp_grid'] = np.asarray(temp_grid) #eV |
| 19 | + self.data['user']['dens_grid'] = np.asarray(dens_grid)#cm-3 |
| 20 | + self.data['user']['use_ionization'] = use_ionization |
| 21 | + self.data['user']['suppliment_with_ecip'] = suppliment_with_ecip |
| 22 | + self.data['user']['use_recombination_three_body'] = use_recombination_three_body |
| 23 | + self.data['user']['use_recombination'] = use_recombination |
| 24 | + self.data['user']['keep_species_data'] = keep_species_data |
| 25 | + |
| 26 | + #default is to not keep all of the data from the CR calculations |
| 27 | + #this can take up a lot of memory and the general use case for this class only |
| 28 | + #calls for the use of GCR coefficients so its kind of a waste to keep all the data |
| 29 | + if(keep_species_data): |
| 30 | + self.data['stage_data'] = {} |
| 31 | + #cycle over all of the ion stages that the user chose and run the CR calculation |
| 32 | + #to get the GCR coefficients for that stage |
| 33 | + for i in range(0,len(fils)): |
| 34 | + #default is for user to just give metastables of the ground state and then |
| 35 | + #choose metastables just based off of ionization potentials in adf04 file |
| 36 | + #the user can also give a list of metastable states for every ionstage |
| 37 | + #and this will override the metastables in the adf04 files |
| 38 | + if(type(metas) == list): |
| 39 | + meta = metas[i] |
| 40 | + else: |
| 41 | + if(i == 0): |
| 42 | + meta = metas |
| 43 | + else: |
| 44 | + m = np.shape(self.data['gcrs'][str(i -1)]['scd'])[1] |
| 45 | + meta = np.linspace(0,m-1,m,dtype=int) |
| 46 | + #setup the CR |
| 47 | + |
| 48 | + tmp = colradpy(str(fils[i]),meta,temp_grid,dens_grid,use_ionization, |
| 49 | + suppliment_with_ecip,use_recombination_three_body,use_recombination) |
| 50 | + tmp.solve_cr() |
| 51 | + #keep the data if requested |
| 52 | + if(keep_species_data): |
| 53 | + self.data['stage_data'][str(i)] = tmp.data |
| 54 | + #keeping all of the GCR data, ionization can be run from this data only |
| 55 | + self.data['gcrs'][str(i)] = {} |
| 56 | + self.data['gcrs'][str(i)]['qcd'] = tmp.data['processed']['qcd'] |
| 57 | + self.data['gcrs'][str(i)]['scd'] = tmp.data['processed']['scd'] |
| 58 | + self.data['gcrs'][str(i)]['acd'] = tmp.data['processed']['acd'] |
| 59 | + self.data['gcrs'][str(i)]['xcd'] = tmp.data['processed']['xcd'] |
| 60 | + |
| 61 | + def populate_ion_matrix(self): |
| 62 | + """This will populate the ionization matrix from the various GCR coefficients |
| 63 | + for all of the ionization stages |
| 64 | + |
| 65 | + This matrix in mostly zeros because we don't have ways to connect charge states |
| 66 | + that are more than one change away. For example if only ground states are included |
| 67 | + this matrix becomes diagonal. |
| 68 | +
|
| 69 | + QCDs bring the atom between metastables states in a charge state |
| 70 | + SCDS bring the atom to the next charge state |
| 71 | + ACDS bring the atom to the previous charge state |
| 72 | + XCDS bring the atom to next charge state between the metastables of that level, |
| 73 | + through the previous charge state |
| 74 | +
|
| 75 | + The columns of this matrix sum to zero |
| 76 | + """ |
| 77 | + #finding the total number of states to be tracked (metastables) |
| 78 | + m = np.shape(self.data['gcrs']['0']['qcd'])[0]#num metastables in ground |
| 79 | + m = m + np.shape(self.data['gcrs']['0']['scd'])[1]#num metastables in plus |
| 80 | + |
| 81 | + for i in range(1,len(self.data['gcrs'])): |
| 82 | + m = m + np.shape(self.data['gcrs'][str(i)]['scd'])[1]#num of metastales in the plus loop |
| 83 | + #create an empty matrix to hold the GCR rates |
| 84 | + self.data['ion_matrix'] = np.zeros((m, m,len(self.data['user']['temp_grid']), len(self.data['user']['dens_grid']))) |
| 85 | + |
| 86 | + m = 0 |
| 87 | + for i in range(0,len(self.data['gcrs'])): |
| 88 | + num_met = np.shape(self.data['gcrs'][str(i)]['qcd'])[0] |
| 89 | + num_ion = np.shape(self.data['gcrs'][str(i)]['scd'])[1] |
| 90 | + diag_met = np.diag_indices(num_met) |
| 91 | + diag_ion = np.diag_indices(num_ion) |
| 92 | + |
| 93 | + #populate QCDs in ion balance |
| 94 | + self.data['ion_matrix'][m+diag_met[0],m+diag_met[1]] = self.data['ion_matrix'][m+diag_met[0],m+diag_met[1]] \ |
| 95 | + -np.sum(self.data['gcrs'][str(i)]['qcd'],axis=1) |
| 96 | + |
| 97 | + self.data['ion_matrix'][m:m+num_met,m:m+num_met,:,:]=self.data['ion_matrix'][m:m+num_met,m:m+num_met,:,:]\ |
| 98 | + +self.data['gcrs'][str(i)]['qcd'].transpose(1,0,2,3) |
| 99 | + |
| 100 | + #populate SCDs in ion balance |
| 101 | + self.data['ion_matrix'][m+diag_met[0],m+diag_met[1]] = self.data['ion_matrix'][m+diag_met[0],m+diag_met[1]]\ |
| 102 | + -np.sum(self.data['gcrs'][str(i)]['scd'],axis=1) |
| 103 | + |
| 104 | + self.data['ion_matrix'][m+num_met:m+num_met+num_ion,m:m+num_met,:,:] = \ |
| 105 | + self.data['ion_matrix'][m+num_met:m+num_met+num_ion,m:m+num_met,:,:] \ |
| 106 | + +self.data['gcrs'][str(i)]['scd'].transpose(1,0,2,3) |
| 107 | + |
| 108 | + #populate ACDs in ion balance |
| 109 | + self.data['ion_matrix'][m+num_met+diag_ion[0], m+num_met+diag_ion[1] ] = \ |
| 110 | + self.data['ion_matrix'][m+num_met+diag_ion[0], m+num_met+diag_ion[1] ]-\ |
| 111 | + np.sum(self.data['gcrs'][str(i)]['acd'],axis=0) |
| 112 | + |
| 113 | + self.data['ion_matrix'][m:m+num_met,m+num_met:m+num_met+num_ion,:,:] = \ |
| 114 | + self.data['ion_matrix'][m:m+num_met,m+num_met:m+num_met+num_ion,:,:] \ |
| 115 | + + self.data['gcrs'][str(i)]['acd'] |
| 116 | + |
| 117 | + #populate XCD in ion balance |
| 118 | + self.data['ion_matrix'][m+num_met+diag_ion[0], m+num_met+diag_ion[1] ] = \ |
| 119 | + self.data['ion_matrix'][m+num_met+diag_ion[0], m+num_met+diag_ion[1] ]-\ |
| 120 | + np.sum(self.data['gcrs'][str(i)]['xcd'],axis=1) |
| 121 | + |
| 122 | + self.data['ion_matrix'][m+num_met:m+num_met+num_ion,m+num_met:m+num_met+num_ion,:,:]=\ |
| 123 | + self.data['ion_matrix'][m+num_met:m+num_met+num_ion,m+num_met:m+num_met+num_ion,:,:] + \ |
| 124 | + self.data['gcrs'][str(i)]['xcd'].transpose(1,0,2,3) |
| 125 | + |
| 126 | + m = m + num_met |
| 127 | + #self.data['ion_matrix'][m+num_met:m+num_met+num_ion,m:m+num_met,:,:]\ |
| 128 | + |
| 129 | + def solve_no_source(self,n0,td_t): |
| 130 | + """Solves the ionization balance matrix given an initial populations and times |
| 131 | +
|
| 132 | + :param n0: The initial populations of levels at t=0 |
| 133 | + :type n0: float array |
| 134 | +
|
| 135 | + :param td_t: Solution times |
| 136 | + :type td_t: float array |
| 137 | +
|
| 138 | +
|
| 139 | + populates the pops, eigen_val and eigen_vec |
| 140 | + |
| 141 | + """ |
| 142 | + self.data['pops'],self.data['eigen_val'],self.data['eigen_vec'] = solve_matrix_exponential( |
| 143 | + np.einsum('ijkl,l->ijkl',self.data['ion_matrix'],self.data['user']['dens_grid']),n0,td_t) |
| 144 | + |
| 145 | + def solve_source(self,n0,s0,td_t): |
| 146 | + """Solves the ionization balance matrix given an initial populations and times when a source term is present |
| 147 | +
|
| 148 | + :param n0: The initial populations of levels at t=0 |
| 149 | + :type n0: float array |
| 150 | +
|
| 151 | + :param td_t: Solution times |
| 152 | + :type td_t: float array |
| 153 | +
|
| 154 | +
|
| 155 | + populates the pops, eigen_val and eigen_vec |
| 156 | + |
| 157 | + """ |
| 158 | + self.data['pops'],self.data['eigen_val'],self.data['eigen_vec'] = solve_matrix_exponential_source( |
| 159 | + np.einsum('ijkl,l->ijkl',self.data['ion_matrix'],self.data['user']['dens_grid']),n0,s0,td_t) |
| 160 | + |
0 commit comments