[1]:
import SimEventViewer as SMV
import torch
import numpy as np
import matplotlib.pyplot as plt
%matplotlib tk
import pandas as pd
import os
import torch.nn as nn
import torch.optim as optim
from collections import OrderedDict
from tqdm import trange
from scipy.interpolate import interp1d
# bins_dir is the numpy file containing the bin edges used to fit to
bins_dir='/home/nr1315/Documents/Project/MachineLearning/test_bins.npy'
# coeffs_file is the h5 file containing the effective dose coefficients
coeffs_file='/home/nr1315/Documents/Project/effective_dose_coeffs.h5'
testbins=np.load(bins_dir)
coeffs=pd.read_hdf(coeffs_file)
seed=0
[2]:
# Shuffles data order
def shuffle_inds(seed,batch):
n_val=int(0.2*batch)
torch.manual_seed(0)
shuffled_indices=torch.randperm(batch)
return shuffled_indices
[3]:
# Prepare a specific simulated dataset for training
def SimTrainingInputs(file,avg,batch,shuffled_inds,seed):
a=SMV.NewSimPlotter()
path,name=os.path.split(file)
a.add_data(file,name[:-3])
df=a.data[name[:-3]]
cubes=df.query('CapCube>0')['CapCube'].values
z=(cubes/1e4).astype(int)
x=((cubes-z*1e4)/100).astype(int)
y=(cubes-z*1e4-x*100).astype(int)
x-=1
y-=1
z-=1
cubs=pd.DataFrame(np.array([x,y,z]).T,columns=['X','Y','Z'])
ze=np.zeros([4,4,4])
coords=np.argwhere(ze==0)
counts=[]
for coord in coords:
counts.append(np.count_nonzero((cubs.values==coord).all(axis=1)))
count=sum(counts)
ncounts=np.array(counts)/sum(counts)*avg
np.random.seed(seed)
train_x=np.random.poisson(np.tile(ncounts,(batch,1)))
train_x=64000*train_x/train_x.sum(axis=1)[:,np.newaxis]
train_x=torch.from_numpy(train_x).to(torch.float)
n_val=int(0.2*batch)
if n_val>=1:
val_x=train_x[shuffled_inds[-n_val:]]
train_x=train_x[shuffled_inds[:-n_val]]
else:
val_x=None
return train_x,val_x,count
[4]:
# Prepare a specific real dataset for training
def RealTrainingInputs(file,avg,batch,shuffled_inds,seed):
file=pd.read_hdf(file)
file=file[file['Combine']]
cubes=file.loc[:,['CubeX','CubeY','CubeZ']]
ze=np.zeros([4,4,4])
coords=np.argwhere(ze==0)
counts=[]
for coord in coords:
counts.append(np.count_nonzero((cubes.values==coord).all(axis=1)))
counts=np.array(counts)/2
count=counts.sum()
ncounts=counts/counts.sum()*avg
np.random.seed(seed)
train_x=np.random.poisson(np.tile(ncounts,(batch,1)))
train_x=avg*train_x/train_x.sum(axis=1)[:,np.newaxis]
train_x=torch.from_numpy(train_x).to(torch.float)
n_val=int(0.2*batch)
if n_val>=1:
val_x=train_x[shuffled_inds[-n_val:]]
train_x=train_x[shuffled_inds[:-n_val]]
else:
val_x=None
return train_x,val_x,count
[5]:
# Loads an expected energy bins file
def LoadTrainingTargets(file,avg,batch,shuffled_inds):
train_y=np.nan_to_num(np.load(file))
train_y=avg*train_y/train_y.sum()
train_y=train_y[:,np.newaxis].repeat(batch,axis=1).T
train_y=torch.from_numpy(train_y).to(torch.float)
n_val=int(0.2*batch)
if n_val>=1:
val_y=train_y[shuffled_inds[-n_val:]]
train_y=train_y[shuffled_inds[:-n_val]]
else:
val_y=None
return train_y,val_y
[6]:
# Prepares training data from a list of data files, associated labels, and whether each is a
# simulated or real dataset.
def prep_training_inputs(avg, batch, shuffled_inds,files,labels,real,seed=0):
train_data={}
val_data={}
counts=[]
for i in range(len(files)):
if real[i]:
train,val,count=RealTrainingInputs(files[i],avg,batch,shuffled_inds,seed)
else:
train,val,count=SimTrainingInputs(files[i],avg,batch,shuffled_inds,seed)
train_data[labels[i]]=train
val_data[labels[i]]=val
counts.append(count)
train=torch.cat(tuple(train_data.values()))
try:
val=torch.cat(tuple(val_data.values()))
except TypeError:
val=None
return train,val,counts
# Prepares training targets from a list of datafiles
def prep_training_targets(avg,batch,shuffled_inds,files,labels):
train_data={}
val_data={}
for i in range(len(files)):
train_data[labels[i]],val_data[labels[i]]=LoadTrainingTargets(files[i],avg,batch,shuffled_inds)
train=torch.cat(tuple(train_data.values()))
try:
val=torch.cat(tuple(val_data.values()))
except TypeError:
val=None
return train, val
[7]:
# Calculates effective dose from a bin distribution
def calc_dose(binvals,centres,coeffs):
E=coeffs['Energy / MeV'].values
AP=coeffs['AP'].values
eff_dose=interp1d(E,AP)
dose=((binvals/400)*eff_dose(centres)).sum(axis=1)
return dose
[ ]:
[8]:
xtrain=['/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-13_cf-4774_1m5_0deg_sc-stand_1V0_v12.h5',
'/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-14_ambe-30-1679_1m5_+0deg_sc-stand_1V0_v67.h5',
'/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-14_amli_1m5_+0deg_sc-stand_1V0_v55.h5',
'/home/nr1315/Documents/Project/Simulations/Data/Low_scatter_new/4x4normal/thermal.h5'
]
labels=['Cf',
'AmBe',
'AmLi',
'Thermal'
]
real=[True,
True,
True,
False
]
ytrain=['/home/nr1315/Documents/Project/MachineLearning/CfBinCounts.npy',
'/home/nr1315/Documents/Project/MachineLearning/AmBeBinCounts.npy',
'/home/nr1315/Documents/Project/MachineLearning/AmLiBinCounts.npy',
'/home/nr1315/Documents/Project/MachineLearning/ThermBinCounts.npy'
]
[9]:
batch=1250
torch.manual_seed(seed)
shuf=shuffle_inds(0,batch)
X_train,X_val,X_counts=prep_training_inputs(64000,batch,shuf,xtrain,labels,real,seed=seed)
Y_train,Y_val=prep_training_targets(64000,batch,shuf,ytrain,labels)
[10]:
x_test=RealTrainingInputs('/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-13_cf-4774_1m5_0deg_sc-stand_1V0_v12.h5',64000,1000,np.arange(0,1000,1),0)
x_test=torch.cat([x_test[0],x_test[1]])
y_test=LoadTrainingTargets('/home/nr1315/Documents/Project/MachineLearning/CfBinCounts.npy',64000,1000,np.arange(0,1000,1))
y_test=torch.cat([y_test[0],y_test[1]])
[11]:
def iterate_minibatches(X, y, batchsize, shuffle=False):
indices = np.arange(len(X))
if shuffle:
indices = np.random.permutation(indices)
for start in range(0, len(indices), batchsize):
ix = indices[start: start + batchsize]
yield X[ix], y[ix]
[12]:
def training_loop(n_epochs,model,optimizer,loss_fn,train_x,val_x,train_y,val_y,batchsize):
train_loss_per_epoch=[]
val_loss_per_epoch=[]
weight_hist=[]
for epoch in range(1,n_epochs+1):
model.train(True)
train_loss=0
for batch_x,batch_y in iterate_minibatches(train_x,train_y,batchsize,shuffle=True):
batch_pred_y=model(batch_x)
batch_train_loss=loss_fn(batch_pred_y,batch_y)
optimizer.zero_grad()
batch_train_loss.backward()
optimizer.step()
train_loss+=batch_train_loss.data.numpy()
train_loss_per_epoch.append(train_loss)
if val_x is not None:
val_loss=loss_fn(model(val_x),val_y)
val_loss_per_epoch.append(val_loss)
if epoch==1:
if val_x is not None:
print(f"Epoch {epoch}, Training loss {train_loss:.4f},"
f" Validation loss {val_loss.item():.4f}")
else:
print(f"Epoch {epoch}, Training loss {train_loss:.4f}")
weight_hist.append(list(model.parameters()))
return train_loss_per_epoch,val_loss_per_epoch,weight_hist
[13]:
n_X_train=X_train/X_train.sum(axis=1)[:,np.newaxis]
n_X_val=X_val/X_val.sum(axis=1)[:,np.newaxis]
n_Y_train=Y_train/Y_train.sum(axis=1)[:,np.newaxis]
n_Y_val=Y_val/Y_val.sum(axis=1)[:,np.newaxis]
[14]:
#model=nn.Sequential(OrderedDict([
# ('hidden_linear1',nn.Linear(64,128)),
# ('hidden_activation1',nn.Sigmoid()),
# ('hidden_linear2',nn.Linear(128,64)),
# ('hidden_activation2',nn.Sigmoid()),
# ('hidden_linear3',nn.Linear(64,32)),
# ('hidden_activation3',nn.Sigmoid()),
# ('output_layer',nn.Linear(32,24))]))
model=nn.Sequential(nn.Linear(64,128),
nn.ReLU(),
nn.Linear(128,64),
nn.ReLU(),
nn.Linear(64,32),
nn.ReLU(),
nn.Linear(32,24),
)
optimizer=optim.Rprop(model.parameters(),lr=1e-2)
n_epochs=100
def weights(m):
classname=m.__class__.__name__
if classname=='Linear':
n=m.in_features
y=1.0/np.sqrt(n)
m.weight.data.normal_(0.0,y)
m.bias.data.fill_(4000)
model.apply(weights)
tloss,vloss,weights=training_loop(n_epochs=n_epochs,
model=model,
optimizer=optimizer,
loss_fn=nn.MSELoss(),
train_x=X_train,
val_x=X_val,
train_y=Y_train,
val_y=Y_val,
batchsize=256)
print()
if len(vloss)>0:
print('Final training loss: '+str(tloss[-1])+', final validation loss: '+str(vloss[-1]))
else:
print('Final training loss: '+str(tloss[-1]))
if len(vloss)>0:
fig,ax=plt.subplots(2,1,figsize=(10,20))
ax[0].plot(np.arange(0,n_epochs,1),tloss,c='b',label='Training loss')
ax[0].set_title('Training loss',fontsize=24)
ax[1].plot(np.arange(0,n_epochs,1),vloss,c='r',label='Validation loss')
ax[1].set_title('Validation loss',fontsize=24)
else:
fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(np.arange(0,n_epochs,1),tloss,c='b',label='Training loss')
ax.set_title('Training loss',fontsize=24)
Epoch 1, Training loss 388717416.5000, Validation loss 2317353.0000
Final training loss: 79519.21240234375, final validation loss: tensor(5084.6782, grad_fn=<MseLossBackward>)
[15]:
barcentres=testbins[:-1]+np.diff(testbins)/2
fig,ax=plt.subplots(4,2,figsize=(20,20))
fig.set_tight_layout(True)
title=['Cf','AmBe','AmLi','Thermal']
for i in range(4):
ax[i,0].bar(barcentres,Y_val[250*i],edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[i,0].set_title(title[i]+' training data',fontsize=22)
ax[i,0].set_xscale('log')
ax[i,1].bar(barcentres,model(X_val[250*i]).detach().numpy(),edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[i,1].set_title(title[i]+' predicted data',fontsize=22)
ax[i,1].set_xscale('log')
ax[i,0].set_xlabel('Energy / MeV',fontsize=18)
ax[i,1].set_xlabel('Energy / MeV',fontsize=18)
ax[i,0].set_xlabel('Frequency',fontsize=18)
ax[i,1].set_xlabel('Frequency',fontsize=18)
plt.show()
[16]:
loss=nn.MSELoss()
l=loss(y_test,model(x_test)).item()
[17]:
fig,ax=plt.subplots(1,2,figsize=(20,10))
ax[0].bar(barcentres,y_test[0],edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[0].set_title('Test data')
ax[1].bar(barcentres,model(x_test[0]).detach().numpy(),edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[1].set_title('Predicted data')
ax[0].set_xscale('log')
ax[1].set_xscale('log')
[ ]:
[ ]:
Now load in an IPNDV dataset, to compare to Cf & the neural net predictions¶
[18]:
import DataProcess as DP
a=DP.Plotter()
folder='/home/nr1315/Documents/Project/IPNDVdata/data_BR1/10-09-2019/'
a.add_data(folder,'2019_09_10_bkg_0deg_0.95d_0.91h_afternoon.root','background')
a.add_data(folder,'2019_09_10_pin96_Bare_0deg_0.root','96_bare')
[19]:
bkg=a.data['background']
bkg=bkg[bkg['Combine']]
bkgcubes=bkg.loc[:,['CubeX','CubeY','CubeZ']]
data=a.data['96_bare']
data=data[data['Combine']]
cubes=data.loc[:,['CubeX','CubeY','CubeZ']]
ze=np.zeros([4,4,4])
coords=np.argwhere(ze==0)
bkgcounts=[]
counts=[]
for coord in coords:
counts.append(np.count_nonzero((cubes.values==coord).all(axis=1)))
bkgcounts.append(np.count_nonzero((bkgcubes.values==coord).all(axis=1)))
bkgcounts=np.array(bkgcounts)/2
counts=np.array(counts)/2
norm=(a.data['background']['time'].max()-a.data['background']['time'].min())/(a.data['96_bare']['time'].max()-a.data['96_bare']['time'].min())
if norm>1:
counts=counts - bkgcounts/norm
else:
counts=norm*counts - bkgcounts
[20]:
tt=np.zeros([4,4,4])
tt[coords[:,0],coords[:,1],coords[:,2]]=counts
tt=np.rot90(tt,2,axes=(0,1))
tcounts=tt.flatten()
Plotting Cf training inputs/target¶
[21]:
fig,ax=plt.subplots(1,2,figsize=(20,10))
ax[0].bar(np.arange(0,64,1),X_val[0],edgecolor='xkcd:deep blue',width=1)
ax[0].set_xlabel('Cube ID',fontsize=18)
ax[0].set_ylabel('Frequency',fontsize=18)
ax[0].set_title('Cf training input',fontsize=22)
ax[1].bar(barcentres,Y_val[0],edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[1].set_xlabel('Energy / MeV',fontsize=18)
ax[1].set_ylabel('Frequency',fontsize=18)
ax[1].set_title('Cf training target',fontsize=22)
ax[1].set_xscale('log')
Plotting the IPNDV dataset prediction vs the Cf target used (i.e. comparing network prediction of IPNDV dataset with a known Cf fluence)¶
[22]:
fig,ax=plt.subplots(1,2,figsize=(20,10))
ax[1].bar(barcentres,model(torch.from_numpy(counts).to(torch.float)).detach().numpy(),edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[1].set_xscale('log')
ax[1].set_xlabel('Energy / MeV',fontsize=18)
ax[1].set_ylabel('Frequency',fontsize=18)
ax[1].set_title('Fluence prediction, 96 bare (IPNDV)',fontsize=22)
ax[0].bar(barcentres,Y_val[0],edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[0].set_xscale('log')
ax[0].set_xlabel('Energy / MeV',fontsize=18)
ax[0].set_title('Cf fluence target',fontsize=22)
ax[0].set_ylabel('Frequency',fontsize=18)
[22]:
Text(0, 0.5, 'Frequency')
[23]:
tt=np.rot90(tt,2,axes=(0,1))
Plotting 3D cube view of background subtracted IPNDV data¶
[24]:
import ndap
import matplotlib.colors as colors
import matplotlib.cm as cm
from mpl_toolkits.mplot3d import Axes3D
sc=(50.888-50)/50
p=ndap.NDArrayPlotter(tt)
p.set_alpha(0.05)
fig=plt.figure()
ax=fig.add_subplot(111,projection='3d')
fig.set_tight_layout(True)
cmap=cm.viridis
norm=colors.Normalize(vmin=0,vmax=np.max(tt))
p.colors=cmap(norm(tt))
alph=norm(tt)*0.95
p.alphas=alph
sm=plt.cm.ScalarMappable(cmap=cmap,norm=norm)
sm.set_array(tt)
p.render(azim=-56,elev=25,ax=ax,text=None,labels=True,space=0.5)
ax.quiver(-0.4,-0.4,-0.4,1,0,0,length=5,arrow_length_ratio=0.05,color='black')
ax.quiver(-0.4,-0.4,-0.4,0,1,0,length=5,arrow_length_ratio=0.05,color='black')
ax.quiver(-0.4,-0.4,-0.4,0,0,1,length=5,arrow_length_ratio=0.05,color='black')
cbar=plt.colorbar(sm,ax=ax)
cbar.set_label('Event count',rotation=270,fontsize=30,labelpad=30)
plt.show()
Comparing inputs and predictions for Cf and IPNDV data¶
[25]:
d=X_val.detach().numpy()[0]
e=X_val.detach().numpy()[750]
ef=np.zeros([4,4,4])
ef[coords[:,0],coords[:,1],coords[:,2]]=e
ef=np.rot90(ef,2,axes=(0,1))
[26]:
ecounts=ef.flatten()
[27]:
fcounts=d+ecounts
[28]:
dcounts=np.copy(counts)
Note this is trying to account for rotation of the detector¶
[29]:
dcounts[:16]=dcounts[:16][::-1]
dcounts[16:32]=dcounts[16:32][::-1]
dcounts[32:48]=dcounts[32:48][::-1]
dcounts[48:]=dcounts[48:][::-1]
[30]:
fig,ax=plt.subplots(2,2,figsize=(20,10))
fig.set_tight_layout(True)
ax[0,0].bar(np.arange(0,64,1),fcounts/fcounts.sum())
ax[0,0].set_title('Cf cube counts,normalized',fontsize=22)
ax[0,0].set_xlabel('Cube number',fontsize=18)
ax[0,1].bar(np.arange(0,64,1),tcounts/tcounts.sum())
ax[0,1].set_title('96 bare cube counts, normalized',fontsize=22)
ax[0,1].set_xlabel('Cube number',fontsize=18)
ax[1,1].bar(barcentres,model(torch.from_numpy(counts).to(torch.float)).detach().numpy(),edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[1,1].set_xscale('log')
ax[1,1].set_xlabel('Energy / MeV',fontsize=18)
ax[1,1].set_ylabel('Frequency',fontsize=18)
ax[1,1].set_title('Fluence prediction, 96 bare (IPNDV)',fontsize=22)
ax[1,0].bar(barcentres,Y_val[750]+Y_val[0],edgecolor='xkcd:deep blue',width=np.diff(testbins))
ax[1,0].set_xscale('log')
ax[1,0].set_xlabel('Energy / MeV',fontsize=18)
ax[1,0].set_title('Cf fluence target',fontsize=22)
ax[1,0].set_ylabel('Frequency',fontsize=18)
plt.show()
Beyond here is testing of dose calculation, unfinished¶
[35]:
def calc_dose(binvals,centres,coeffs):
E=coeffs['Energy / MeV'].values
AP=coeffs['AP'].values
eff_dose=interp1d(E,AP)
dose=((binvals/400)*eff_dose(centres)).sum(axis=1)
return dose
[ ]:
[36]:
E=coeffs['Energy / MeV'].values
AP=coeffs['AP'].values
eff_dose=interp1d(E,AP)
[37]:
effserrs=np.load('/home/nr1315/Documents/Project/Simulations/Data/Low_scatter_old/simeffs.npy')
[38]:
effserrs[0]/=1e6
[39]:
Y_val[0]
[39]:
tensor([0.0000e+00, 7.7758e+02, 0.0000e+00, 1.5339e+03, 2.1336e+03, 1.5129e+03,
2.4050e+03, 2.8502e+03, 3.5835e+03, 4.0967e+03, 4.8158e+03, 5.3545e+03,
5.8893e+03, 6.2581e+03, 6.4400e+03, 5.8920e+03, 4.7713e+03, 3.3026e+03,
1.6761e+03, 5.9166e+02, 1.1313e+02, 0.0000e+00, 2.2123e+00, 0.0000e+00])
[40]:
xtrain
[40]:
['/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-13_cf-4774_1m5_0deg_sc-stand_1V0_v12.h5',
'/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-14_ambe-30-1679_1m5_+0deg_sc-stand_1V0_v67.h5',
'/home/nr1315/Documents/Project/NPL_2017-06-13/data/nemenix2_npl_2017-06-14_amli_1m5_+0deg_sc-stand_1V0_v55.h5',
'/home/nr1315/Documents/Project/Simulations/Data/Low_scatter_new/4x4normal/thermal.h5']
[41]:
def calc_dose_new(binvals,centres,coeffs,eff):
E=coeffs['Energy / MeV'].values
AP=coeffs['AP'].values
eff_dose=interp1d(E,AP)
efficiency=interp1d(eff[0],eff[1])
dose=((binvals.detach().numpy()/400))*eff_dose(centres)/efficiency(centres)
return dose
[42]:
times=[]
for file in xtrain[:3]:
df=pd.read_hdf(file)
time=df['time'].max()-df['time'].min()
times.append(time)
[43]:
efficiency=interp1d(effserrs[0],effserrs[1])
[ ]:
[44]:
X_counts[:3]
[44]:
[95078.0, 6386.0, 30535.0]
[45]:
sctime=64000*np.array(times)/np.array(X_counts[:3])/1e8
[46]:
calc_dose_new(Y_val[0]/sctime[0],barcentres,coeffs,effserrs)
[46]:
array([ 0. , 0.51202556, 0. , 0.71689412, 1.1773983 ,
1.04159186, 2.16550161, 3.47970837, 6.10912891, 9.55046197,
15.63753709, 24.05948994, 38.3344697 , 58.01321766, 75.54448203,
96.28895568, 89.83380318, 74.00285959, 46.41913814, 20.25659155,
4.87955757, 0. , 0.14702784, 0. ])
[47]:
plt.bar(barcentres,Y_val[0]/sctime[0],edgecolor='xkcd:deep blue',width=np.diff(testbins))
plt.xscale('log')
[ ]:
[48]:
X_val[0]
[48]:
tensor([ 617.0620, 1067.6470, 1001.8536, 1323.8423, 544.2906, 1100.5436,
1080.6062, 866.2794, 460.5536, 665.9086, 654.9431, 593.1372,
257.1923, 328.9668, 439.6193, 380.8040, 1026.7753, 2423.3892,
2194.1091, 1863.1486, 830.3920, 1653.8060, 1790.3771, 1633.8687,
453.5755, 778.5549, 1151.3839, 821.4202, 455.5692, 435.6318,
462.5473, 471.5191, 1112.5060, 1838.2268, 2118.3472, 2001.7134,
939.0508, 1315.8673, 1655.7998, 1402.5950, 494.4471, 1030.7628,
836.3733, 833.3826, 518.3720, 474.5097, 550.2718, 452.5786,
1024.7815, 2227.0059, 2357.5957, 1797.3552, 783.5392, 917.1197,
1592.9969, 1201.2274, 556.2530, 632.0151, 913.1322, 847.3388,
382.7978, 434.6350, 481.4878, 446.5974])
[49]:
Y_val[0]
[49]:
tensor([0.0000e+00, 7.7758e+02, 0.0000e+00, 1.5339e+03, 2.1336e+03, 1.5129e+03,
2.4050e+03, 2.8502e+03, 3.5835e+03, 4.0967e+03, 4.8158e+03, 5.3545e+03,
5.8893e+03, 6.2581e+03, 6.4400e+03, 5.8920e+03, 4.7713e+03, 3.3026e+03,
1.6761e+03, 5.9166e+02, 1.1313e+02, 0.0000e+00, 2.2123e+00, 0.0000e+00])
[ ]:
[ ]:
[ ]:
[ ]: