<jupyter_start><jupyter_text>Implant profile function<jupyter_code>def implant_profile(xmin=0,xmax=5,Cp=1.0e17,Rp=0.5):
    x = np.arange(xmin,xmax,0.01)
    net_doping = Cp*np.exp((-(x-Rp)**2)/(2*Rp**2))
    return (net_doping)<jupyter_output><empty_output><jupyter_text>Epi doping function<jupyter_code>def epi_doping(baseline=1e16,xmin=0,xmax=5,slope=0.2):
     x = np.arange(xmin,xmax,0.01)
     epi_doping = baseline+slope*x*baseline
     return (epi_doping)
def net_doping(As_doping,B_doping,Phos_doping):
    net_doping = np.abs(As_doping - Boron_doping+Phos_doping)
    return (net_doping)<jupyter_output><empty_output><jupyter_text>Plot function<jupyter_code>def plot_doping(net_doping,xmin=0,xmax=5):
    x = np.arange(xmin,xmax,0.01)
    
    plt.figure(figsize=(6,4),dpi=90)
    plt.semilogy(x,net_doping,lw=3,c='k')
    plt.xlim(xmin,xmax*1.1)
    plt.ylim(1.0e14,1e20)
    plt.grid(True)
    plt.xlabel("X-distance ($\mu$m)",fontsize=12)
    plt.ylabel("Net doping ($C/{cm}^3$)",fontsize=12)
    plt.show()<jupyter_output><empty_output><jupyter_text>Plot saving<jupyter_code>def plot_saving(net_doping,xmin=0,xmax=5):
    x = np.arange(xmin,xmax,0.01)
    
    plt.figure(figsize=(5,5))
    plt.semilogy(x,net_doping,lw=3,c='k')
    plt.xlim(xmin,xmax*1.1)
    plt.ylim(1.0e14,1e20)<jupyter_output><empty_output><jupyter_text>Doping profile evaluation function<jupyter_code>def evaluate_doping(doping):
    from scipy.signal import argrelextrema
    
    l = len(doping)
    src_junction=0
    body_junction=0
    
    a = argrelextrema(doping,np.less) # Returns a Tuple of ndarrays (indices of extrema)
    b=a[0] # Extract the ndarray
    
    if len(b)<2:
        print("No channel found! Source doping too high relative to P-well doping!")
    else:
        x1=b[0]
        x2=b[1]
        src_junction=round((x1*0.01),3)
        body_junction=round((x2*0.01),3)

        if (body_junction-src_junction)<=0.3:
            print(f"Source junction at {src_junction}. P-well junction at {body_junction}. Short channel")
        elif 0.3<(body_junction-src_junction)<=0.6:
            print(f"Source junction at {src_junction}. P-well junction at {body_junction}. Right channel length")
        else:
            print(f"Source junction at {src_junction}. P-well junction at {body_junction}. Long channel")<jupyter_output><empty_output><jupyter_text>Doping profile labeler function<jupyter_code>def label_doping(doping):
    from scipy.signal import argrelextrema
    
    l = len(doping)
    src_junction=0
    body_junction=0
    
    a = argrelextrema(doping,np.less) # Returns a Tuple of ndarrays (indices of extrema)
    b=a[0] # Extract the ndarray
    
    if len(b)<2:
        return ("No channel")
    else:
        x1=b[0]
        x2=b[1]
        src_junction=round((x1*0.01),3)
        body_junction=round((x2*0.01),3)

        if (body_junction-src_junction)<=0.3:
            return ("Short channel")
        elif 0.3<(body_junction-src_junction)<=0.6:
            return ("Optimum channel")
        else:
            return ("Long channel")<jupyter_output><empty_output><jupyter_text>Doping profile classifier function<jupyter_code>def classifier_doping(doping):
    from scipy.signal import argrelextrema
    
    l = len(doping)
    src_junction=0
    body_junction=0
    
    a = argrelextrema(doping,np.less) # Returns a Tuple of ndarrays (indices of extrema)
    b=a[0] # Extract the ndarray
    
    if len(b)<2:
        return (0)
    else:
        x1=b[0]
        x2=b[1]
        src_junction=round((x1*0.01),3)
        body_junction=round((x2*0.01),3)

        if (body_junction-src_junction)<=0.3:
            return (1)
        elif 0.3<(body_junction-src_junction)<=0.6:
            return (2)
        else:
            return (3)<jupyter_output><empty_output><jupyter_text>Implants and epi doping<jupyter_code># Implants and epi doping
As_doping=implant_profile(Cp=5e19,Rp=0.25,xmin=0,xmax=5)
Boron_doping=implant_profile(Cp=4e17,Rp=0.4,xmin=0,xmax=5)
Phos_doping = epi_doping(xmin=0,xmax=5,slope=0.2,baseline=1e16)

