diff --git a/__main__.py b/__main__.py index 75b3acf88860e5c9032f5f78e3a578ff3ff48401..00b81dc1a736b7ccee38de73c6caee41c2dbaf50 100755 --- a/__main__.py +++ b/__main__.py @@ -43,6 +43,7 @@ parser_fpga.add_argument('label', help='LABEL to identify FPGA design') parser_gen_signal = subparsers.add_parser('gen_signal', help='generate signal') parser_gen_signal.add_argument('det_name', help='name of the detector') +parser_gen_signal.add_argument('-l','--label', help='LABEL to identify signal generation method', default='signal') parser_gen_signal.add_argument('-vol', '--voltage', type=str, help='bias voltage') parser_gen_signal.add_argument('-abs', '--absorber', type=str, help='model of particle energy absorber') parser_gen_signal.add_argument('-amp', '--amplifier', type=str, help='amplifier') diff --git a/control/kei_2400b_control.py b/control/kei_2400b_bias_control.py similarity index 100% rename from control/kei_2400b_control.py rename to control/kei_2400b_bias_control.py diff --git a/control/kei_2400c_control.py b/control/kei_2400c_bias_control.py similarity index 100% rename from control/kei_2400c_control.py rename to control/kei_2400c_bias_control.py diff --git a/control/keithley2470ccontrol_hyj.py b/control/kei_2470c_bias_control.py similarity index 100% rename from control/keithley2470ccontrol_hyj.py rename to control/kei_2470c_bias_control.py diff --git a/control/keye4980acontrol.py b/control/key_e4980a_bias_control.py similarity index 92% rename from control/keye4980acontrol.py rename to control/key_e4980a_bias_control.py index ac040eab10b9522f026d6eed5fe3959d791b0c12..bf3dc11142b171608b97db210406d23efe661c5b 100644 --- a/control/keye4980acontrol.py +++ b/control/key_e4980a_bias_control.py @@ -2,7 +2,7 @@ import pyvisa as visa import time import warnings -class keysighte4980a: +class keysight_e4980a: def __init__(self,resource_name): instlist=visa.ResourceManager() print(instlist.list_resources()) @@ -36,6 +36,6 @@ class keysighte4980a: return float(cap) if __name__=="__main__": - lcr=keysighte4980a("USB0::0x2A8D::0x2F01::MY46516486::INSTR") + lcr=keysight_e4980a("USB0::0x2A8D::0x2F01::MY46516486::INSTR") lcr.testIO() lcr.set_trigger_internal() diff --git a/control/mdo_3034_control.py b/control/mdo_3034_scope_control.py similarity index 100% rename from control/mdo_3034_control.py rename to control/mdo_3034_scope_control.py diff --git a/control/scan_amp.py b/control/scan_amp_2026.py similarity index 91% rename from control/scan_amp.py rename to control/scan_amp_2026.py index e8428c9107dd9c95917906096aff506c88ebc0bd..87b998f5965072259fd0ed8bafe2880c9bdb777d 100644 --- a/control/scan_amp.py +++ b/control/scan_amp_2026.py @@ -1,5 +1,5 @@ import raser.control.kei_2026_bias_control as kei2026 -import raser.control.tek_tds5054b_control as tds5054b +import raser.control.tek_tds5054b_scope_control as tds5054b import visa import time import pylab diff --git a/control/scan_cv_2470.py b/control/scan_cv_2470.py index 26f29a6e5e39dbd8c4afdbb7282af857002028a4..48e441425d646d65150d266e735b9f25d77718e4 100644 --- a/control/scan_cv_2470.py +++ b/control/scan_cv_2470.py @@ -1,5 +1,5 @@ -import keye4980acontrol -import keithley2470ccontrol_hyj as kei2470 +import raser.control.key_e4980a_bias_control as keye4980a +import raser.control.kei_2470c_bias_control as kei2470 import csv import numpy as np import platform @@ -23,7 +23,7 @@ if platform.python_version().startswith('2'): sys.exit() -lcr=keye4980acontrol.keysighte4980a("USB0::0x2A8D::0x2F01::MY46516486::INSTR") +lcr=keye4980a.keysight_e4980a("USB0::0x2A8D::0x2F01::MY46516486::INSTR") lcr.set_frequency("1kHz") lcr.set_voltage_level(0.1) diff --git a/control/scan_iv.py b/control/scan_iv_2400.py similarity index 90% rename from control/scan_iv.py rename to control/scan_iv_2400.py index 36e15f5702bf21c1b6c20c92ffcac13d15d4ea5c..9fc524c7af07e2a1e260dbb310f85d376513341e 100644 --- a/control/scan_iv.py +++ b/control/scan_iv_2400.py @@ -1,4 +1,4 @@ -import raser.control.Kei2400c_control as kei2400 +import raser.control.kei_2400c_bias_control as kei2400 import visa import time import pylab diff --git a/control/scan_strip_iv.py b/control/scan_iv_2400_strip.py similarity index 90% rename from control/scan_strip_iv.py rename to control/scan_iv_2400_strip.py index 7aec31aadb074ac391a60e0df397413b8937a4c4..9f7d1b6694983c88b38add774d17f760a9e349ad 100644 --- a/control/scan_strip_iv.py +++ b/control/scan_iv_2400_strip.py @@ -1,4 +1,4 @@ -import raser.control.kei_2400b_control as kei2400 +import raser.control.kei_2400b_bias_control as kei2400 import visa import time import pylab diff --git a/control/scaniv.py b/control/scan_iv_2470.py similarity index 93% rename from control/scaniv.py rename to control/scan_iv_2470.py index 56412f9969f37d676049bcab47b9102aff91fab8..a60d3e87d2cae17acea7c95aee838cb2d51dc40f 100644 --- a/control/scaniv.py +++ b/control/scan_iv_2470.py @@ -1,5 +1,5 @@ #import Kei2400CControl as kei2400 -import keithley2470ccontrol_hyj as kei2470 +import raser.control.kei_2470c_bias_control as kei2470 # import visa import pyvisa as visa import time diff --git a/control/tek_tds5054b_control.py b/control/tek_tds5054b_scope_control.py similarity index 100% rename from control/tek_tds5054b_control.py rename to control/tek_tds5054b_scope_control.py diff --git a/current/cal_current.py b/current/cal_current.py index 14b69df59d61afc58d93ce3b9b685493b841257e..92ad06e0c895870e3fc35a786df33a48528c48fb 100644 --- a/current/cal_current.py +++ b/current/cal_current.py @@ -16,14 +16,13 @@ import numpy as np import ROOT from .model import Material -from .model import Vector +from util.math import Vector from util.output import create_path t_bin = 50e-12 t_end = 10e-9 t_start = 0 delta_t = 10e-12 -pixel = 25 #um min_intensity = 1 # V/cm class Carrier: @@ -55,13 +54,9 @@ class Carrier: self.z = z_init self.t = t_init self.t_end = t_end - self.pixel = pixel self.path = [[x_init, y_init, z_init, t_init]] self.signal = [[] for j in range(int(read_ele_num))] self.end_condition = 0 - self.diffuse_end_condition = 0 - self.row=0 - self.column=0 self.cal_mobility = Material(material).cal_mobility self.charge = charge @@ -79,9 +74,7 @@ class Carrier: e_field = my_f.get_e_field(self.x,self.y,self.z) intensity = Vector(e_field[0],e_field[1],e_field[2]).get_length() mobility = Material(my_d.material) - #mu = mobility.cal_mobility(my_d.temperature, my_d.doping_function(self.z+delta_z), self.charge, average_intensity) - mu = mobility.cal_mobility(my_d.temperature, 1e12, self.charge, intensity) - # TODO: rebuild the doping function or admit this as an approximation + mu = mobility.cal_mobility(my_d.temperature, my_f.get_doping(self.x, self.y, self.z), self.charge, intensity) velocity_vector = [e_field[0]*mu, e_field[1]*mu, e_field[2]*mu] # cm/s if(intensity > min_intensity): @@ -163,80 +156,6 @@ class Carrier: elif (self.t > t_end): self.end_condition = "time out" return self.end_condition - - def diffuse_single_step(self,my_d,my_f): - delta_t=t_bin - #e_field = my_f.get_e_field(self.x,self.y,self.z) - intensity = 0 - - kboltz=8.617385e-5 #eV/K - mobility = Material(my_d.material) - mu = mobility.cal_mobility(my_d.temperature, my_d.doping_function(self.z), self.charge, intensity) - diffusion = (2.0*kboltz*mu*my_d.temperature*delta_t)**0.5 - #diffusion = 0.0 - dif_x=random.gauss(0.0,diffusion)*1e4 - dif_y=random.gauss(0.0,diffusion)*1e4 - dif_z=0 - - if((self.x+dif_x)>=my_d.l_x): - self.x = my_d.l_x - elif((self.x+dif_x)<0): - self.x = 0 - else: - self.x = self.x+dif_x - # y axis - if((self.y+dif_y)>=my_d.l_y): - self.y = my_d.l_y - elif((self.y+dif_y)<0): - self.y = 0 - else: - self.y = self.y+dif_y - # z axis - if((self.z+dif_z)>=my_d.l_z): - self.z = my_d.l_z - elif((self.z+dif_z)<0): - self.z = 0 - else: - self.z = self.z+dif_z - #time - self.t = self.t+delta_t - #record - self.path.append([self.x,self.y,self.z,self.t]) - - def diffuse_end(self,my_f): - if (self.z<=0): - # self.end_condition = "out of bound" - self.diffuse_end_condition = "collect" - return self.diffuse_end_condition - - def diffuse_not_in_sensor(self,my_d): - if (self.x<=0) or (self.x>=my_d.l_x)\ - or (self.y<=0) or (self.y>=my_d.l_y)\ - or (self.z>=my_d.l_z): - self.diffuse_end_condition = "out of bound" - mod_x = self.x % self.pixel - mod_y = self.y % self.pixel - if ((mod_x> 7.5) & (mod_x<17.5)) & ((mod_y> 7.5) & (mod_y<17.5)) \ - & (self.t <= self.t_end): - self.diffuse_end_condition = "collect" - return self.diffuse_end_condition - - ''' - if (self.z<= 0) or (self.t >= self.t_end): - self.diffuse_end_condition = "collect" - #print("diffuse end") - return self.diffuse_end_condition - ''' - - def pixel_position(self,my_f,my_d): - if self.diffuse_end_condition == "collect": - self.row = self.x // self.pixel - self.column = self.y // self.pixel - else: - self.row = -1 - self.column = -1 - return self.row,self.column,abs(self.charge) - class CalCurrent: @@ -557,108 +476,19 @@ class CalCurrentGain(CalCurrent): self.negative_cu[j].Add(test_n) test_n.Reset() + class CalCurrentG4P(CalCurrent): def __init__(self, my_d, my_f, my_g4p, batch): G4P_carrier_list = CarrierListFromG4P(my_d.material, my_g4p, batch) super().__init__(my_d, my_f, G4P_carrier_list.ionized_pairs, G4P_carrier_list.track_position) + class CalCurrentStrip(CalCurrent): def __init__(self, my_d, my_f, my_g4p, batch): G4P_carrier_list = StripCarrierListFromG4P(my_d.material, my_g4p, batch) super().__init__(my_d, my_f, G4P_carrier_list.ionized_pairs, G4P_carrier_list.track_position) -class CalCurrentPixel: - """Calculation of diffusion electrons in pixel detector""" - def __init__(self, my_d, my_f, my_g4p): - batch = len(my_g4p.localposition) - layer = len(my_d.lt_z) - G4P_carrier_list = PixelCarrierListFromG4P(my_d, my_g4p) - self.collected_charge=[] #temp paras don't save as self. - self.sum_signal = [] - self.event = [] - for k in range(batch): - l_dict = {} - signal_charge = [] - for j in range(layer): - self.electrons = [] - self.charge,self.collected_charge = [],[]#same like before - self.row,self.column=[],[] - Hit = {'index':[],'charge':[]} - #print(len(G4P_carrier_list.ionized_pairs[k][j])) - print("%f pairs of carriers are generated from G4 in event_ %d layer %d" %(sum(G4P_carrier_list.ionized_pairs[k][j]),k,j)) - #print(G4P_carrier_list.track_position[k][j]) - for i in range(len(G4P_carrier_list.track_position[k][j])): - electron = Carrier(G4P_carrier_list.track_position[k][j][i][0],\ - G4P_carrier_list.track_position[k][j][i][1],\ - G4P_carrier_list.track_position[k][j][i][2],\ - 0,\ - -1*G4P_carrier_list.ionized_pairs[k][j][i],\ - my_d.material,\ - 1) - if not electron.not_in_sensor(my_d): - self.electrons.append(electron) - self.diffuse_loop(my_d,my_f) - - Xbins=int(my_d.l_x // electron.pixel) - Ybins=int(my_d.l_y // electron.pixel) - Xup=my_d.l_x // electron.pixel - Yup=my_d.l_y // electron.pixel - test_charge = ROOT.TH2F("charge", "charge",Xbins, 0, Xup, Ybins, 0, Yup) - for i in range(len(self.row)): - #test_charge.SetBinContent(int(self.row[i]),int(self.column[i]),self.charge[i]) - test_charge.Fill(self.row[i],self.column[i],self.charge[i]) - - sum_fired = ROOT.TH2F("charge", "Pixel Detector charge",Xbins, 0, Xup, Ybins, 0, Yup) - sum_fired.Add(test_charge) - - self.sum_charge = ROOT.TH2F("charge", "Pixel Detector charge",Xbins, 0, Xup, Ybins, 0, Yup) - self.sum_charge.Add(test_charge) - - test_charge.Reset - collected_charge=self.pixel_charge(my_d,Xbins,Ybins) - signal_charge.append(collected_charge) - - Hit["index"],Hit["charge"] = self.pixel_fired(sum_fired,Xbins,Ybins) - l_dict[j] = Hit - print("%f electrons are collected in event_ %d,layer %d" %(sum(self.charge),k,j)) - self.sum_signal.append(signal_charge) - self.event.append(l_dict) - #print(signal_charge) - del signal_charge - #print(self.sum_signal) - #print(self.event) - - def diffuse_loop(self, my_d, my_f): - for electron in self.electrons: - while not electron.diffuse_not_in_sensor(my_d): - electron.diffuse_single_step(my_d, my_f) - electron.diffuse_end(my_f) - x,y,charge_quantity = electron.pixel_position(my_f,my_d) - if (x != -1)&(y != -1): - self.row.append(x) - self.column.append(y) - self.charge.append(charge_quantity) - - def pixel_charge(self,my_d,Xbins,Ybins): - for x in range(Xbins): - for y in range(Ybins): - charge =self.sum_charge.GetBinContent(x,y) - if (charge>0.2): - self.collected_charge.append([x,y,charge]) - return self.collected_charge - - def pixel_fired(self,tot,Xbins,Ybins): - Hit = {'index':[],'charge':[]} - for x in range(Xbins): - for y in range(Ybins): - charge =tot.GetBinContent(x,y) - if (charge>0.2): - Hit["index"].append([x,y]) - Hit["charge"].append(charge) - return Hit["index"],Hit["charge"] - - class CalCurrentLaser(CalCurrent): def __init__(self, my_d, my_f, my_l): super().__init__(my_d, my_f, my_l.ionized_pairs, my_l.track_position) @@ -750,65 +580,6 @@ class CarrierListFromG4P: self.tracks_t_energy_deposition = my_g4p.edep_devices[j] #涓轰粈涔堜笉浣跨敤锛� self.ionized_pairs = [step*1e6/self.energy_loss for step in self.tracks_step] -class PixelCarrierListFromG4P: - def __init__(self, my_d,my_g4p): - """ - Description: - Events position and energy depositon - Parameters: - material : string - deciding the energy loss of MIP - my_g4p : Particles - batch : int - batch = 0: Single event, select particle with long enough track - batch != 0: Multi event, assign particle with batch number - Modify: - 2022/10/25 - """ - batch = len(my_g4p.localposition) - layer = len(my_d.lt_z) - material = my_d.material - self.pixelsize_x = my_d.p_x - self.pixelsize_y = my_d.p_y - self.pixelsize_z = my_d.p_z - - if (material == "SiC"): - self.energy_loss = 8.4 #ev - elif (material == "Si"): - self.energy_loss = 3.6 #ev - - self.track_position, self.ionized_pairs= [],[] - self.layer= layer - for j in range(batch): - self.single_event(my_g4p,j) - - def single_event(self,my_g4p,j): - s_track_position,s_energy= [],[] - for i in range(self.layer): - position = [] - energy = [] - name = "Layer_"+str(i) - #print(name) - for k in range(len(my_g4p.devicenames[j])): - px,py,pz = self.split_name(my_g4p.devicenames[j][k]) - if name in my_g4p.devicenames[j][k]: - tp = [0 for i in range(3)] - tp[0] = my_g4p.localposition[j][k][0]+(px-0.5)*self.pixelsize_x - tp[1] = my_g4p.localposition[j][k][1]+(py-0.5)*self.pixelsize_y - tp[2] = my_g4p.localposition[j][k][2]+self.pixelsize_z/2 - position.append(tp) - energy.append(my_g4p.energy_steps[j][k]) - s_track_position.append(position) - pairs = [step*1e6/self.energy_loss for step in energy] - s_energy.append(pairs) - del position,energy - self.track_position.append(s_track_position) - self.ionized_pairs.append(s_energy) - - def split_name(self,volume_name): - parts = volume_name.split('_') - return int(parts[1]),int(parts[2]),int(parts[4]) - class StripCarrierListFromG4P: def __init__(self, material, my_g4p, batch): diff --git a/current/cal_current_diffuse.py b/current/cal_current_diffuse.py new file mode 100644 index 0000000000000000000000000000000000000000..4a6368c2ca31d97c6c422fc888d29f08669821c5 --- /dev/null +++ b/current/cal_current_diffuse.py @@ -0,0 +1,289 @@ +# -*- encoding: utf-8 -*- + +''' +Description: + Simulate e-h pairs diffusing and calculate induced current in MAPS +@Date : 2021/09/02 14:01:46 +@Author : Yuhang Tan, Haobo Wang +@version : 2.0 +''' + +import random +import math +import os + +import numpy as np +import ROOT + +from .model import Material +from util.math import Vector + +t_bin = 50e-12 +t_end = 10e-9 +t_start = 0 +delta_t = 10e-12 +pixel = 25 #um +min_intensity = 1 # V/cm + +class Carrier: + """ + Description: + Definition of carriers and the record of their movement + Parameters: + x_init, y_init, z_init, t_init : float + initial space and time coordinates in um and s + charge : float + a set of drifting carriers, absolute value for number, sign for charge + Attributes: + x, y, z, t : float + space and time coordinates in um and s + path : float[] + recording the carrier path in [x, y, z, t] + charge : float + a set of drifting carriers, absolute value for number, sign for charge + signal : float[] + the generated signal current on the reading electrode + end_condition : 0/string + tag of how the carrier ended drifting + Modify: + 2022/10/28 + """ + def __init__(self, x_init, y_init, z_init, t_init, charge, read_ele_num): + self.x = x_init + self.y = y_init + self.z = z_init + self.t = t_init + self.t_end = t_end + self.pixel = pixel + self.path = [[x_init, y_init, z_init, t_init]] + self.signal = [[] for j in range(int(read_ele_num))] + self.diffuse_end_condition = 0 + self.row=0 + self.column=0 + + self.charge = charge + + def diffuse_single_step(self,my_d,my_f): + delta_t=t_bin + #e_field = my_f.get_e_field(self.x,self.y,self.z) + intensity = 0 + + kboltz=8.617385e-5 #eV/K + mobility = Material(my_d.material) + mu = mobility.cal_mobility(my_d.temperature, my_f.get_doping(self.x, self.y, self.z), self.charge, intensity) + diffusion = (2.0*kboltz*mu*my_d.temperature*delta_t)**0.5 + #diffusion = 0.0 + dif_x=random.gauss(0.0,diffusion)*1e4 + dif_y=random.gauss(0.0,diffusion)*1e4 + dif_z=0 + + if((self.x+dif_x)>=my_d.l_x): + self.x = my_d.l_x + elif((self.x+dif_x)<0): + self.x = 0 + else: + self.x = self.x+dif_x + # y axis + if((self.y+dif_y)>=my_d.l_y): + self.y = my_d.l_y + elif((self.y+dif_y)<0): + self.y = 0 + else: + self.y = self.y+dif_y + # z axis + if((self.z+dif_z)>=my_d.l_z): + self.z = my_d.l_z + elif((self.z+dif_z)<0): + self.z = 0 + else: + self.z = self.z+dif_z + #time + self.t = self.t+delta_t + #record + self.path.append([self.x,self.y,self.z,self.t]) + + def diffuse_end(self,my_f): + if (self.z<=0): + # self.end_condition = "out of bound" + self.diffuse_end_condition = "collect" + return self.diffuse_end_condition + + def diffuse_not_in_sensor(self,my_d): + if (self.x<=0) or (self.x>=my_d.l_x)\ + or (self.y<=0) or (self.y>=my_d.l_y)\ + or (self.z>=my_d.l_z): + self.diffuse_end_condition = "out of bound" + mod_x = self.x % self.pixel + mod_y = self.y % self.pixel + if ((mod_x> 7.5) & (mod_x<17.5)) & ((mod_y> 7.5) & (mod_y<17.5)) \ + & (self.t <= self.t_end): + self.diffuse_end_condition = "collect" + return self.diffuse_end_condition + + ''' + if (self.z<= 0) or (self.t >= self.t_end): + self.diffuse_end_condition = "collect" + #print("diffuse end") + return self.diffuse_end_condition + ''' + + def pixel_position(self,my_f,my_d): + if self.diffuse_end_condition == "collect": + self.row = self.x // self.pixel + self.column = self.y // self.pixel + else: + self.row = -1 + self.column = -1 + return self.row,self.column,abs(self.charge) + + + +class CalCurrentPixel: + """Calculation of diffusion electrons in pixel detector""" + def __init__(self, my_d, my_f, my_g4p): + batch = len(my_g4p.localposition) + layer = len(my_d.lt_z) + G4P_carrier_list = PixelCarrierListFromG4P(my_d, my_g4p) + self.collected_charge=[] #temp paras don't save as self. + self.sum_signal = [] + self.event = [] + for k in range(batch): + l_dict = {} + signal_charge = [] + for j in range(layer): + self.electrons = [] + self.charge,self.collected_charge = [],[]#same like before + self.row,self.column=[],[] + Hit = {'index':[],'charge':[]} + #print(len(G4P_carrier_list.ionized_pairs[k][j])) + print("%f pairs of carriers are generated from G4 in event_ %d layer %d" %(sum(G4P_carrier_list.ionized_pairs[k][j]),k,j)) + #print(G4P_carrier_list.track_position[k][j]) + for i in range(len(G4P_carrier_list.track_position[k][j])): + electron = Carrier(G4P_carrier_list.track_position[k][j][i][0],\ + G4P_carrier_list.track_position[k][j][i][1],\ + G4P_carrier_list.track_position[k][j][i][2],\ + 0,\ + -1*G4P_carrier_list.ionized_pairs[k][j][i],\ + 1) + if not electron.diffuse_not_in_sensor(my_d): + self.electrons.append(electron) + self.diffuse_loop(my_d,my_f) + + Xbins=int(my_d.l_x // electron.pixel) + Ybins=int(my_d.l_y // electron.pixel) + Xup=my_d.l_x // electron.pixel + Yup=my_d.l_y // electron.pixel + test_charge = ROOT.TH2F("charge", "charge",Xbins, 0, Xup, Ybins, 0, Yup) + for i in range(len(self.row)): + #test_charge.SetBinContent(int(self.row[i]),int(self.column[i]),self.charge[i]) + test_charge.Fill(self.row[i],self.column[i],self.charge[i]) + + sum_fired = ROOT.TH2F("charge", "Pixel Detector charge",Xbins, 0, Xup, Ybins, 0, Yup) + sum_fired.Add(test_charge) + + self.sum_charge = ROOT.TH2F("charge", "Pixel Detector charge",Xbins, 0, Xup, Ybins, 0, Yup) + self.sum_charge.Add(test_charge) + + test_charge.Reset + collected_charge=self.pixel_charge(my_d,Xbins,Ybins) + signal_charge.append(collected_charge) + + Hit["index"],Hit["charge"] = self.pixel_fired(sum_fired,Xbins,Ybins) + l_dict[j] = Hit + print("%f electrons are collected in event_ %d,layer %d" %(sum(self.charge),k,j)) + self.sum_signal.append(signal_charge) + self.event.append(l_dict) + #print(signal_charge) + del signal_charge + #print(self.sum_signal) + #print(self.event) + + def diffuse_loop(self, my_d, my_f): + for electron in self.electrons: + while not electron.diffuse_not_in_sensor(my_d): + electron.diffuse_single_step(my_d, my_f) + electron.diffuse_end(my_f) + x,y,charge_quantity = electron.pixel_position(my_f,my_d) + if (x != -1)&(y != -1): + self.row.append(x) + self.column.append(y) + self.charge.append(charge_quantity) + + def pixel_charge(self,my_d,Xbins,Ybins): + for x in range(Xbins): + for y in range(Ybins): + charge =self.sum_charge.GetBinContent(x,y) + if (charge>0.2): + self.collected_charge.append([x,y,charge]) + return self.collected_charge + + def pixel_fired(self,tot,Xbins,Ybins): + Hit = {'index':[],'charge':[]} + for x in range(Xbins): + for y in range(Ybins): + charge =tot.GetBinContent(x,y) + if (charge>0.2): + Hit["index"].append([x,y]) + Hit["charge"].append(charge) + return Hit["index"],Hit["charge"] + + +class PixelCarrierListFromG4P: + def __init__(self, my_d,my_g4p): + """ + Description: + Events position and energy depositon + Parameters: + material : string + deciding the energy loss of MIP + my_g4p : Particles + batch : int + batch = 0: Single event, select particle with long enough track + batch != 0: Multi event, assign particle with batch number + Modify: + 2022/10/25 + """ + batch = len(my_g4p.localposition) + layer = len(my_d.lt_z) + material = my_d.material + self.pixelsize_x = my_d.p_x + self.pixelsize_y = my_d.p_y + self.pixelsize_z = my_d.p_z + + if (material == "SiC"): + self.energy_loss = 8.4 #ev + elif (material == "Si"): + self.energy_loss = 3.6 #ev + + self.track_position, self.ionized_pairs= [],[] + self.layer= layer + for j in range(batch): + self.single_event(my_g4p,j) + + def single_event(self,my_g4p,j): + s_track_position,s_energy= [],[] + for i in range(self.layer): + position = [] + energy = [] + name = "Layer_"+str(i) + #print(name) + for k in range(len(my_g4p.devicenames[j])): + px,py,pz = self.split_name(my_g4p.devicenames[j][k]) + if name in my_g4p.devicenames[j][k]: + tp = [0 for i in range(3)] + tp[0] = my_g4p.localposition[j][k][0]+(px-0.5)*self.pixelsize_x + tp[1] = my_g4p.localposition[j][k][1]+(py-0.5)*self.pixelsize_y + tp[2] = my_g4p.localposition[j][k][2]+self.pixelsize_z/2 + position.append(tp) + energy.append(my_g4p.energy_steps[j][k]) + s_track_position.append(position) + pairs = [step*1e6/self.energy_loss for step in energy] + s_energy.append(pairs) + del position,energy + self.track_position.append(s_track_position) + self.ionized_pairs.append(s_energy) + + def split_name(self,volume_name): + parts = volume_name.split('_') + return int(parts[1]),int(parts[2]),int(parts[4]) + diff --git a/current/model.py b/current/model.py index d14752479af598f3ba22813012a9da0dcf5412cc..339932b0084a7c4c1bf10d75a45e0f3c9eb7b8bd 100644 --- a/current/model.py +++ b/current/model.py @@ -330,38 +330,6 @@ class Material: return coefficient -class Vector: - def __init__(self,a1,a2,a3): - self.components = [a1,a2,a3] - - def cross(self,Vector_b): - """ Get vector cross product of self and another Vector""" - o1 = self.components[1]*Vector_b.components[2]-self.components[2]*Vector_b.components[1] - o2 = self.components[2]*Vector_b.components[0]-self.components[0]*Vector_b.components[2] - o3 = self.components[0]*Vector_b.components[1]-self.components[1]*Vector_b.components[0] - return Vector(o1,o2,o3) - - def get_length(self): - " Return length of self" - return math.sqrt(self.components[0]*self.components[0]+self.components[1]*self.components[1]+self.components[2]*self.components[2]) - - def add(self,Vector_b): - " Return the sum of two Vectors. eg: [1,2,3]+[1,2,3] = [2,4,6]" - o1 = self.components[0]+Vector_b.components[0] - o2 = self.components[1]+Vector_b.components[1] - o3 = self.components[2]+Vector_b.components[2] - return Vector(o1,o2,o3) - - def sub(self,Vector_b): - " Return the subtraction of two Vectors. eg: [1,2,3]-[1,2,3] = [0,0,0]" - o1 = self.components[0]-Vector_b.components[0] - o2 = self.components[1]-Vector_b.components[1] - o3 = self.components[2]-Vector_b.components[2] - return Vector(o1,o2,o3) - - def mul(self,k): - " Return Vector multiplied by number. eg: 2 * [1,2,3] = [2,4,6]" - return Vector(self.components[0]*k,self.components[1]*k,self.components[2]*k) def main(): if not (os.path.exists("./output/model")): diff --git a/draw/__init__.py b/draw/__init__.py index 56d912c04af8f1cd7e0be6f7dfd6ecfaeaef12c4..59dc25f741ef22e6c47f5c9451ce8176a6edb393 100644 --- a/draw/__init__.py +++ b/draw/__init__.py @@ -5,15 +5,17 @@ from . import cv from . import compare_iv from . import compare_cv from . import draw_iv_cv_paper9 -from . import alpha_ana_SICAR +from . import alpha_ana_sicar from . import data_convolution +from . import draw_figure_sicar as dfc + def main(kwargs): label = kwargs['label'] if label == 'sicar1.1.8': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/wangkeqi/sicar1.1.8' output_dir = '/afs/ihep.ac.cn/users/w/wangkeqi/raser/output/fig' - draw_figure(input_dir, output_dir, label) + dfc.draw(input_dir, output_dir, label) elif label == 'compare_sicar1.1.8_iv': iv.main(label) elif label == 'compare_sicar1.1.8_cv': @@ -21,22 +23,22 @@ def main(kwargs): elif label == 'sicar1.1.8-1': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/wangkeqi/sicar1.1.8' output_dir = '/afs/ihep.ac.cn/users/w/wangkeqi/raser/output/fig' - draw_figure(input_dir, output_dir, label) + dfc.draw(input_dir, output_dir, label) elif label == 'sicar1.1.8-2': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/wangkeqi/sicar1.1.8' output_dir = '/afs/ihep.ac.cn/users/w/wangkeqi/raser/output/fig' - draw_figure(input_dir, output_dir, label) + dfc.draw(input_dir, output_dir, label) elif label == 'itk_md8_data_v1': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/lizhan/itkmd8/itkmd8data' output_dir = '/afs/ihep.ac.cn/users/l/lizhan/disk/scrathfs/raser/output/fig' - draw_figure(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", + dfc.draw(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", xlowerlimit_iv=0,xupperlimit_iv=700,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, xlowerlimit_cv=0,xupperlimit_cv=400,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0) elif label == 'itk_md8_sim_v1': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/lizhan/itkmd8/itkmd8sim' output_dir = '/afs/ihep.ac.cn/users/l/lizhan/disk/scrathfs/raser/output/fig' - draw_figure(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", + dfc.draw(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", xlowerlimit_iv=0,xupperlimit_iv=700,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, xlowerlimit_cv=0,xupperlimit_cv=400,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0) @@ -48,14 +50,14 @@ def main(kwargs): elif label == 'itk_atlas18_sim_v1': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/lizhan/atlas18/sim' output_dir = '/afs/ihep.ac.cn/users/l/lizhan/disk/scrathfs/raser/output/fig' - draw_figure(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [A]", + dfc.draw(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [A]", xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", xlowerlimit_iv=0,xupperlimit_iv=700,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, xlowerlimit_cv=0,xupperlimit_cv=400,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0) elif label == 'itk_atlas18_data_v1': input_dir = '/publicfs/atlas/atlasnew/silicondet/itk/raser/lizhan/atlas18/data' output_dir = '/afs/ihep.ac.cn/users/l/lizhan/disk/scrathfs/raser/output/fig' - draw_figure(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", + dfc.draw(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [nA]", xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", xlowerlimit_iv=0,xupperlimit_iv=700,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, xlowerlimit_cv=0,xupperlimit_cv=400,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0) @@ -92,117 +94,9 @@ def main(kwargs): root_fullpath = os.path.join(csv_folder, root_filename) draw_iv_cv_paper9.create_root_file(csv_filename, root_fullpath) draw_iv_cv_paper9.main() - alpha_ana_SICAR.main() + alpha_ana_sicar.main() data_convolution.landau_mirror() data_convolution.energy_sim() else: raise NameError(label) - -def draw_figure(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [A]", - xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", - xlowerlimit_iv=0,xupperlimit_iv=510,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, - xlowerlimit_cv=0,xupperlimit_cv=399.99,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0): - - com_name = [] - for file in os.listdir(input_dir): - if file.endswith('.root'): - com_name.append(file) - for name in com_name: - if label == 'sicar1.1.8' and not name.startswith('sicar1.1.8'): - continue - elif label == 'sicar1.1.8-1' and not name.startswith('sicar1.1.8-1_'): - continue - elif label == 'sicar1.1.8-2' and not name.startswith('sicar1.1.8-2_'): - continue - name = name.split('.root')[0] - - input_file = os.path.join(input_dir, name + '.root') - output_file = os.path.join(output_dir, name + '.root') - pdf_file = os.path.join(output_dir, name + '.pdf') - png_file = os.path.join(output_dir, name + '.png') - - if name.endswith('iv'): - file = ROOT.TFile(input_file, "READ") - tree = file.Get("myTree") - graph = ROOT.TGraph() - - for i, event in enumerate(tree): - if label in ['itk_md8_data','itk_atlas18_data']: - x = event.Voltage_V - x = abs(x) - y = event.Current_nA - y = abs(y)*1e-9 - elif label == 'itk_atlas18_sim': - x = event.Voltage - x = abs(x) - y = event.Current - y = abs(y)*1e-9 - else: - x = event.Value - x = abs(x) - y = event.Reading - y = abs(y) - graph.SetPoint(i, x, y) - - draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle_iv,ytitle_iv, - xlowerlimit_iv,xupperlimit_iv,ylowerlimit_iv,yupperlimit_iv,ylogscale_iv) - #problem: unable to change y limits - - if name.endswith('cv'): - file = ROOT.TFile(input_file, "READ") - tree = file.Get("myTree") - graph = ROOT.TGraph() - for i, event in enumerate(tree): - x = event.Voltage - x = abs(x) - y = event.Capacitance - y = abs(y) - graph.SetPoint(i, x, y) - - draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle_cv,ytitle_cv, - xlowerlimit_cv,xupperlimit_cv,ylowerlimit_cv,yupperlimit_cv,ylogscale_cv) - - -def draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle,ytitle, - xlowerlimit,xupperlimit,ylowerlimit,yupperlimit,ylogscale): - graph.SetNameTitle("") - graph.SetLineWidth(1) - graph.SetMarkerColor(ROOT.kBlack) - graph.SetMarkerStyle(24) - graph.SetMarkerSize(1) - - graph.GetXaxis().SetTitle(xtitle) - graph.GetXaxis().SetLimits(xlowerlimit,xupperlimit) - graph.GetXaxis().CenterTitle() - graph.GetXaxis().SetTitleOffset(1.4) - graph.GetXaxis().SetTitleSize(0.05) - graph.GetXaxis().SetLabelSize(0.05) - graph.GetXaxis().SetNdivisions(505) - - graph.GetYaxis().SetLimits(ylowerlimit,yupperlimit) - graph.GetYaxis().SetTitle(ytitle) - graph.GetYaxis().CenterTitle() - graph.GetYaxis().SetTitleOffset(1.8) - graph.GetYaxis().SetTitleSize(0.05) - graph.GetYaxis().SetLabelSize(0.05) - graph.Draw("AP") - - c = ROOT.TCanvas("c","c",500,500) - c.SetLeftMargin(0.22) - c.SetBottomMargin(0.16) - legend = ROOT.TLegend(0.27,0.67,0.62,0.80) - c.SetGrid() - c.SetFrameLineWidth(5) - - legend.SetTextSize(0.04) - legend.AddEntry(graph,name.split('_')[0]) - - c.cd() - c.SetLogy(ylogscale) - graph.Draw() - legend.Draw() - - c.SaveAs(output_file) - c.SaveAs(pdf_file) - c.SaveAs(png_file) - del c \ No newline at end of file + \ No newline at end of file diff --git a/draw/alpha_ana_SICAR.py b/draw/alpha_ana_sicar.py similarity index 100% rename from draw/alpha_ana_SICAR.py rename to draw/alpha_ana_sicar.py diff --git a/draw/draw_figure_sicar.py b/draw/draw_figure_sicar.py new file mode 100644 index 0000000000000000000000000000000000000000..ab74bcf6748272e4945e9152a00ee8702b10f8c5 --- /dev/null +++ b/draw/draw_figure_sicar.py @@ -0,0 +1,110 @@ +import os +import ROOT +def draw(input_dir, output_dir, label,xtitle_iv="Reverse Bias Voltage [V]",ytitle_iv="Current [A]", + xtitle_cv="Reverse Bias Voltage [V]",ytitle_cv="Capacitance [pF]", + xlowerlimit_iv=0,xupperlimit_iv=510,ylowerlimit_iv=1e-11,yupperlimit_iv=1e-5,ylogscale_iv=0, + xlowerlimit_cv=0,xupperlimit_cv=399.99,ylowerlimit_cv=0,yupperlimit_cv=1e2,ylogscale_cv=0): + + com_name = [] + for file in os.listdir(input_dir): + if file.endswith('.root'): + com_name.append(file) + for name in com_name: + if label == 'sicar1.1.8' and not name.startswith('sicar1.1.8'): + continue + elif label == 'sicar1.1.8-1' and not name.startswith('sicar1.1.8-1_'): + continue + elif label == 'sicar1.1.8-2' and not name.startswith('sicar1.1.8-2_'): + continue + name = name.split('.root')[0] + + input_file = os.path.join(input_dir, name + '.root') + output_file = os.path.join(output_dir, name + '.root') + pdf_file = os.path.join(output_dir, name + '.pdf') + png_file = os.path.join(output_dir, name + '.png') + + if name.endswith('iv'): + file = ROOT.TFile(input_file, "READ") + tree = file.Get("myTree") + graph = ROOT.TGraph() + + for i, event in enumerate(tree): + if label in ['itk_md8_data','itk_atlas18_data']: + x = event.Voltage_V + x = abs(x) + y = event.Current_nA + y = abs(y)*1e-9 + elif label == 'itk_atlas18_sim': + x = event.Voltage + x = abs(x) + y = event.Current + y = abs(y)*1e-9 + else: + x = event.Value + x = abs(x) + y = event.Reading + y = abs(y) + graph.SetPoint(i, x, y) + + draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle_iv,ytitle_iv, + xlowerlimit_iv,xupperlimit_iv,ylowerlimit_iv,yupperlimit_iv,ylogscale_iv) + #problem: unable to change y limits + + if name.endswith('cv'): + file = ROOT.TFile(input_file, "READ") + tree = file.Get("myTree") + graph = ROOT.TGraph() + for i, event in enumerate(tree): + x = event.Voltage + x = abs(x) + y = event.Capacitance + y = abs(y) + graph.SetPoint(i, x, y) + + draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle_cv,ytitle_cv, + xlowerlimit_cv,xupperlimit_cv,ylowerlimit_cv,yupperlimit_cv,ylogscale_cv) + + +def draw_with_options(graph,name,output_file,pdf_file,png_file,xtitle,ytitle, + xlowerlimit,xupperlimit,ylowerlimit,yupperlimit,ylogscale): + graph.SetNameTitle("") + graph.SetLineWidth(1) + graph.SetMarkerColor(ROOT.kBlack) + graph.SetMarkerStyle(24) + graph.SetMarkerSize(1) + + graph.GetXaxis().SetTitle(xtitle) + graph.GetXaxis().SetLimits(xlowerlimit,xupperlimit) + graph.GetXaxis().CenterTitle() + graph.GetXaxis().SetTitleOffset(1.4) + graph.GetXaxis().SetTitleSize(0.05) + graph.GetXaxis().SetLabelSize(0.05) + graph.GetXaxis().SetNdivisions(505) + + graph.GetYaxis().SetLimits(ylowerlimit,yupperlimit) + graph.GetYaxis().SetTitle(ytitle) + graph.GetYaxis().CenterTitle() + graph.GetYaxis().SetTitleOffset(1.8) + graph.GetYaxis().SetTitleSize(0.05) + graph.GetYaxis().SetLabelSize(0.05) + graph.Draw("AP") + + c = ROOT.TCanvas("c","c",500,500) + c.SetLeftMargin(0.22) + c.SetBottomMargin(0.16) + legend = ROOT.TLegend(0.27,0.67,0.62,0.80) + c.SetGrid() + c.SetFrameLineWidth(5) + + legend.SetTextSize(0.04) + legend.AddEntry(graph,name.split('_')[0]) + + c.cd() + c.SetLogy(ylogscale) + graph.Draw() + legend.Draw() + + c.SaveAs(output_file) + c.SaveAs(pdf_file) + c.SaveAs(png_file) + del c \ No newline at end of file diff --git a/field/build_device.py b/field/build_device.py index 921d5fa4c7254f224bd388b405d676297605e74c..9bb4dffa6194b95626aea4caeae47aacf4582de5 100644 --- a/field/build_device.py +++ b/field/build_device.py @@ -1,14 +1,16 @@ #!/usr/bin/env python3 # -*- encoding: utf-8 -*- -import devsim -from . import model_create - -from util.output import output import json import os +import devsim import matplotlib.pyplot +import numpy as np + +from . import model_create +from util.output import output +from util.math import * class Detector: """ @@ -65,8 +67,10 @@ class Detector: if "strip" in self.det_name or "Strip" in self.det_name: # TODO: change this into model self.read_ele_num = self.device_dict['read_ele_num'] + else: + self.read_ele_num = 1 - if "pixeldetector" in self.det_model: + if "pixel" in self.det_model: self.p_x = self.device_dict['px'] self.p_y = self.device_dict['py'] self.p_z = self.device_dict['pz'] @@ -148,13 +152,13 @@ class Detector: elif self.control_dict["ac-weightfield"] == False: pass if 'Acceptors_ir' in self.device_dict['doping']: - model_create.CreateNodeModel(self.device, self.region, "Acceptors", self.device_dict['doping']['Acceptors']+"+"+self.device_dict['doping']['Acceptors_ir']) + model_create.CreateNodeModel(self.device, self.region, "Acceptors", self.device_dict['doping']['Acceptors']+"+"+self.device_dict['doping']['Acceptors_ir']) else: - model_create.CreateNodeModel(self.device, self.region, "Acceptors", self.device_dict['doping']['Acceptors']) + model_create.CreateNodeModel(self.device, self.region, "Acceptors", self.device_dict['doping']['Acceptors']) if 'Donors_ir' in self.device_dict['doping']: - model_create.CreateNodeModel(self.device, self.region, "Donors", self.device_dict['doping']['Donors']+"+"+self.device_dict['doping']['Donors_ir']) + model_create.CreateNodeModel(self.device, self.region, "Donors", self.device_dict['doping']['Donors']+"+"+self.device_dict['doping']['Donors_ir']) else: - model_create.CreateNodeModel(self.device, self.region, "Donors", self.device_dict['doping']['Donors']) + model_create.CreateNodeModel(self.device, self.region, "Donors", self.device_dict['doping']['Donors']) model_create.CreateNodeModel(self.device, self.region, "NetDoping", "Donors-Acceptors") devsim.edge_from_node_model(device=self.device, region=self.region, node_model="Acceptors") devsim.edge_from_node_model(device=self.device, region=self.region, node_model="NetDoping") diff --git a/field/devsim_field.py b/field/devsim_field.py index 80daf40f36709ec7950dc6a6b7f7f5612cc1e189..679b6f12a813e236009dc670bbbeea1e0d4e0b9c 100644 --- a/field/devsim_field.py +++ b/field/devsim_field.py @@ -10,16 +10,10 @@ import pickle import ROOT import numpy as np -from scipy.interpolate import interp1d as p1d -from scipy.interpolate import interp2d as p2d -from scipy.interpolate import griddata -from scipy.interpolate import LinearNDInterpolator as LNDI -diff_res = 1e-5 # difference resolution in cm +from util.math import * -x_bin = 1000 -y_bin = 1000 -z_bin = 1000 +diff_res = 1e-5 # difference resolution in cm class DevsimField: def __init__(self, device_name, dimension, voltage, read_ele_num, l_z): @@ -29,15 +23,39 @@ class DevsimField: 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) 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) - self.set_potential(PotentialFile) #self.potential, self.x_efield, self.y_efield, self.z_efield + 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[] + def set_doping(self, DopingFile): + try: + with open(DopingFile,'rb') as file: + DopingNotUniform=pickle.load(file) + print("Doping file loaded for {}".format(self.name)) + if DopingNotUniform['metadata']['dimension'] < self.dimension: + print("Doping dimension not match") + return + except FileNotFoundError: + print("Doping file not found, please run field simulation first") + print("or manually set the doping file") + return + + if DopingNotUniform['metadata']['dimension'] == 1: + DopingUniform = get_common_interpolate_1d(DopingNotUniform) + elif DopingNotUniform['metadata']['dimension'] == 2: + DopingUniform = get_common_interpolate_2d(DopingNotUniform) + elif DopingNotUniform['metadata']['dimension'] == 3: + DopingUniform = get_common_interpolate_3d(DopingNotUniform) + + self.Doping = DopingUniform + def set_potential(self, PotentialFile): try: with open(PotentialFile,'rb') as file: @@ -54,9 +72,9 @@ class DevsimField: if PotentialNotUniform['metadata']['dimension'] == 1: PotentialUniform = get_common_interpolate_1d(PotentialNotUniform) elif PotentialNotUniform['metadata']['dimension'] == 2: - PotentialUniform =get_common_interpolate_2d(PotentialNotUniform) + PotentialUniform = get_common_interpolate_2d(PotentialNotUniform) elif PotentialNotUniform['metadata']['dimension'] == 3: - PotentialUniform =get_common_interpolate_3d(PotentialNotUniform) + PotentialUniform = get_common_interpolate_3d(PotentialNotUniform) self.Potential = PotentialUniform @@ -88,9 +106,9 @@ class DevsimField: if TrappingRate_pNotUniform['metadata']['dimension'] == 1: TrappingRate_pUniform = get_common_interpolate_1d(TrappingRate_pNotUniform) elif TrappingRate_pNotUniform['metadata']['dimension'] == 2: - TrappingRate_pUniform =get_common_interpolate_2d(TrappingRate_pNotUniform) + TrappingRate_pUniform = get_common_interpolate_2d(TrappingRate_pNotUniform) elif TrappingRate_pNotUniform['metadata']['dimension'] == 3: - TrappingRate_pUniform =get_common_interpolate_3d(TrappingRate_pNotUniform) + TrappingRate_pUniform = get_common_interpolate_3d(TrappingRate_pNotUniform) self.TrappingRate_p = TrappingRate_pUniform @@ -110,14 +128,27 @@ class DevsimField: if TrappingRate_nNotUniform['metadata']['dimension'] == 1: TrappingRate_nUniform = get_common_interpolate_1d(TrappingRate_nNotUniform) elif TrappingRate_nNotUniform['metadata']['dimension'] == 2: - TrappingRate_nUniform =get_common_interpolate_2d(TrappingRate_nNotUniform) + TrappingRate_nUniform = get_common_interpolate_2d(TrappingRate_nNotUniform) elif TrappingRate_nNotUniform['metadata']['dimension'] == 3: - TrappingRate_nUniform =get_common_interpolate_3d(TrappingRate_nNotUniform) + TrappingRate_nUniform = get_common_interpolate_3d(TrappingRate_nNotUniform) self.TrappingRate_n = TrappingRate_nUniform # DEVSIM dimension order: x, y, z # RASER dimension order: z, x, y + + def get_doping(self, x, y, z): + ''' + input: position in um + output: doping in cm^-3 + ''' + x, y, z = x/1e4, y/1e4, z/1e4 # um to cm + if self.dimension == 1: + return self.Doping(z) + elif self.dimension == 2: + return self.Doping(z, x) + elif self.dimension == 3: + return self.Doping(z, x, y) def get_potential(self, x, y, z): ''' @@ -243,45 +274,6 @@ class DevsimField: elif self.dimension == 3: return self.TrappingRate_p(z, x, y) -def get_common_interpolate_1d(data): - values = data['values'] - points = data['points'] - f = p1d(points, values) - return f - -def get_common_interpolate_2d(data): - values = data['values'] - points_x = [] - points_y = [] - for point in data['points']: - points_x.append(point[0]) - points_y.append(point[1]) - new_x = np.linspace(min(points_x), max(points_x), x_bin) - new_y = np.linspace(min(points_y), max(points_y), y_bin) - new_points = np.array(np.meshgrid(new_x, new_y)).T.reshape(-1, 2) - new_values = griddata((points_x, points_y), values, new_points, method='linear') - f = p2d(new_x, new_y, new_values) - return f - -def get_common_interpolate_3d(data): - values = data['values'] - points_x = [] - points_y = [] - points_z = [] - for point in data['points']: - points_x.append(point[0]) - points_y.append(point[1]) - points_z.append(point[2]) - new_x = np.linspace(min(points_x), max(points_x), x_bin) - new_y = np.linspace(min(points_y), max(points_y), y_bin) - new_z = np.linspace(min(points_z), max(points_z), z_bin) - new_points = np.array(np.meshgrid(new_x, new_y, new_z)).T.reshape(-1, 3) - new_values = griddata((points_x, points_y, points_z), values, new_points, method='linear') - lndi = LNDI(new_points, new_values) - def f(x, y, z): - point = [x, y, z] - return lndi(point) - return f def linear_w_p(z, l_z): if z >= l_z: diff --git a/field/devsim_solve.py b/field/devsim_solve.py index e2dd236b788b8ef6bab0caa9d0fee997624f8a68..bc648a6b23fbb576623b58d3aa05333a1ba52773 100644 --- a/field/devsim_solve.py +++ b/field/devsim_solve.py @@ -293,7 +293,11 @@ def milestone_save_1D(device, region, v, path): metadata['voltage'] = v metadata['dimension'] = 1 - for name in ['Potential', 'TrappingRate_p', 'TrappingRate_n']: # scalar field on mesh point (instead of on edge) + names = ['Potential', 'TrappingRate_p', 'TrappingRate_n'] + 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: data = {} data['values'] = eval(name) # refer to the object with given name @@ -327,7 +331,11 @@ def milestone_save_2D(device, region, v, path): metadata['voltage'] = v metadata['dimension'] = 2 - for name in ['Potential', 'TrappingRate_p', 'TrappingRate_n']: # scalar field on mesh point (instead of on edge) + names = ['Potential', 'TrappingRate_p', 'TrappingRate_n'] + 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: data = {} data['values'] = eval(name) # refer to the object with given name @@ -338,7 +346,6 @@ def milestone_save_2D(device, region, v, path): pickle.dump(data, file) - def milestone_save_wf_2D(device, region, v, path,contact): x = np.array(devsim.get_node_model_values(device=device, region=region, name="x")) # get x-node values y = np.array(devsim.get_node_model_values(device=device, region=region, name="y")) # get y-node values @@ -354,7 +361,6 @@ def milestone_save_wf_2D(device, region, v, path,contact): draw2D(x,y,Potential,"Potential",v, path) draw2D(x_mid,y_mid,ElectricField,"ElectricField",v, path) - dd = os.path.join(path, str(v),str(contact)+'V.dd') devsim.write_devices(file=dd, type="tecplot") @@ -382,7 +388,11 @@ def milestone_save_3D(device, region, v, path): metadata['voltage'] = v metadata['dimension'] = 3 - for name in ['Potential']: # scalar field on mesh point (instead of on edge) + names = ['Potential', 'TrappingRate_p', 'TrappingRate_n'] + 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: data = {} data['values'] = eval(name) # refer to the object with given name diff --git a/gen_signal/__init__.py b/gen_signal/__init__.py index a4a63a362ced60c83869255528a7d4b387c7c172..af5d0aaf5ee383f6caf43689c730d8d7bd415560 100644 --- a/gen_signal/__init__.py +++ b/gen_signal/__init__.py @@ -1,204 +1,8 @@ -#!/usr/bin/env python3 -# -*- encoding: utf-8 -*- -''' -@Description: The main program of Raser induced current simulation -@Date : 2024/02/20 18:12:26 -@Author : tanyuhang, Chenxi Fu -@version : 2.0 -''' -import sys -import os -import array -import time -import subprocess -import ROOT - -from field import build_device as bdv -from particle import g4simulation as g4s -from field import devsim_field as devfield -from current import cal_current as ccrt -from elec import ele_readout as rdout -from elec import ngspice_set_input as ngsip -from elec import ngspice as ng - -from . import draw_save -from util.output import output - -import json - -import random - def main(kwargs): - """ - Description: - The main program of Raser induced current simulation - Parameters: - --------- - dset : class - Parameters of simulation - Function or class: - Detector -- Define the basic parameters and mesh structure of the detector - DevsimCal -- Get the electric field and weighting potential - Particles -- Electron and hole paris distibution - CalCurrent -- Drift of e-h pais and induced current - Amplifier -- Readout electronics simulation - draw_plots -- Draw electric field, drift path and energy deposition - Modify: - --------- - 2021/09/02 - """ - start = time.time() - - det_name = kwargs['det_name'] - my_d = bdv.Detector(det_name) - - if kwargs['voltage'] != None: - voltage = float(kwargs['voltage']) - else: - voltage = float(my_d.voltage) - - if kwargs['absorber'] != None: - absorber = kwargs['absorber'] - else: - absorber = my_d.absorber - - if kwargs['amplifier'] != None: - amplifier = kwargs['amplifier'] - else: - amplifier = my_d.amplifier - - if "strip" in det_name: - my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage, my_d.read_ele_num, my_d.l_z) - else: - my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage, 1, my_d.l_z) - - if kwargs['scan'] != None: - geant4_json = "./setting/absorber/" + absorber + ".json" - with open(geant4_json) as f: - g4_dic = json.load(f) - - total_events = int(g4_dic['total_events']) - for i in range(kwargs['scan']): - # TODO: change this into multithread - instance_number = i - g4_seed = instance_number * total_events - my_g4p = g4s.Particles(my_d, absorber, g4_seed) - batch_loop(my_d, my_f, my_g4p, amplifier, g4_seed, total_events, instance_number) - del my_g4p - return - - else: - g4_seed = random.randint(0,1e7) - my_g4p = g4s.Particles(my_d, absorber, g4_seed) - - 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) + label = kwargs['label'] - if 'ngspice' in amplifier: - save_current(my_d, my_current, my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage, 1, my_d.l_z), key=None) - input_p=ngsip.set_input(my_current, my_d, key=None) - input_c=','.join(input_p) - ng.ngspice_t0(input_c, input_p) - subprocess.run(['ngspice -b -r t0.raw output/T0_tmp.cir'], shell=True) - ng.plot_waveform() + if label == 'signal': + from . import gen_signal_main + gen_signal_main.main(kwargs) else: - ele_current = rdout.Amplifier(my_current, amplifier) - draw_save.draw_plots(my_d,ele_current,my_f,my_g4p,my_current) - - del my_f - end = time.time() - print("total_time:%s"%(end-start)) - - - -def batch_loop(my_d, my_f, my_g4p, amplifier, g4_seed, total_events, instance_number): - """ - Description: - Batch run some events to get time resolution - Parameters: - --------- - start_n : int - Start number of the event - end_n : int - end number of the event - detection_efficiency: float - The ration of hit particles/total_particles - @Returns: - --------- - None - @Modify: - --------- - 2021/09/07 - """ - path = output(__file__, my_d.det_name, 'batch') - if "plugin" in my_d.det_model: - draw_save.draw_ele_field(my_d,my_f,"xy",my_d.det_model,my_d.l_z*0.5,path) - else: - draw_save.draw_ele_field_1D(my_d,my_f,path) - draw_save.draw_ele_field(my_d,my_f,"xz",my_d.det_model,my_d.l_y*0.5,path) - - start_n = instance_number * total_events - end_n = (instance_number + 1) * total_events - - effective_number = 0 - for event in range(start_n,end_n): - print("run events number:%s"%(event)) - if len(my_g4p.p_steps[event-start_n]) > 5: - effective_number += 1 - my_current = ccrt.CalCurrentG4P(my_d, my_f, my_g4p, event-start_n) - ele_current = rdout.Amplifier(my_current, amplifier) - draw_save.save_signal_time_resolution(my_d,event,ele_current,my_g4p,start_n,my_f) - del ele_current - detection_efficiency = effective_number/(end_n-start_n) - print("detection_efficiency=%s"%detection_efficiency) - -# TODO: change this to a method of CalCurrent -def save_current(my_d,my_current,my_f,key): - if key!=None: - if "planar3D" in my_d.det_model or "planarRing" in my_d.det_model: - path = os.path.join('output', 'pintct', my_d.det_name, ) - elif "lgad3D" in my_d.det_model: - path = os.path.join('output', 'lgadtct', my_d.det_name, ) - if os.path.exists(path): - os.mkdir(path) - L = eval("my_l.{}".format(key)) - #L is defined by different keys - elif key==None: - if "planar3D" in my_d.det_model or "planarRing" in my_d.det_model: - path = os.path.join('output', 'PIN', my_d.det_name, ) - elif "lgad3D" in my_d.det_model: - path = os.path.join('output', 'LGAD', my_d.det_name, ) - if not os.path.exists(path): - os.makedirs(path) - - #L is defined by different keys - time = array.array('d', [999.]) - current = array.array('d', [999.]) - fout = ROOT.TFile(os.path.join(path, "sim-current") + ".root", "RECREATE") - t_out = ROOT.TTree("tree", "signal") - t_out.Branch("time", time, "time/D") - for i in range(my_current.read_ele_num): - t_out.Branch("current"+str(i), current, "current"+str(i)+"/D") - for j in range(my_current.n_bin): - current[0]=my_current.sum_cu[i].GetBinContent(j) - time[0]=j*my_current.t_bin - t_out.Fill() - t_out.Write() - fout.Close() - - - - - - - -if __name__ == '__main__': - args = sys.argv[1:] - kwargs = {} - for arg in args: - key, value = arg.split('=') - kwargs[key] = value - main(kwargs) - \ No newline at end of file + raise NameError diff --git a/gen_signal/gen_signal_main.py b/gen_signal/gen_signal_main.py new file mode 100644 index 0000000000000000000000000000000000000000..1a7ea2821b7fc9dfd268b7a4a5096787535af62f --- /dev/null +++ b/gen_signal/gen_signal_main.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8 -*- +''' +@Description: The main program of Raser induced current simulation +@Date : 2024/02/20 18:12:26 +@Author : tanyuhang, Chenxi Fu +@version : 2.0 +''' +import sys +import os +import array +import time +import subprocess +import ROOT + +from field import build_device as bdv +from particle import g4simulation as g4s +from field import devsim_field as devfield +from current import cal_current as ccrt +from elec import ele_readout as rdout +from elec import ngspice_set_input as ngsip +from elec import ngspice as ng + +from . import draw_save +from util.output import output + +import json + +import random + +def main(kwargs): + """ + Description: + The main program of Raser induced current simulation + Parameters: + --------- + dset : class + Parameters of simulation + Function or class: + Detector -- Define the basic parameters and mesh structure of the detector + DevsimCal -- Get the electric field and weighting potential + Particles -- Electron and hole paris distibution + CalCurrent -- Drift of e-h pais and induced current + Amplifier -- Readout electronics simulation + draw_plots -- Draw electric field, drift path and energy deposition + Modify: + --------- + 2021/09/02 + """ + start = time.time() + + det_name = kwargs['det_name'] + my_d = bdv.Detector(det_name) + + if kwargs['voltage'] != None: + voltage = float(kwargs['voltage']) + else: + voltage = float(my_d.voltage) + + if kwargs['absorber'] != None: + absorber = kwargs['absorber'] + else: + absorber = my_d.absorber + + if kwargs['amplifier'] != None: + amplifier = kwargs['amplifier'] + 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) + + if kwargs['scan'] != None: + geant4_json = "./setting/absorber/" + absorber + ".json" + with open(geant4_json) as f: + g4_dic = json.load(f) + + total_events = int(g4_dic['total_events']) + for i in range(kwargs['scan']): + # TODO: change this into multithread + instance_number = i + g4_seed = instance_number * total_events + my_g4p = g4s.Particles(my_d, absorber, g4_seed) + batch_loop(my_d, my_f, my_g4p, amplifier, g4_seed, total_events, instance_number) + del my_g4p + return + + else: + g4_seed = random.randint(0,1e7) + my_g4p = g4s.Particles(my_d, absorber, g4_seed) + + 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) + + if 'ngspice' in amplifier: + save_current(my_d, my_current, my_f = devfield.DevsimField(my_d.device, my_d.dimension, voltage, 1, my_d.l_z), key=None) + input_p=ngsip.set_input(my_current, my_d, key=None) + input_c=','.join(input_p) + ng.ngspice_t0(input_c, input_p) + subprocess.run(['ngspice -b -r t0.raw output/T0_tmp.cir'], shell=True) + ng.plot_waveform() + else: + ele_current = rdout.Amplifier(my_current, amplifier) + draw_save.draw_plots(my_d,ele_current,my_f,my_g4p,my_current) + + del my_f + end = time.time() + print("total_time:%s"%(end-start)) + + + +def batch_loop(my_d, my_f, my_g4p, amplifier, g4_seed, total_events, instance_number): + """ + Description: + Batch run some events to get time resolution + Parameters: + --------- + start_n : int + Start number of the event + end_n : int + end number of the event + detection_efficiency: float + The ration of hit particles/total_particles + @Returns: + --------- + None + @Modify: + --------- + 2021/09/07 + """ + path = output(__file__, my_d.det_name, 'batch') + if "plugin" in my_d.det_model: + draw_save.draw_ele_field(my_d,my_f,"xy",my_d.det_model,my_d.l_z*0.5,path) + else: + draw_save.draw_ele_field_1D(my_d,my_f,path) + draw_save.draw_ele_field(my_d,my_f,"xz",my_d.det_model,my_d.l_y*0.5,path) + + start_n = instance_number * total_events + end_n = (instance_number + 1) * total_events + + effective_number = 0 + for event in range(start_n,end_n): + print("run events number:%s"%(event)) + if len(my_g4p.p_steps[event-start_n]) > 5: + effective_number += 1 + my_current = ccrt.CalCurrentG4P(my_d, my_f, my_g4p, event-start_n) + ele_current = rdout.Amplifier(my_current, amplifier) + draw_save.save_signal_time_resolution(my_d,event,ele_current,my_g4p,start_n,my_f) + del ele_current + detection_efficiency = effective_number/(end_n-start_n) + print("detection_efficiency=%s"%detection_efficiency) + +# TODO: change this to a method of CalCurrent +def save_current(my_d,my_current,my_f,key): + if key!=None: + if "planar3D" in my_d.det_model or "planarRing" in my_d.det_model: + path = os.path.join('output', 'pintct', my_d.det_name, ) + elif "lgad3D" in my_d.det_model: + path = os.path.join('output', 'lgadtct', my_d.det_name, ) + if os.path.exists(path): + os.mkdir(path) + L = eval("my_l.{}".format(key)) + #L is defined by different keys + elif key==None: + if "planar3D" in my_d.det_model or "planarRing" in my_d.det_model: + path = os.path.join('output', 'PIN', my_d.det_name, ) + elif "lgad3D" in my_d.det_model: + path = os.path.join('output', 'LGAD', my_d.det_name, ) + if not os.path.exists(path): + os.makedirs(path) + + #L is defined by different keys + time = array.array('d', [999.]) + current = array.array('d', [999.]) + fout = ROOT.TFile(os.path.join(path, "sim-current") + ".root", "RECREATE") + t_out = ROOT.TTree("tree", "signal") + t_out.Branch("time", time, "time/D") + for i in range(my_current.read_ele_num): + t_out.Branch("current"+str(i), current, "current"+str(i)+"/D") + for j in range(my_current.n_bin): + current[0]=my_current.sum_cu[i].GetBinContent(j) + time[0]=j*my_current.t_bin + t_out.Fill() + t_out.Write() + fout.Close() + + + + + + + +if __name__ == '__main__': + args = sys.argv[1:] + kwargs = {} + for arg in args: + key, value = arg.split('=') + kwargs[key] = value + main(kwargs) + \ No newline at end of file diff --git a/motor/mdo_3034_control.py b/motor/mdo_3034_control.py deleted file mode 100644 index 4edb4aaa36c32223e5e69b54ce20310ab922d30a..0000000000000000000000000000000000000000 --- a/motor/mdo_3034_control.py +++ /dev/null @@ -1,94 +0,0 @@ -import numpy as np -import pandas as pd -import pylab -import re -import time - -try: - import visa -except ImportError as err: - print(err) - exit() - -class MDO3034C: - def __init__(self, resource_name): - instlist=visa.ResourceManager() - #print(instlist.list_resources()) - self.my_resource=instlist.open_resource(resource_name) - - def write_command(self,command): - self.my_resource.write(command) - time.sleep(0.5) - def testIO(self): - #self.my_resource.write('*RST') - self.my_resource.write('*CLS') - #self.my_resource.query_delay = 10.0 - message=self.my_resource.query('*IDN?') - time.sleep(1) - #print("ocsilloscope information:" + message) - return message - - def readSet(self,ch,point_number): - self.my_resource.write(":DATA:SOU "+ ch) - self.my_resource.write(':DATA:START 1') - self.my_resource.write(':DATA:STOP ' + point_number) - self.my_resource.write(':WFMOutpre:ENCdg BINARY') - self.my_resource.write(":WFMOutpre:BYT_Nr 1") - self.my_resource.write(":HEADer 0") - self.my_resource.write(":WFMOutpre?") - - def readOffset(self): - self.write_command('WFMPRE:YMULT?') - ymult = float(self.my_resource.read_raw()) - print("ymult = " + repr(ymult) + '\n') - self.write_command('WFMPRE:YZERO?') - yzero = float(self.my_resource.read_raw()) - print("yzero = " + repr(yzero) + '\n') - self.write_command('WFMPRE:YOFF?') - yoff = float(self.my_resource.read_raw()) - print("yoff = " + repr(yoff) + '\n') - self.write_command('WFMPRE:XINCR?') - xincr = float(self.my_resource.read_raw()) - print("xincr = " + repr(xincr) + '\n') - self.write_command('WFMPRE:XZERO?') - xzero = float(self.my_resource.read_raw()) - print("xzero = " + repr(xzero) + '\n') - return ymult,yzero,yoff,xincr,xzero - - def readWave(self,ymult,yzero,yoff,xincr,xzero,point_num): - #ymult,yzero,yoff,xincr,xzero=self.readOffset() - self.my_resource.write('*CLS') - self.my_resource.write("CURVE?") - #file = open('test.txt','w+') - - ########################################## - # receive data format: - # #510000<data>\n receive 10000 data - # #41000<data>\n receive 1000 data - ######################################### - data = np.frombuffer(self.my_resource.read_raw(),dtype=np.int8,count=int(point_num),offset=len(str(point_num)) + 2) - #np.savetxt('test.txt',data,fmt='%d',delimiter=',') - - print(data.size) - Volts = (data - yoff) * ymult + yzero - Time = np.arange(0, data.size, 1) - Time = Time * xincr + xzero - - return Time, Volts - - def save_wave_data(self,time,voltage,filenames='./data.csv'): - datadic = {'Time[ms]':time,'Voltage[mv]':voltage} - dataform = pd.DataFrame(datadic,columns=['Time[ms]','Voltage[mv]']) - dataform.to_csv(filenames,mode='a+',index=False) - - - def plotWave(self, Time, Volts): - pylab.plot(Time, Volts) - pylab.show() - -def ReadInterface(): - rm = visa.ResourceManager() - print(rm.list_resources()) - list_sources = rm.list_resources() - return list_sources - diff --git a/motor/thread.py b/motor/thread.py index 043a15fb93719cd04680fa125a4b5453588e8750..2b7a6b6a738dc8c137ac315fcd4c5a8257243292 100644 --- a/motor/thread.py +++ b/motor/thread.py @@ -1,5 +1,5 @@ import pymotor,stage,raser.motor.vitual_device as vitual_device -import raser.motor.mdo_3034_control as MD +import raser.control.mdo_3034_scope_control as MD import time from datetime import datetime import numpy as np diff --git a/particle/g4simulation.py b/particle/g4simulation.py index c112ea7c53f802d9e0c7b4e43c26eab746fa3106..42396202909a4bd35b622b86d26c9f9e9a03e725 100644 --- a/particle/g4simulation.py +++ b/particle/g4simulation.py @@ -29,7 +29,7 @@ class Particles: #use in pixel_detector _randx = None _randy = None - def __init__(self, my_d, absorber, g4_seed): + def __init__(self, my_d, absorber, g4_seed = random.randint(0, 1e7)): """ Description: Geant4 main process diff --git a/root/__init__.py b/root/__init__.py index 804037ae655831d228d6eaee957658bb5ea34668..fc45015038cf102ace020c9b54eb36863b56d110 100644 --- a/root/__init__.py +++ b/root/__init__.py @@ -1,60 +1,5 @@ -import sys -import os -import ROOT -import csv - -def convert_csv_to_root(input_dir, output_dir, label): - com_name = [] - for file in os.listdir(input_dir): - if file.endswith('.csv'): - com_name.append(file) - for name in com_name: - if label == 'sicar1.1.8' and not name.startswith('sicar1.1.8'): - continue - elif label == 'sicar1.1.8-1' and not name.startswith('sicar1.1.8-1_'): - continue - elif label == 'sicar1.1.8-2' and not name.startswith('sicar1.1.8-2_'): - continue - - name = name.split('.csv')[0] - input_file = os.path.join(input_dir, name + '.csv') - output_file = os.path.join(output_dir, name + '.root') - - if name.endswith('iv'): - if label=="itk_atlas18_data_v1": - df = ROOT.RDF.MakeCsvDataFrame(input_file, True, '\t') - elif label =="njupin_iv_v1": - df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') - else: - df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') - if label in ["itk_md8_data_v1","itk_atlas18_data_v1"]: - df.Snapshot("myTree", output_file, {"Voltage_V", "Current_nA"}) - elif label in ['itk_atlas18_sim_v1','itk_md8_sim_v1']: - df.Snapshot("myTree", output_file, {"Voltage", "Current"}) - elif label =="njupin_iv_v1": - df.Snapshot("myTree", output_file, {"Current","Voltage"}) - - else: - df.Snapshot("myTree", output_file, {"Value","Reading"}) - - if name.endswith('cv'): - df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') - if label=="itk_md8_sim_v1": - df.Snapshot("myTree", output_file, {"Voltage", "Capacitance"}) - elif label =="njupin_cv_v1": - df.Snapshot("myTree", output_file, {"Voltage", "Capacitance"}) - else: - df.Snapshot("myTree", output_file, {"Voltage", "Capacitance", "Capacitance^-2"}) - - if name.endswith('Wfm'): - df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') - df.Snapshot("myTree", output_file, {"Time", "Volt"}) - - - sys.stdout.write('Saved as {}\n'.format(output_file)) - - def main(kwargs): + from .convert import convert_csv_to_root label = kwargs['label'] if label == 'sicar1.1.8': diff --git a/root/convert.py b/root/convert.py new file mode 100644 index 0000000000000000000000000000000000000000..09d92ada4b73d92f7c361b53cb70915fa7b8218c --- /dev/null +++ b/root/convert.py @@ -0,0 +1,54 @@ +import sys +import os +import ROOT +import csv + +def convert_csv_to_root(input_dir, output_dir, label): + com_name = [] + for file in os.listdir(input_dir): + if file.endswith('.csv'): + com_name.append(file) + for name in com_name: + if label == 'sicar1.1.8' and not name.startswith('sicar1.1.8'): + continue + elif label == 'sicar1.1.8-1' and not name.startswith('sicar1.1.8-1_'): + continue + elif label == 'sicar1.1.8-2' and not name.startswith('sicar1.1.8-2_'): + continue + + name = name.split('.csv')[0] + input_file = os.path.join(input_dir, name + '.csv') + output_file = os.path.join(output_dir, name + '.root') + + if name.endswith('iv'): + if label=="itk_atlas18_data_v1": + df = ROOT.RDF.MakeCsvDataFrame(input_file, True, '\t') + elif label =="njupin_iv_v1": + df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') + else: + df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') + if label in ["itk_md8_data_v1","itk_atlas18_data_v1"]: + df.Snapshot("myTree", output_file, {"Voltage_V", "Current_nA"}) + elif label in ['itk_atlas18_sim_v1','itk_md8_sim_v1']: + df.Snapshot("myTree", output_file, {"Voltage", "Current"}) + elif label =="njupin_iv_v1": + df.Snapshot("myTree", output_file, {"Current","Voltage"}) + + else: + df.Snapshot("myTree", output_file, {"Value","Reading"}) + + if name.endswith('cv'): + df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') + if label=="itk_md8_sim_v1": + df.Snapshot("myTree", output_file, {"Voltage", "Capacitance"}) + elif label =="njupin_cv_v1": + df.Snapshot("myTree", output_file, {"Voltage", "Capacitance"}) + else: + df.Snapshot("myTree", output_file, {"Voltage", "Capacitance", "Capacitance^-2"}) + + if name.endswith('Wfm'): + df = ROOT.RDF.MakeCsvDataFrame(input_file, True, ',') + df.Snapshot("myTree", output_file, {"Time", "Volt"}) + + + sys.stdout.write('Saved as {}\n'.format(output_file)) diff --git a/spaceres/__init__.py b/spaceres/__init__.py index f3c07cb0f9d34ac77831db38105086738de025a9..59b4b6e8a785215dbe8be42b51469446f7772dfa 100644 --- a/spaceres/__init__.py +++ b/spaceres/__init__.py @@ -1,17 +1,9 @@ import sys import os -#sys.path.insert(0, sys.path[0]+"/../") - -import ROOT import time import subprocess -from . import telescope as tlcp -#from . import test -from particle.g4simulation import Particles -from particle.geometry import R3dDetector -from current.cal_current import CalCurrentPixel -from util.output import create_path +import ROOT def main(kwargs): label = kwargs['label'] @@ -19,103 +11,17 @@ def main(kwargs): print("taichu_v1: ","first version of telescope simulation") print("taichu_v2: ","second version of telescope simulation") elif label.startswith("taichu_v1"): - #paths = ['det_name=Taichu3', 'parfile=readjson/detector.json', 'geant4_model=pixel_detector', 'geant4_parfile=readjson/absorber.json', 'pixel_detector'] - dset = Setting() #read label.json instead of inputting path - my_d = R3dDetector(dset) #remain the same - my_f = 0 - my_g4p = Particles(my_d, dset) #remove my_f - my_charge = CalCurrentPixel(my_d,my_f,my_g4p) - if label.endswith("draw_charge"): - draw_charge(my_charge) - my_telescope = tlcp.telescope(my_d,my_charge) - #tlcp.main(my_d) + from . import telescope_signal as tlcp + tlcp.main() elif label.startswith("taichu_v2"): - #virtual object - class MyObject: - pass - #output - res = [] - psize = [] - N = 25 - MaxSize = 25. - for i in range(N): - t_my_d = MyObject() - t_my_d.seedcharge = 100 - t_my_d.p_x = MaxSize*(i+1)/N - t_my_d.p_y = MaxSize*(i+1)/N - t_my_d.p_z = 200. - t_my_d.lt_z = [20000.,60000.,100000.,140000.,180000.,220000.] - psize.append(t_my_d.p_x) - res.append(tlcp.main(t_my_d)) - - graph = ROOT.TGraph() - for i in range(len(psize)): - graph.SetPoint(i,psize[i],res[i]) - - canvas = ROOT.TCanvas("canvas", "TGraph", 800, 600) - graph.SetMarkerStyle(ROOT.kFullCircle) - graph.GetYaxis().SetTitle("Resolution [um]") - graph.GetYaxis().CenterTitle() - graph.GetXaxis().SetTitle("Pixel Size [um]") - graph.GetXaxis().CenterTitle() - - legend = ROOT.TLegend(0.27,0.67,0.62,0.80) - legend.SetTextSize(0.04) - legend.AddEntry(graph,label) - - canvas.SetGrid() - - graph.Draw("APL") - legend.Draw() - - canvas.Draw() - Name = "Res vs size" - now = time.strftime("%Y_%m%d_%H%M") - path = os.path.join("output/fig", str(now),'' ) - """ If the path does not exit, create the path""" - if not os.access(path, os.F_OK): - os.makedirs(path) - canvas.SaveAs(path+Name+".png") + from . import telescope_signal as tlcp + tlcp.taichu_v2(label) elif label.startswith("acts_v1"): - python_script = "raser/spaceres/telescope_simulation.py" - - result = subprocess.run(["python3", python_script], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - - if result.returncode == 0: - print(f"Script '{python_script}' executed successfully.") - else: - print(f"Script '{python_script}' failed with return code:", result.returncode) - - stdout_output = result.stdout - stderr_output = result.stderr - - print("Standard Output:") - print(stdout_output) - - print("Standard Error:") - print(stderr_output) + from . import telescope_acts as tlcp_acts + tlcp_acts.main() + elif label.startswith("g4"): + from . import telescope_g4 + telescope_g4.main() else: raise NameError(label) -def draw_charge(my_charge): - path = os.path.join("output", "pixel",) - create_path(path) - c=ROOT.TCanvas("c","canvas1",1000,1000) - c.cd() - c.Update() - c.SetLeftMargin(0.12) - # c.SetTopMargin(0.12) - c.SetRightMargin(0.12) - c.SetBottomMargin(0.14) - ROOT.gStyle.SetOptStat(ROOT.kFALSE) - ROOT.gStyle.SetOptStat(0) - - my_charge.sum_charge.GetXaxis().SetNdivisions(510) - my_charge.sum_charge.GetYaxis().SetNdivisions(505) - my_charge.sum_charge.GetXaxis().SetTitle("X") - my_charge.sum_charge.GetYaxis().SetTitle("Y") - - my_charge.sum_charge.Draw("lego") - c.Update() - c.SaveAs(path+"/Pixel_charge.pdf") - c.SaveAs(path+"/Pixel_charge.root") diff --git a/spaceres/telescope_simulation.py b/spaceres/telescope_acts.py similarity index 93% rename from spaceres/telescope_simulation.py rename to spaceres/telescope_acts.py index 80a2e6805dd4045e3a36d10da78fe575f81602bc..a007c578c63154f703cdfc079c9fd795ff4c9b32 100755 --- a/spaceres/telescope_simulation.py +++ b/spaceres/telescope_acts.py @@ -4,6 +4,9 @@ from pathlib import Path import acts import acts.examples + +from util.io_decorator import io_decorator as iod + from acts.examples.simulation import ( addParticleGun, addDigitization, @@ -30,9 +33,11 @@ from acts.examples.reconstruction import ( TrackSelectorConfig, ) -u = acts.UnitConstants +# get run result +@iod +def main(): + u = acts.UnitConstants -if "__main__" == __name__: detector, trackingGeometry, decorators = acts.examples.TelescopeDetector.create( positions=[20, 60, 100 ,140, 180, 220], stereos = [0, 0, 0, 0, 0, 0], @@ -42,10 +47,10 @@ if "__main__" == __name__: field = acts.ConstantBField(acts.Vector3(0, 0, 1 * u.T)) - outputDir = Path.cwd() / "output/telescope_simulation" + outputDir = Path.cwd() / "output/spaceres/telescope_acts" if not outputDir.exists(): outputDir.mkdir() - inputDir = Path.cwd() / "setting" + inputDir = Path.cwd() / "setting/acts" rnd = acts.examples.RandomNumbers(seed=42) @@ -148,4 +153,7 @@ if "__main__" == __name__: outputDirRoot=outputDir / postfix, ) ''' - s.run() \ No newline at end of file + s.run() + +if "__main__" == __name__: + main() \ No newline at end of file diff --git a/spaceres/telescope_jiaqi.py b/spaceres/telescope_g4.py similarity index 94% rename from spaceres/telescope_jiaqi.py rename to spaceres/telescope_g4.py index 1bdfd52bd9860fb599b9295bb16ca8f45c57135b..8d464f11b1dbfcdc29457cc24e2de55a0b769f84 100755 --- a/spaceres/telescope_jiaqi.py +++ b/spaceres/telescope_g4.py @@ -584,45 +584,50 @@ class B2ActionInitialization(G4VUserActionInitialization): self.SetUserAction(B2EventAction()) self.SetUserAction(B2SteppingAction()) -# Detect interactive mode (if no arguments) and define UI session -ui = None -if len(sys.argv) == 1: - ui = G4UIExecutive(len(sys.argv), sys.argv) - -# Optionally: choose a different Random engine... -# G4Random.setTheEngine(MTwistEngine()) - -# Construct the default run manager -runManager = G4RunManagerFactory.CreateRunManager(G4RunManagerType.Serial) - -# Set mandatory initialization classes -runManager.SetUserInitialization(B2aDetectorConstruction()) - -physicsList = FTFP_BERT() -physicsList.RegisterPhysics(G4StepLimiterPhysics()) -runManager.SetUserInitialization(physicsList) - -# Set user action classes -runManager.SetUserInitialization(B2ActionInitialization()) - -# Initialize visualization -visManager = G4VisExecutive() -# G4VisExecutive can take a verbosity argument - see /vis/verbose guidance. -# visManager = G4VisExecutive("Quiet"); -visManager.Initialize() - -# Get the pointer to the User Interface manager -UImanager = G4UImanager.GetUIpointer() - -# Process macro or start UI session -if ui == None: - # batch mode - command = "/control/execute ./cfg/ " - fileName = sys.argv[1] - UImanager.ApplyCommand(command+fileName) -else: - # interactive mode - UImanager.ApplyCommand("/control/execute ./param_file/g4macro/init_vistelescope.mac") - if ui.IsGUI(): - UImanager.ApplyCommand("/control/execute ./param_file/g4macro/gui.mac") - ui.SessionStart() + +def main(batchMac = None): + # Detect interactive mode (if no arguments) and define UI session + ui = None + if batchMac == None: + ui = G4UIExecutive(1, [__file__]) + + # Optionally: choose a different Random engine... + # G4Random.setTheEngine(MTwistEngine()) + + # Construct the default run manager + runManager = G4RunManagerFactory.CreateRunManager(G4RunManagerType.Serial) + + # Set mandatory initialization classes + runManager.SetUserInitialization(B2aDetectorConstruction()) + + physicsList = FTFP_BERT() + physicsList.RegisterPhysics(G4StepLimiterPhysics()) + runManager.SetUserInitialization(physicsList) + + # Set user action classes + runManager.SetUserInitialization(B2ActionInitialization()) + + # Initialize visualization + visManager = G4VisExecutive() + # G4VisExecutive can take a verbosity argument - see /vis/verbose guidance. + # visManager = G4VisExecutive("Quiet"); + visManager.Initialize() + + # Get the pointer to the User Interface manager + UImanager = G4UImanager.GetUIpointer() + + # Process macro or start UI session + if ui == None: + # batch mode + command = "/control/execute ./param_file/g4macro/" + fileName = batchMac + UImanager.ApplyCommand(command+fileName) + else: + # interactive mode + UImanager.ApplyCommand("/control/execute ./param_file/g4macro/init_vistelescope.mac") + if ui.IsGUI(): + UImanager.ApplyCommand("/control/execute ./param_file/g4macro/gui.mac") + ui.SessionStart() + +if __name__ == "__main__": + main(sys.argv[1]) \ No newline at end of file diff --git a/spaceres/telescope.py b/spaceres/telescope_signal.py similarity index 84% rename from spaceres/telescope.py rename to spaceres/telescope_signal.py index fbcc272202f7a5df50d83c252ad0c25219d08c89..2d2514377aa5187f8d098e7234dc08b53ac7c8ca 100644 --- a/spaceres/telescope.py +++ b/spaceres/telescope_signal.py @@ -6,13 +6,20 @@ Description: @Author : yiminghu @version : 1.0 ''' -import ROOT + import time import os + +import ROOT import acts import numpy as np -class telescope: +from particle.g4simulation import Particles +from field.build_device import Detector +from current.cal_current_diffuse import CalCurrentPixel +from util.output import create_path + +class Telescope: def __init__(self,my_d,my_c): """ Description: @@ -128,7 +135,7 @@ class telescope: Name = "fit"+str(DUT) now = time.strftime("%Y_%m%d_%H%M") - path = os.path.join("fig", str(now),'' ) + path = os.path.join("output/spaceres/taichu_v1", str(now),'' ) #print(path) """ If the path does not exit, create the path""" @@ -220,7 +227,7 @@ class telescope: label.Draw() now = time.strftime("%Y_%m%d_%H%M") - path = os.path.join("fig", str(now),'' ) + path = os.path.join("output/spaceres/taichu_v1", str(now),'' ) #print(path) """ If the path does not exit, create the path""" @@ -376,7 +383,7 @@ class island: #interface to generate simple examples for debugging -class Test: +class PixelHitTest: def __init__(self,my_d): self.event = [] @@ -444,11 +451,89 @@ class Test: #print(t_list) return t_list -def main(my_d): - my_c = Test(my_d) - tel = telescope(my_d,my_c) - return tel.Resolution_Tol[2][0] - +def draw_charge(my_charge): + path = os.path.join("output", "pixel",) + create_path(path) + c=ROOT.TCanvas("c","canvas1",1000,1000) + c.cd() + c.Update() + c.SetLeftMargin(0.12) + # c.SetTopMargin(0.12) + c.SetRightMargin(0.12) + c.SetBottomMargin(0.14) + ROOT.gStyle.SetOptStat(ROOT.kFALSE) + ROOT.gStyle.SetOptStat(0) + + my_charge.sum_charge.GetXaxis().SetNdivisions(510) + my_charge.sum_charge.GetYaxis().SetNdivisions(505) + my_charge.sum_charge.GetXaxis().SetTitle("X") + my_charge.sum_charge.GetYaxis().SetTitle("Y") + + my_charge.sum_charge.Draw("lego") + c.Update() + c.SaveAs(path+"/Pixel_charge.pdf") + c.SaveAs(path+"/Pixel_charge.root") + +def main(): + my_d = Detector("TAICHU3") #remain the same + my_f = 0 + my_g4p = Particles(my_d, my_d.absorber) #remove my_f + my_hit_charge = CalCurrentPixel(my_d,my_f,my_g4p) + draw_charge(my_hit_charge) + my_telescope_charge = Telescope(my_d,my_hit_charge) + my_hit_test = PixelHitTest(my_d) + my_telescope_test = Telescope(my_d,my_hit_test) + +def taichu_v2(label=""): + #virtual object + class MyObject: + pass + #output + res = [] + psize = [] + N = 25 + MaxSize = 25. + for i in range(N): + t_my_d = MyObject() + t_my_d.seedcharge = 100 + t_my_d.p_x = MaxSize*(i+1)/N + t_my_d.p_y = MaxSize*(i+1)/N + t_my_d.p_z = 200. + t_my_d.lt_z = [20000.,60000.,100000.,140000.,180000.,220000.] + psize.append(t_my_d.p_x) + my_hit_test = PixelHitTest(t_my_d) + my_telescope_test = Telescope(t_my_d,my_hit_test) + res.append(my_telescope_test.Resolution_Tol[2][0]) + + graph = ROOT.TGraph() + for i in range(len(psize)): + graph.SetPoint(i,psize[i],res[i]) + + canvas = ROOT.TCanvas("canvas", "TGraph", 800, 600) + graph.SetMarkerStyle(ROOT.kFullCircle) + graph.GetYaxis().SetTitle("Resolution [um]") + graph.GetYaxis().CenterTitle() + graph.GetXaxis().SetTitle("Pixel Size [um]") + graph.GetXaxis().CenterTitle() + + legend = ROOT.TLegend(0.27,0.67,0.62,0.80) + legend.SetTextSize(0.04) + legend.AddEntry(graph,label) + + canvas.SetGrid() + + graph.Draw("APL") + legend.Draw() + + canvas.Draw() + Name = "Res vs size" + now = time.strftime("%Y_%m%d_%H%M") + path = os.path.join("output/spaceres/taichu_v2", str(now),'' ) + """ If the path does not exit, create the path""" + if not os.access(path, os.F_OK): + os.makedirs(path) + canvas.SaveAs(path+Name+".png") + if __name__ == '__main__': start = time.time() main() diff --git a/util/io_decorator.py b/util/io_decorator.py new file mode 100644 index 0000000000000000000000000000000000000000..3dcc74dd612e5d4960a949d57c1f35529af0cce8 --- /dev/null +++ b/util/io_decorator.py @@ -0,0 +1,31 @@ +import sys +import io +from contextlib import redirect_stdout, redirect_stderr +import importlib.util +import inspect + +def io_decorator(func): + def wrapper(*args, **kwargs): + try: + # Capture the standard output and error + stdout_buffer = io.StringIO() + stderr_buffer = io.StringIO() + + with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer): + func(*args, **kwargs) + # Get the output + stdout_output = stdout_buffer.getvalue() + stderr_output = stderr_buffer.getvalue() + + print(f"Function '{func.__name__}' executed successfully.") + print("Standard Output:") + print(stdout_output) + + if stderr_output: + print("Standard Error:") + print(stderr_output) + + except Exception as e: + print(f"Function '{func.__name__}' failed with an exception:", e) + + return wrapper diff --git a/util/math.py b/util/math.py new file mode 100644 index 0000000000000000000000000000000000000000..acd31bf7b66f3df979bffd20ea7d7800736b58fb --- /dev/null +++ b/util/math.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# -*- encoding: utf-8 -*- + +''' +Description: + Math Objects +@Date : 2024/09/19 20:57:33 +@Author : Chenxi Fu +@version : 1.0 +''' + +import math + +import numpy as np +from scipy.interpolate import interp1d as p1d +from scipy.interpolate import interp2d as p2d +from scipy.interpolate import griddata +from scipy.interpolate import LinearNDInterpolator as LNDI + +x_bin = 1000 +y_bin = 1000 +z_bin = 1000 + +class Vector: + def __init__(self,a1,a2,a3): + self.components = [a1,a2,a3] + + def cross(self,Vector_b): + """ Get vector cross product of self and another Vector""" + o1 = self.components[1]*Vector_b.components[2]-self.components[2]*Vector_b.components[1] + o2 = self.components[2]*Vector_b.components[0]-self.components[0]*Vector_b.components[2] + o3 = self.components[0]*Vector_b.components[1]-self.components[1]*Vector_b.components[0] + return Vector(o1,o2,o3) + + def get_length(self): + " Return length of self" + return math.sqrt(self.components[0]*self.components[0]+self.components[1]*self.components[1]+self.components[2]*self.components[2]) + + def add(self,Vector_b): + " Return the sum of two Vectors. eg: [1,2,3]+[1,2,3] = [2,4,6]" + o1 = self.components[0]+Vector_b.components[0] + o2 = self.components[1]+Vector_b.components[1] + o3 = self.components[2]+Vector_b.components[2] + return Vector(o1,o2,o3) + + def sub(self,Vector_b): + " Return the subtraction of two Vectors. eg: [1,2,3]-[1,2,3] = [0,0,0]" + o1 = self.components[0]-Vector_b.components[0] + o2 = self.components[1]-Vector_b.components[1] + o3 = self.components[2]-Vector_b.components[2] + return Vector(o1,o2,o3) + + def mul(self,k): + " Return Vector multiplied by number. eg: 2 * [1,2,3] = [2,4,6]" + return Vector(self.components[0]*k,self.components[1]*k,self.components[2]*k) + + +def get_common_interpolate_1d(data): + values = data['values'] + points = data['points'] + f = p1d(points, values) + return f + +def get_common_interpolate_2d(data): + values = data['values'] + points_x = [] + points_y = [] + for point in data['points']: + points_x.append(point[0]) + points_y.append(point[1]) + new_x = np.linspace(min(points_x), max(points_x), x_bin) + new_y = np.linspace(min(points_y), max(points_y), y_bin) + new_points = np.array(np.meshgrid(new_x, new_y)).T.reshape(-1, 2) + new_values = griddata((points_x, points_y), values, new_points, method='linear') + f = p2d(new_x, new_y, new_values) + return f + +def get_common_interpolate_3d(data): + values = data['values'] + points_x = [] + points_y = [] + points_z = [] + for point in data['points']: + points_x.append(point[0]) + points_y.append(point[1]) + points_z.append(point[2]) + + new_x = np.linspace(min(points_x), max(points_x), x_bin) + new_y = np.linspace(min(points_y), max(points_y), y_bin) + new_z = np.linspace(min(points_z), max(points_z), z_bin) + new_points = np.array(np.meshgrid(new_x, new_y, new_z)).T.reshape(-1, 3) + new_values = griddata((points_x, points_y, points_z), values, new_points, method='linear') + lndi = LNDI(new_points, new_values) + def f(x, y, z): + point = [x, y, z] + return lndi(point) + return f \ No newline at end of file