From 64c3f436dc5c25f84b7cb84110de703b205fa403 Mon Sep 17 00:00:00 2001 From: zhaosen <tokyosenzhao@163.com> Date: Sat, 5 Oct 2024 19:16:48 +0800 Subject: [PATCH] half of gen_signal --- current/cal_current.py | 2 +- current/model.py | 2 +- field/build_device.py | 1 + field/devsim_field.py | 131 +++++++++++++++++----------------- field/save_milestone.py | 15 ++-- field/solver_section.py | 12 ++-- gen_signal/draw_save.py | 3 +- gen_signal/gen_signal_main.py | 14 ++-- particle/carrier_list.py | 12 ++-- 9 files changed, 98 insertions(+), 94 deletions(-) diff --git a/current/cal_current.py b/current/cal_current.py index 6f947e6..c6948a2 100644 --- a/current/cal_current.py +++ b/current/cal_current.py @@ -20,7 +20,7 @@ from particle.carrier_list import CarrierListFromG4P, StripCarrierListFromG4P from util.math import Vector, signal_convolution from util.output import create_path -t_bin = 50e-12 +t_bin = 100e-12 t_end = 10e-9 t_start = 0 delta_t = 10e-12 diff --git a/current/model.py b/current/model.py index 5845768..49ac8f7 100644 --- a/current/model.py +++ b/current/model.py @@ -30,7 +30,7 @@ class Material: self.hole_mass = 0.386*m_e self.electron_mass = 0.26*m_e self.avalanche_model = "vanOverstraeten" - self.mobility_model = 'Reggiani' + self.mobility_model = 'Selberherr' if self.mat_name == "SiC": # 4H-SiC, use the longitudinal effective mass self.permittivity=9.76 diff --git a/field/build_device.py b/field/build_device.py index 56276a5..b684f01 100644 --- a/field/build_device.py +++ b/field/build_device.py @@ -50,6 +50,7 @@ class Detector: self.absorber = self.device_dict['absorber'] self.amplifier = self.device_dict['amplifier'] + self.read_out_contact = self.device_dict["read_out_contact"] if "lgad3D" in self.det_model: self.avalanche_bond = self.device_dict['avalanche_bond'] diff --git a/field/devsim_field.py b/field/devsim_field.py index 679b6f1..f3f25d6 100644 --- a/field/devsim_field.py +++ b/field/devsim_field.py @@ -6,7 +6,12 @@ @Author : Henry Stone @Version : 1.0 ''' - +""" +@File : Field_to_G4.py +@Time : 2024/09/30 +@Author : Sen Zhao +@Version : 2.0 +""" import pickle import ROOT import numpy as np @@ -16,23 +21,24 @@ from util.math import * diff_res = 1e-5 # difference resolution in cm class DevsimField: - def __init__(self, device_name, dimension, voltage, read_ele_num, l_z): + def __init__(self, device_name, dimension, voltage, contact,read_ele_num): self.name = device_name self.voltage = voltage # float self.dimension = dimension self.read_ele_num = int(read_ele_num) - self.l_z = l_z # used for planar weighting field TODO: auto weighting field - DopingFile = "./output/field/{}/NetDoping_0.0V.pkl".format(self.name) + + + DopingFile = "./output/field/{}/NetDoping_0V.pkl".format(self.name) PotentialFile = "./output/field/{}/Potential_{}V.pkl".format(self.name, self.voltage) TrappingRate_pFile = "./output/field/{}/TrappingRate_p_{}V.pkl".format(self.name, self.voltage) TrappingRate_nFile = "./output/field/{}/TrappingRate_n_{}V.pkl".format(self.name, self.voltage) - + Weighting_Potential = "./output/field/{}/weightingfield/{}/Potential_{}V.pkl".format(self.name,contact, 1) self.set_doping(DopingFile) #self.Doping self.set_potential(PotentialFile) #self.Potential, self.x_efield, self.y_efield, self.z_efield self.set_trap_p(TrappingRate_pFile) # self.TrappingRate_p self.set_trap_n(TrappingRate_nFile) # self.TrappingRate_n - self.set_w_p() #self.weighting_potential[] + self.set_w_p(Weighting_Potential) #self.weighting_potential[] def set_doping(self, DopingFile): try: @@ -78,18 +84,30 @@ class DevsimField: self.Potential = PotentialUniform - def set_w_p(self): - self.WeightingPotentials = [] #length = ele_num - if self.read_ele_num == 1: - print("Linear weighting potential loaded") - pass - elif self.read_ele_num >= 2: - for i in range(self.read_ele_num): - self.WeightingPotentials.append(strip_w_p(i)) - print("Weighting potential loaded for {}, strip {}".format(self.name, i+1)) - else: - raise ValueError(self.read_ele_num) + def set_w_p(self,Weighting_PotentialFile): + try: + with open(Weighting_PotentialFile,'rb') as file: + Weighting_PotentialNotUniform=pickle.load(file) + print("Weighting_Potential file loaded for {}".format(self.name)) + if Weighting_PotentialNotUniform['metadata']['dimension'] < self.dimension: + print("Weighting_Potential dimension not match") + return + except FileNotFoundError: + print("Weighting_Potential file not found, please run field simulation first") + print("or manually set the Weighting_Potential file") + return + + if Weighting_PotentialNotUniform['metadata']['dimension'] == 1: + weighting_PotentialUniform = get_common_interpolate_1d(Weighting_PotentialNotUniform) + elif Weighting_PotentialNotUniform['metadata']['dimension'] == 2: + weighting_PotentialUniform = get_common_interpolate_2d(Weighting_PotentialNotUniform) + elif Weighting_PotentialNotUniform['metadata']['dimension'] == 3: + weighting_PotentialUniform = get_common_interpolate_3d(Weighting_PotentialNotUniform) + + self.weighting_Potential = weighting_PotentialUniform + + def set_trap_p(self, TrappingRate_pFile): try: with open(TrappingRate_pFile,'rb') as file: @@ -134,6 +152,7 @@ class DevsimField: self.TrappingRate_n = TrappingRate_nUniform + # DEVSIM dimension order: x, y, z # RASER dimension order: z, x, y @@ -203,7 +222,23 @@ class DevsimField: E_x = - ((self.Potential(z, x) - self.Potential(z, x-diff_res))) / diff_res except ValueError: raise ValueError("Point {} might be out of bound x".format(x)) - return (E_x, 0, E_z) + try: + E_y = - ((self.Potential(z, x+diff_res/2) - self.Potential(z, x-diff_res/2))) / diff_res + except ValueError: + try: + E_y = - ((self.Potential(z, x+diff_res) - self.Potential(z, x))) / diff_res + except ValueError: + try: + E_y = - ((self.Potential(z, x) - self.Potential(z, x-diff_res))) / diff_res + except ValueError: + raise ValueError("Point {} might be out of bound x".format(y)) + try: + return (E_x, 0, E_z) + except AttributeError: + try: + return (E_x,E_y,0) + except AttributeError: + return (0,E_y,E_z) elif self.dimension == 3: try: @@ -238,15 +273,15 @@ class DevsimField: raise ValueError("Point {} might be out of bound y".format(y)) return (E_x, E_y, E_z) - def get_w_p(self, x, y, z, i): - ''' - input: position in um - output: weighting potential in 1 - ''' - if self.read_ele_num == 1: - return linear_w_p(z, self.l_z) - elif self.read_ele_num > 1: - return self.WeightingPotentials[i].Interpolate(z, x) + def get_w_p(self, x, y, z,i): # used in cal current + x, y, z = x/1e4, y/1e4, z/1e4 # um to cm + if self.dimension == 1: + return self.weighting_Potential(z) + elif self.dimension == 2: + return self.weighting_Potential(z, x) + elif self.dimension == 3: + return self.weighting_Potential(z, x, y) + def get_trap_e(self, x, y, z): ''' @@ -256,8 +291,10 @@ class DevsimField: x, y, z = x/1e4, y/1e4, z/1e4 # um to cm if self.dimension == 1: return self.TrappingRate_n(z) + elif self.dimension == 2: return self.TrappingRate_n(z, x) + elif self.dimension == 3: return self.TrappingRate_n(z, x, y) @@ -275,46 +312,6 @@ class DevsimField: return self.TrappingRate_p(z, x, y) -def linear_w_p(z, l_z): - if z >= l_z: - w_potential = 0 - elif z >= 1: - w_potential = 1 - (1/(l_z-1)) * (z-1) - else: - w_potential = 1 - return w_potential - -def strip_w_p(ele_number): - nx = 51 - ny = 321 - xmin, xmax = 0.0, 50.0 - ymin, ymax = 0.0, 320.0 - dx = (xmax - xmin) / (nx - 1) - dy = (ymax - ymin) / (ny - 1) - - u = np.zeros((ny, nx)) - u[ele_number*75:(ele_number*75+20), 0] = 1.0 - u[:, -1] = 0.0 - - max_iter = 100000 - tolerance = 1e-6 - for iteration in range(max_iter): - u_old = u.copy() - for i in range(1, ny - 1): - for j in range(1, nx - 1): - u[i, j] = (u[i+1, j] + u[i-1, j] + u[i, j+1] + u[i, j-1]) / 4 - diff = np.abs(u - u_old).max() - if diff < tolerance: - break - - x = np.linspace(xmin, xmax, nx) - y = np.linspace(ymin, ymax, ny) - w_potential=ROOT.TGraph2D() - for i in range(len(y)): - for j in range(len(x)): - w_potential.SetPoint(int(i*len(x)+j),x[j]*6,y[i],u[i][j]) - return w_potential - if __name__ == "__main__": testField = DevsimField("ITk-Si-strip", 2, -500.0, 4) print(testField.get_e_field(100,100,50)) \ No newline at end of file diff --git a/field/save_milestone.py b/field/save_milestone.py index ed547d4..340372c 100644 --- a/field/save_milestone.py +++ b/field/save_milestone.py @@ -49,6 +49,7 @@ def milestone_save_2D(device, region, v, path): Potential = np.array(devsim.get_node_model_values(device=device, region=region, name="Potential")) # get the potential data TrappingRate_n = np.array(devsim.get_node_model_values(device=device, region=region, name="TrappingRate_n")) TrappingRate_p = np.array(devsim.get_node_model_values(device=device, region=region, name="TrappingRate_p")) + NetDoping= np.array(devsim.get_node_model_values(device=device, region=region, name="NetDoping")) devsim.element_from_edge_model(edge_model="ElectricField", device=device, region=region) devsim.edge_average_model(device=device, region=region, node_model="x", edge_model="xmid") @@ -70,8 +71,8 @@ def milestone_save_2D(device, region, v, path): metadata['dimension'] = 2 names = ['Potential', 'TrappingRate_p', 'TrappingRate_n'] - # if v == 0: - # names.append('NetDoping') + if v == 0: + names.append('NetDoping') for name in names: # scalar field on mesh point (instead of on edge) with open(os.path.join(path, "{}_{}V.pkl".format(name,v)),'wb') as file: @@ -105,9 +106,9 @@ def milestone_save_wf_2D(device, region, v, path,contact): metadata = {} metadata['voltage'] = v metadata['dimension'] = 2 - + save_wf_path = os.path.join(path,contact) for name in ['Potential']: # scalar field on mesh point (instead of on edge) - with open(os.path.join(path, "{}_{}_{}V.pkl".format(name,v,contact)),'wb') as file: + with open(os.path.join(save_wf_path, "{}_{}V.pkl".format(name,v)),'wb') as file: data = {} data['values'] = eval(name) # refer to the object with given name merged_list = [x, y] @@ -122,7 +123,7 @@ def milestone_save_3D(device, region, v, path): Potential = np.array(devsim.get_node_model_values(device=device, region=region, name="Potential")) # get the potential data TrappingRate_n = np.array(devsim.get_node_model_values(device=device, region=region, name="TrappingRate_n")) TrappingRate_p = np.array(devsim.get_node_model_values(device=device, region=region, name="TrappingRate_p")) - + NetDoping= np.array(devsim.get_node_model_values(device=device, region=region, name="NetDoping")) devsim.element_from_edge_model(edge_model="ElectricField", device=device, region=region) devsim.edge_average_model(device=device, region=region, node_model="x", edge_model="xmid") devsim.edge_average_model(device=device, region=region, node_model="y", edge_model="ymid") @@ -143,8 +144,8 @@ def milestone_save_3D(device, region, v, path): metadata['dimension'] = 2 names = ['Potential', 'TrappingRate_p', 'TrappingRate_n'] - # if v == 0: - # names.append('NetDoping') + if v == 0: + names.append('NetDoping') for name in names: # scalar field on mesh point (instead of on edge) with open(os.path.join(path, "{}_{}V.pkl".format(name,v)),'wb') as file: diff --git a/field/solver_section.py b/field/solver_section.py index 3bea26c..99d275b 100644 --- a/field/solver_section.py +++ b/field/solver_section.py @@ -195,7 +195,9 @@ def main (kwargs): v_current=1 print("=======RASER info========\nBegin simulation WeightingField\n======================") for contact in circuit_contacts: - folder_path = os.path.join(path,"/weghtingfield/{}_{}_device".format(contact,v_current)) + print(path) + folder_path = os.path.join(path, "weightingfield") + print(folder_path) if not os.path.exists(folder_path): os.makedirs(folder_path) @@ -205,10 +207,10 @@ def main (kwargs): value=0.0, acreal=paras['acreal'], acimag=paras['acimag']) loop.initial_solver(contact=contact,set_contact_type=None,irradiation_label=irradiation_label,irradiation_flux=irradiation_flux,impact_label=impact_label) - loop.loop_solver(circuit_contact=contact,v_current=v_current,area_factor=paras["area_factor"],path=path,device=device,region=region) - if(paras['milestone_mode']==True and v_current%paras['milestone_step']==0.0): - save_milestone.save_milestone(device=device, region=region, v=v_current, path=path,dimension=default_dimension,contact=contact,is_wf=is_wf) - devsim.write_devices(file=os.path.join(folder_path,"weightingfield.dat"), type="tecplot") + loop.loop_solver(circuit_contact=contact,v_current=v_current,area_factor=paras["area_factor"],path=folder_path,device=device,region=region) + + save_milestone.save_milestone(device=device, region=region, v=v_current, path=folder_path,dimension=default_dimension,contact=contact,is_wf=is_wf) + devsim.write_devices(file=os.path.join(folder_path,"weightingfield.dat"), type="tecplot") elif is_wf == False: v_current = 0 loop.initial_solver(contact=circuit_contacts,set_contact_type=None,irradiation_label=irradiation_label,irradiation_flux=irradiation_flux,impact_label=impact_label) diff --git a/gen_signal/draw_save.py b/gen_signal/draw_save.py index 06b38d5..e7e97a4 100644 --- a/gen_signal/draw_save.py +++ b/gen_signal/draw_save.py @@ -226,6 +226,7 @@ def draw_current(my_d, my_current, ele_current, read_ele_num, model, path, tag=" if ele_current[read_ele_num].GetMinimum() < 0: rightmax = 1.1*ele_current[read_ele_num].GetMinimum() + else: rightmax = 1.1*ele_current[read_ele_num].GetMaximum() if rightmax == 0: @@ -282,7 +283,7 @@ def cce(my_d,my_f,my_current, path): for j in range(my_current.n_bin): sum_charge=sum_charge+my_current.sum_cu[i].GetBinContent(j)*my_current.t_bin charge.append(sum_charge/1.6e-19) - print(charge) + print("===========RASER info================\nCollected Charge is {} C\n==============Result==============".format(list(charge))) n=int(len(charge)) c1=ROOT.TCanvas("c1","canvas1",1000,1000) cce=ROOT.TGraph(n,x,charge) diff --git a/gen_signal/gen_signal_main.py b/gen_signal/gen_signal_main.py index b015b18..aaab285 100644 --- a/gen_signal/gen_signal_main.py +++ b/gen_signal/gen_signal_main.py @@ -21,6 +21,7 @@ from elec import readout as rdo from elec import ngspice_set_input as ngsip from elec import ngspice as ng from elec.set_pwl_input import set_pwl_input as pwlin +import geant4_pybind as g4b from .draw_save import energy_deposition, draw_drift_path, draw_current, cce from util.output import output @@ -50,12 +51,11 @@ def main(kwargs): start = time.time() det_name = kwargs['det_name'] - my_d = bdv.Detector(det_name) - + my_d = bdv.Detector(det_name,devsim_solve_paras = None) if kwargs['voltage'] != None: - voltage = float(kwargs['voltage']) + voltage = str(kwargs['voltage']) else: - voltage = float(my_d.voltage) + voltage = str(my_d.voltage) if kwargs['absorber'] != None: absorber = kwargs['absorber'] @@ -67,12 +67,14 @@ def main(kwargs): else: amplifier = my_d.amplifier - my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage, my_d.read_ele_num, my_d.l_z) + contact = my_d.read_out_contact + + my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage,contact, my_d.read_ele_num) g4_seed = random.randint(0,1e7) my_g4p = g4t.Particles(my_d, absorber, g4_seed) - if "strip" in det_name: + if "strip——" in det_name: my_current = ccrt.CalCurrentStrip(my_d, my_f, my_g4p, 0) else: my_current = ccrt.CalCurrentG4P(my_d, my_f, my_g4p, 0) diff --git a/particle/carrier_list.py b/particle/carrier_list.py index 783ccc3..e6e30a4 100644 --- a/particle/carrier_list.py +++ b/particle/carrier_list.py @@ -33,11 +33,11 @@ class CarrierListFromG4P: if particle_number > 0: batch=1 - if batch == 0: - print("the sensor didn't have particles hitted") - raise ValueError - else: - self.batch_def(my_g4p,batch) + if batch == 0: + print("=========RASER info ===========\nGeant4:the sensor didn't have particles hitted\n==========================") + raise ValueError + else: + self.batch_def(my_g4p,batch) def batch_def(self,my_g4p,j): self.beam_number = j @@ -73,7 +73,7 @@ class StripCarrierListFromG4P: break if batch == 0: - print("the sensor didn't have particles hitted") + print("=========RASER info ===========\nGeant4:the sensor didn't have particles hitted\n==========================") raise ValueError else: self.batch_def(my_g4p,batch) -- GitLab