# Net doping
Net_doping = np.abs(As_doping - Boron_doping+Phos_doping)<jupyter_output><empty_output><jupyter_text>Plot<jupyter_code>plot_doping(Net_doping,xmin=0,xmax=5)
evaluate_doping(Net_doping)<jupyter_output>Source junction at 1.19. P-well junction at 1.44. Short channel<jupyter_text>Random generation of doping profiles<jupyter_code>num_samples=500
As_Cp=np.random.random(size=num_samples)*3e19
Boron_Cp=np.random.random(size=num_samples)*4e17
As_Rp=0.1+np.random.random(size=num_samples)*0.2
Boron_Rp=0.15+np.random.random(size=num_samples)*0.25
Phos_baseline=4e16+np.random.random(size=num_samples)*1e16

df = pd.DataFrame([As_Cp,Boron_Cp,As_Rp,Boron_Rp,Phos_baseline])
df=df.transpose()
df.columns=['As_Cp','Boron_Cp','As_Rp','Boron_Rp','Phos_baseline']
df.head(10)
def channel_labels(a,b,c,d,e):
    x=net_doping(As_doping=implant_profile(Cp=a,Rp=b),
                 B_doping=implant_profile(Cp=c,Rp=d),
                 Phos_doping=epi_doping(baseline=e))
    y=label_doping(x)
    return (y)
def channel_classes(a,b,c,d,e):
    x=net_doping(As_doping=implant_profile(Cp=a,Rp=b),
                 B_doping=implant_profile(Cp=c,Rp=d),
                 Phos_doping=epi_doping(baseline=e))
    y=classifier_doping(x)
    return (y)
channels=[]
for i in range(df.shape[0]):
    channels.append(channel_labels(df.iloc[i]['As_Cp'],df.iloc[i]['As_Rp'],df.iloc[i]['Boron_Cp'],
         df.iloc[i]['Boron_Rp'],df.iloc[i]['Phos_baseline']))
channel_class=[]
for i in range(df.shape[0]):
    channel_class.append(channel_classes(df.iloc[i]['As_Cp'],df.iloc[i]['As_Rp'],df.iloc[i]['Boron_Cp'],
         df.iloc[i]['Boron_Rp'],df.iloc[i]['Phos_baseline']))
df['Channel']=channels
df['Channel_class']=channel_class
def net_profiles(a,b,c,d,e):
    x=net_doping(As_doping=implant_profile(Cp=a,Rp=b),
                 B_doping=implant_profile(Cp=c,Rp=d),
                 Phos_doping=epi_doping(baseline=e))
    return (x)
net_profile=[]
for i in range(df.shape[0]):
    net_profile.append(net_profiles(df.iloc[i]['As_Cp'],df.iloc[i]['As_Rp'],df.iloc[i]['Boron_Cp'],
         df.iloc[i]['Boron_Rp'],df.iloc[i]['Phos_baseline']))
df['Net_dopings']=net_profile
df.head(10)
plt.figure(figsize=(9,6))
plt.title("Distribution of channel claases",fontsize=18)
plt.hist(df['Channel_class'],color='orange')
plt.grid(True)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.show()<jupyter_output><empty_output><jupyter_text>Save the net doping plots in a directory<jupyter_code>from PIL import Image
from tqdm import tqdm

savelocation = 'Saved_Figs/'
for i in tqdm(range(df.shape[0])):
    plot_saving(df.iloc[i]['Net_dopings'])
    plt.savefig(fname=savelocation+'Plot'+str(i),dpi=40,bbox_inches='tight')
    plt.close()
    #img = Image.open(savelocation+'Plot'+str(i)+'.png').convert('LA')
    #img.save(savelocation+'Plot'+str(i)+'.png')<jupyter_output>100%|████████████████████████████████████████| 500/500 [04:35<00:00,  1.81it/s]<jupyter_text>Image of a random plot<jupyter_code>from skimage import io
im0 = io.imread('Saved_Figs/Plot15.png',as_grey=True)
plt_shape=im0.shape
plt.imshow(im0,cmap='gray')
plt.show()
x=plt.imread('Saved_Figs/Plot15.png')
plt.imshow(x)<jupyter_output><empty_output><jupyter_text>Neural Network Model<jupyter_code>import keras
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout<jupyter_output><empty_output><jupyter_text>Set up the image data to be used as input to the Neural Network<jupyter_code>X =[]
for i in range(df.shape[0]):
    X.append(io.imread(savelocation+'Plot'+str(i)+'.png',as_grey=True).reshape(plt_shape[0],plt_shape[1],1))
    
y=df['Channel_class']
num_classes = 4
y = keras.utils.to_categorical(y, num_classes)
X=np.array(X)
X.shape<jupyter_output><empty_output><jupyter_text>Training and Test set splits<jupyter_code>from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25)<jupyter_output><empty_output><jupyter_text>Set up the Convolutional Neural NetworkA convolutional neural network (CNN, or ConvNet) is a class of deep, feed-forward artificial neural networks, most commonly applied to analyzing visual imagery. CNNs use a variation of multilayer perceptrons designed to require minimal preprocessing. A CNN consists of an input and an output layer, as well as multiple hidden layers. The hidden layers of a CNN typically consist of convolutional layers, pooling layers, fully connected layers and normalization layers.![cnn1](https://cdn-images-1.medium.com/max/1600/1*N4h1SgwbWNmtrRhszM9EJg.png)<jupyter_code>input_shape=(plt_shape[0],plt_shape[1],1)
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=2, padding='same', activation='relu', 
                        input_shape=input_shape))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Conv2D(filters=128, kernel_size=2, padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=2))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(50, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(4, activation='softmax'))

model.summary()<jupyter_output>_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_13 (Conv2D)           (None, 171, 184, 32)      160       
_________________________________________________________________
max_pooling2d_13 (MaxPooling (None, 85, 92, 32)        0         
_________________________________________________________________
conv2d_14 (Conv2D)           (None, 85, 92, 64)        8256      
_________________________________________________________________
max_pooling2d_14 (MaxPooling (None, 42, 46, 64)        0         
_________________________________________________________________
conv2d_15 (Conv2D)           (None, 42, 46, 128)       32896     
_________________________________________________________________
max_pooling2d_15 (MaxPooling (None, 21, 23, 128)       0         
_________________________________________________________________
dropout_9 [...]<jupyter_text>Optimizer and loss function<jupyter_code>optimizer=keras.optimizers.adam(lr=0.001)
model.compile(loss='categorical_crossentropy', optimizer=optimizer,metrics=['accuracy'])
from keras.callbacks import ModelCheckpoint   

# train the model
checkpointer = ModelCheckpoint(filepath='model.weights.best.hdf5', verbose=0, 
                               save_best_only=True)
hist = model.fit(X_train, y_train, batch_size=32, epochs=20,
          validation_data=(X_val, y_val), callbacks=[checkpointer], 
          verbose=1, shuffle=True)
model.load_weights('model.weights.best.hdf5')
model.evaluate(X_test,y_test)
predictions=model.predict(X_test)<jupyter_output><empty_output><jupyter_text>Show time! Test a prediction!<jupyter_code>test_prediction=15
plt.imshow(X_test[test_prediction].reshape(X_test.shape[1],X_test.shape[2]),cmap='gray')
plt.show()<jupyter_output><empty_output><jupyter_text>What the Neural Network outputs in probabilities<jupyter_code>predictions[test_prediction]<jupyter_output><empty_output><jupyter_text>What the actual class is<jupyter_code>y_test[test_prediction]<jupyter_output><empty_output><jupyter_text>Visually show the Neural Network output<jupyter_code>plt.figure(figsize=(8,5))
plt.barh(width=predictions[test_prediction],bottom=[1,2,3,4],edgecolor='k',color='orange',alpha=0.75,
         tick_label=['No channel','Short-channel','Right channel','Long channel'])
plt.grid(True)
plt.ylabel("Output Classes",fontsize=15)
plt.title("Class probabilities predicted by the deep neural network",fontsize=15)
plt.show()<jupyter_output>c:\programdata\miniconda3\lib\site-packages\matplotlib\pyplot.py:2790: MatplotlibDeprecationWarning: The *bottom* kwarg to `barh` is deprecated use *y* instead. Support for *bottom* will be removed in Matplotlib 3.0
  ret = ax.barh(*args, **kwargs)<jupyter_text>Table of predicted and actual class labels<jupyter_code>df_preds1=pd.DataFrame(predictions,columns=['Predicted Class-'+str(i) for i in range(1,5)])
df_preds2=pd.DataFrame(y_test,columns=['Actual Class-'+str(i) for i in range(1,5)])
df_preds=pd.concat([df_preds1,df_preds2],axis=1)
df_preds.head(20)
plt.hist(predictions)
plt.show()<jupyter_output><empty_output><jupyter_text>Another one!<jupyter_code>test_prediction=90
plt.imshow(X_test[test_prediction].reshape(X_test.shape[1],X_test.shape[2]),cmap='gray')
plt.show()
predictions[test_prediction]
y_test[test_prediction]
plt.figure(figsize=(8,5))
plt.barh(width=predictions[test_prediction],bottom=[1,2,3,4],edgecolor='k',color='orange',alpha=0.75,
         tick_label=['No channel','Short-channel','Right channel','Long channel'])
plt.grid(True)
plt.ylabel("Output Classes",fontsize=15)
plt.title("Class probabilities predicted by the deep neural network",fontsize=15)
plt.show()<jupyter_output>c:\programdata\miniconda3\lib\site-packages\matplotlib\pyplot.py:2790: MatplotlibDeprecationWarning: The *bottom* kwarg to `barh` is deprecated use *y* instead. Support for *bottom* will be removed in Matplotlib 3.0
  ret = ax.barh(*args, **kwargs)
{'fraction_non_alphanumeric': 0.14521525763997323, 'fraction_numerical': 0.03271618707710611, 'mean_word_length': 5.538648517258143, 'pattern_counts': {'":': 0, '<': 101, '<?xml version=': 0, '>': 88, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '337173', 'license': 'MIT', 'n_tokens_mistral': 5399, 'n_tokens_neox': 5027, 'n_words': 738, 'path': 'Channel_Doping_Image_Learning-1.ipynb', 'repo_name': 'tirthajyoti/Convolutional-Networks', 'size': '13449'}