diff --git a/docker/apmtools/APT_analyzer.ipynb b/docker/apmtools/APT_analyzer.ipynb deleted file mode 100644 index a329a8d0b1787c5f3081d6be1edd4611d60d1ecb..0000000000000000000000000000000000000000 --- a/docker/apmtools/APT_analyzer.ipynb +++ /dev/null @@ -1,1214 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "c15820a3", - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "%reset -f\n", - "from tkinter import *\n", - "from tkinter.ttk import Combobox\n", - "from tkinter import messagebox\n", - "from tkinter import filedialog\n", - "import matplotlib.pyplot as plt\n", - "from matplotlib.figure import Figure\n", - "from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)\n", - "import numpy as np\n", - "import apt_importers as apt\n", - "import math\n", - "from matplotlib import gridspec\n", - "import re\n", - "from tkinter.filedialog import asksaveasfile\n", - "import tkinter.scrolledtext as tkst\n", - "import webbrowser\n", - "from mpl_toolkits.mplot3d import proj3d\n", - "import pandas as pd\n", - "import h5py\n", - "\n", - "def data_for_cylinder_along_z(center_x,center_y,center_z,radius,height_z):\n", - " z = np.linspace(center_z-height_z/2, center_z+height_z/2, 50)\n", - " theta = np.linspace(0, 2*np.pi, 50)\n", - " theta_grid, z_grid=np.meshgrid(theta, z)\n", - " x_grid = radius*np.cos(theta_grid) + center_x\n", - " y_grid = radius*np.sin(theta_grid) + center_y\n", - " return x_grid,y_grid,z_grid\n", - "\n", - "def gerade(k,x,d):\n", - " return k*x+d\n", - "\n", - "class APT_analyzer(): # define class object \n", - " def __init__(self,tk): # initialize when starting tkinter\n", - " self.plot_exist=0\n", - " self.conc_check=0\n", - " self.excess_check=0\n", - " self.invert=0\n", - " self.data_color=['blue','red','green','yellow','purple','black','white','grey','brown'] # colors of cylinder to be seletected\n", - " self.color_cp=['blue','red','green','yellow','purple','black','white','grey','brown']\n", - " self.frame=Frame(tk) # setting up frame\n", - " self.frame.pack(expand=True,fill=BOTH) # placing frame\n", - " self.canvas_all=Canvas(self.frame,width=1400,height=800,scrollregion=(0,0,1550,850)) #setting up canvas onto frame\n", - " ################# scroll bars vertical and horizontal ################\n", - " self.hbar=Scrollbar(self.frame,orient=HORIZONTAL) # setting up horizontal scrollbar\n", - " self.hbar.pack(side=TOP,fill=X) # placing horizontal scrollbar on the top side\n", - " self.hbar.config(command=self.canvas_all.xview) # configurating horizontal scrollbar\n", - " self.vbar=Scrollbar(self.frame,orient=VERTICAL) # setting up vertical scrollbar\n", - " self.vbar.pack(side=LEFT,fill=Y) # placing vertical scrollbar on the left side\n", - " self.vbar.config(command=self.canvas_all.yview) # configurating vertical scrollbar\n", - " self.canvas_all.config(yscrollcommand=self.vbar.set,xscrollcommand=self.hbar.set) #configurating canvas\n", - " \n", - "\n", - " self.b_page1_loading = Button(self.canvas_all, text=\"1. Load\", command=self.page_1,font=('helvetica',12,'bold')) # button for tip calculation\n", - " self.canvas_all.create_window(75,20,window=self.b_page1_loading)\n", - " \n", - " self.b_page2_visualize = Button(self.canvas_all, text=\"2. Visualize\", command=self.page_2,font=('helvetica',12,'bold')) # button for tip calculation\n", - " self.canvas_all.create_window(180,20,window=self.b_page2_visualize)\n", - " \n", - " self.b_page3_cylinder = Button(self.canvas_all, text=\"3. Calculate\", command=self.page_3,font=('helvetica',12,'bold')) # button for tip calculation\n", - " self.canvas_all.create_window(300,20,window=self.b_page3_cylinder)\n", - "\n", - " ############## initiate values #######################################\n", - " #### page 1 #### \n", - " self.succ=0\n", - " self.utext0=Label(self.canvas_all,text='Welcome to the APT-analyzer!') # title of segment\n", - " self.utext1=Label(self.canvas_all,text='This open source tool enables you to look at and analyze APT tips ') # title of segment\n", - " self.utext2=Label(self.canvas_all,text='All you need is a .pos (or .epos) file and a .rrng file') # title of segment\n", - " self.utext3=Label(self.canvas_all,text='Select the files you want to look at below and press \"Load files\"') # title of segment\n", - " self.utext4=Label(self.canvas_all,text='------------- Initiate files --------------') # title of segment\n", - " self.b_pos_file = Button(self.canvas_all,bg='green',fg='white', text=\"Select .pos /.epos file\", command=self.search_pos) # button for pos file initiation\n", - " self.b_rrng_file = Button(self.canvas_all,bg='green',fg='white', text=\"Select .rrng file\", command=self.search_rrng) # button for rrng file initiation\n", - " self.b_calc_tip = Button(self.canvas_all, text=\"Load files\", command=self.calculate_tip,bg='blue',fg='white',font=('helvetica',14,'bold')) # button for tip calculation\n", - " self.dtext0=Label(self.canvas_all,text='The loading of the files may take some time.') # title of segment\n", - " self.dtext1=Label(self.canvas_all,text='When \"Sucessfully loaded files!\" appears underneath the Load button') # title of segment\n", - " self.dtext2=Label(self.canvas_all,text='then everthing is working as intendet') # title of segment\n", - " self.dtext3=Label(self.canvas_all,text='and a preview image of the tip should appear on the right') # title of segment \n", - " self.dtext4=Label(self.canvas_all,text='You may now go to section 2.Visualize (top middle)') # title of segment\n", - " self.dtext5=Label(self.canvas_all,text='where you have more options for the visalization') # title of segment\n", - " self.dtext6=Label(self.canvas_all,text='as well as the ability to set control points and print them') # title of segment\n", - " self.dtext7=Label(self.canvas_all,text='After that you can go to section 3.Calculate (top right)') # title of segment\n", - " self.dtext8=Label(self.canvas_all,text='To calculate the concentration profile and excess profile') # title of segment\n", - " self.dtext9=Label(self.canvas_all,text='of a cylinder area which you can select within the tip') # title of segment\n", - " self.label_help=Label(self.canvas_all,text='if you need help press this button:') # title of segment\n", - " self.b_help = Button(self.canvas_all, text=\"help\",bg='orange',fg='black',command=self.help_web,font=('helvetica',14,'bold')) # button for tip calculation\n", - " \n", - " #### page 2 ####\n", - " self.cb_atom = Combobox(tk, values='') \n", - "\n", - " self.diss=0\n", - " self.diss2=0\n", - " self.slider_image_size_cv=DoubleVar()\n", - " self.slider_image_size = Scale(self.canvas_all,from_=1,to=5,orient='horizontal',variable=self.slider_image_size_cv,showvalue=0)\n", - " self.label_plot_tip=Label(self.canvas_all,text='------------- plot options ---------------') # title of segment\n", - " self.label_image_size=Label(self.canvas_all,text='Select image size') # label for resolution\n", - " self.label_slider_res=Label(self.canvas_all,text='small')\n", - " self.label_slider_res2=Label(self.canvas_all,text='large') \n", - " self.slider_image_size.set(3)\n", - " self.b_plot1 = Button(self.canvas_all, text=\"plot tip\", command=self.plot_tip,bg='blue',fg='white',font=('helvetica',14,'bold')) # button for plotting the tip\n", - " self.var_axis=IntVar()\n", - " self.check_axis = Checkbutton(self.canvas_all,text=\"Hide Axes\", onvalue=1, offvalue=0,variable=self.var_axis,font=('helvetica', 10,'bold'))\n", - " self.label_resolution=Label(self.canvas_all,text='Select number of atoms') # label for resolution\n", - " self.label_select_atom=Label(self.canvas_all,text='Select atom type')\n", - " self.slider_res_cv=DoubleVar()\n", - " self.label_slider_res3=Label(self.canvas_all,text='small')\n", - " self.label_slider_res4=Label(self.canvas_all,text='large')\n", - " self.slider_res = Scale(self.canvas_all,from_=1,to=5,orient='horizontal',variable=self.slider_res_cv,showvalue=0)\n", - " self.slider_res.set(1)\n", - " self.label_select_atom_size=Label(self.canvas_all,text='Select atom size')\n", - " self.slider_size_cv=DoubleVar()\n", - " self.slider_size = Scale(self.canvas_all,from_=1,to=200,orient='horizontal',variable=self.slider_size_cv,showvalue=0)\n", - " self.label_slider_res5=Label(self.canvas_all,text='small')\n", - " self.label_slider_res6=Label(self.canvas_all,text='large') \n", - " self.slider_size.set(50)\n", - " self.i_plot=IntVar()\n", - " self.cb_inverse=Checkbutton(self.canvas_all, text='Flip Tip', onvalue=1, offvalue=0, variable=self.i_plot, font=('helvetica', 10,'bold')) \n", - " self.control=IntVar()\n", - " self.label_control=Checkbutton(self.canvas_all, text='create control points by clicking on screen', onvalue=1, offvalue=0, variable=self.control, font=('helvetica', 10,'bold')) \n", - " self.text_box = Text(self.canvas_all,height=10, width=35)\n", - " self.b_control_print = Button(self.canvas_all, text=\"print\",bg='green', command=self.save,fg='white',font=('helvetica',12,'bold')) # button for pos file initiation\n", - " self.b_control_clear = Button(self.canvas_all, text=\"clear\",bg='red', command=self.clear_text,fg='white',font=('helvetica',12,'bold')) # button for pos file initiation\n", - " self.var_points=IntVar()\n", - " self.check_points = Checkbutton(self.canvas_all,text=\"plot with points\", onvalue=1, offvalue=0,variable=self.var_points,font=('helvetica', 10,'bold'))\n", - " self.b_adjust_cly = Button(self.canvas_all, text=\"adjust cylinder according to points\",bg='yellow',fg='black', command=self.adjust,font=('helvetica',10,'bold')) # button for pos file initiation \n", - " self.cb_color_cp = Combobox(tk, values=self.color_cp, width=10) \n", - " self.cb_color_cp.current(0)\n", - " self.var_plane=IntVar()\n", - " self.label_color_cp=Label(self.canvas_all,text='color of control points') \n", - " self.check_plane = Checkbutton(self.canvas_all,text=\"show fit plane and normal vector\", onvalue=1, offvalue=0,variable=self.var_plane,font=('helvetica', 10,'bold'))\n", - " \n", - " #### page 3 ####\n", - " self.var_cyl=IntVar()\n", - " self.label_conc=Label(self.canvas_all,text='------------ concentration calculation option ------------')#.place(x=20,y=400) # title of segment\n", - " self.var_cyl=IntVar()\n", - " self.check_cylinder = Checkbutton(self.canvas_all,text=\"show cylinder for concentration calculation\", onvalue=1, offvalue=0,variable=self.var_cyl,font=('helvetica', 10,'bold'))#.place(x=20,y=220)\n", - " \n", - " self.b_calc_conc = Button(self.canvas_all, text=\"plot concentration\", command=self.calc_con,bg='blue',fg='white',font=('helvetica',12,'bold')) # button for calculating the concentration of cylinder\n", - " self.b_calc_excess = Button(self.canvas_all, text=\"plot excess\", command=self.calc_excess,bg='blue',fg='white',font=('helvetica',12,'bold')) # button for calculating the concentration of cylinder\n", - " self.b_plot_cyl = Button(self.canvas_all, text=\"plot cylinder\", command=self.calc_zoom,bg='blue',fg='white',font=('helvetica',13,'bold')) # button for calculating the concentration of cylinder\n", - " self.b_print_ex = Button(self.canvas_all, text=\"print excess\", command=self.save_excess,bg='green',fg='white',font=('helvetica',13,'bold')) # button for calculating the concentration of cylinder\n", - " \n", - " self.label_cly_pos=Label(self.canvas_all,text='cylinder center position')\n", - " self.label_cly_x=Label(self.canvas_all,text='x')\n", - " self.cly_x=StringVar(value='0')\n", - " self.entry_cly_x=Entry(self.canvas_all,textvariable=self.cly_x,width=10) \n", - " self.label_cly_y=Label(self.canvas_all,text='y') \n", - " self.cly_y=StringVar(value='0')\n", - " self.entry_cly_y=Entry(self.canvas_all,textvariable=self.cly_y,width=10) \n", - " self.label_cly_z=Label(self.canvas_all,text='z')\n", - " self.cly_z=StringVar(value='0')\n", - " self.entry_cly_z=Entry(self.canvas_all,textvariable=self.cly_z,width=10)\n", - " self.label_cly_radius=Label(self.canvas_all,text='radius of cylinder') \n", - " self.radius=StringVar(value='10')\n", - " self.entry_cly_radius=Entry(self.canvas_all,textvariable=self.radius) \n", - " self.label_cly_height=Label(self.canvas_all,text='height of cylinder') \n", - " self.height=StringVar(value='30')\n", - " self.entry_cly_height=Entry(self.canvas_all,textvariable=self.height) \n", - " self.label_cly_beta=Label(self.canvas_all,text='tilt along x-axis')\n", - " self.beta=StringVar(value='0')\n", - " self.entry_cly_beta=Entry(self.canvas_all,textvariable=self.beta)\n", - " self.label_cly_alpha=Label(self.canvas_all,text='tilt along y-axis')\n", - " self.alpha=StringVar(value='0')\n", - " self.entry_cly_alpha=Entry(self.canvas_all,textvariable=self.alpha)\n", - " self.label_color_cyl=Label(self.canvas_all,text='color of the cylinder') # label for cylinder color\n", - " self.cb_color = Combobox(self.canvas_all, values=self.data_color)\n", - " self.cb_color.current(0) \n", - " self.label_inter=Label(self.canvas_all,text='Select interval') # label for resolution\n", - " self.slider_inter_cv=DoubleVar()\n", - " self.label_slider_inter=Label(self.canvas_all,text='small large') # title of segment\n", - " self.slider_inter = Scale(self.canvas_all,from_=1,to=20,orient='horizontal',variable=self.slider_inter_cv,showvalue=0)#Combobox(self.canvas_all, values=self.data_res) # combobox for resolution\n", - " self.slider_inter.set(15)\n", - " self.b_plot2 = Button(self.canvas_all, text=\"plot tip\", command=self.plot_tip,bg='blue',fg='white',font=('helvetica',13,'bold')) # button for plotting the tip\n", - " self.b_print_conc = Button(self.canvas_all, text=\"print concentration\", command=self.save_conc,bg='green',fg='white',font=('helvetica',13,'bold')) # button for plotting the tip\n", - " self.var_norm=IntVar()\n", - " self.check_norm = Checkbutton(self.canvas_all,text=\"normalize Excess\", onvalue=1, offvalue=0,variable=self.var_norm)\n", - " self.var_switch=IntVar()\n", - " self.check_switch = Checkbutton(self.canvas_all,text=\"set cylinders as bulk*\", onvalue=1, offvalue=0,variable=self.var_switch)\n", - " self.label_astrix=Label(self.canvas_all,text='* the conc. of each segment is calculated in relation to the ends') \n", - " self.data_bulk=['start','end']\n", - " self.cb_bulk = Combobox(tk, values=self.data_bulk, width=4) \n", - " self.cb_bulk.current(0)\n", - " self.text_box_ex = Text(self.canvas_all,height=6, width=25)\n", - " #self.cb_exp=Checkbutton(self.canvas_all, text='create points for excess calculation', onvalue=1, offvalue=0, variable=self.control, font=('helvetica', 10,'bold')) \n", - " self.label_exp=Label(self.canvas_all,text='For calcuating the excess select 4 points') \n", - " \n", - " \n", - " ############## setting up page 1 ##################\n", - " self.a1=self.canvas_all.create_window(200,50,window=self.utext0) \n", - " self.a2=self.canvas_all.create_window(200,70,window=self.utext1) \n", - " self.a3=self.canvas_all.create_window(200,90,window=self.utext2) \n", - " self.a4=self.canvas_all.create_window(200,110,window=self.utext3) \n", - " self.a5=self.canvas_all.create_window(200,140,window=self.utext4) \n", - " self.a6=self.canvas_all.create_window(120,165,window=self.b_pos_file) \n", - " self.a7=self.canvas_all.create_window(280,165,window=self.b_rrng_file) \n", - " self.a8=self.canvas_all.create_window(200,230,window=self.b_calc_tip)\n", - " self.a9=self.canvas_all.create_window(200,300,window=self.dtext0) \n", - " self.a10=self.canvas_all.create_window(200,320,window=self.dtext1) \n", - " self.a11=self.canvas_all.create_window(200,340,window=self.dtext2) \n", - " self.a12=self.canvas_all.create_window(200,360,window=self.dtext3) \n", - " self.a13=self.canvas_all.create_window(200,400,window=self.dtext4) \n", - " self.a14=self.canvas_all.create_window(200,420,window=self.dtext5) \n", - " self.a15=self.canvas_all.create_window(200,440,window=self.dtext6)\n", - " self.a16=self.canvas_all.create_window(200,460,window=self.dtext7)\n", - " self.a17=self.canvas_all.create_window(200,480,window=self.dtext8)\n", - " self.a18=self.canvas_all.create_window(200,500,window=self.dtext9)\n", - " self.a19=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a20=self.canvas_all.create_window(200,560,window=self.b_help)\n", - " self.a21=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a22=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a23=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a24=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a25=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a26=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a27=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a28=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a29=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a30=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a31=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a32=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a33=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a34=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " \n", - " ###################### setup figures ################################# \n", - " self.fig=Figure(figsize=(17,13)) # defining figure size\n", - " self.canvas=FigureCanvasTkAgg(self.fig,master=self.canvas_all) # setting up canvas for figure\n", - " self.toolbar=NavigationToolbar2Tk(self.canvas, self.canvas_all) # setting up toolbar for figure\n", - " self.canvas_all.create_window(400,10,window=self.canvas.get_tk_widget(),anchor=N+W,tags='canvas') #placing figure canvas on general canvas\n", - " self.canvas_all.pack(expand=True,fill=BOTH) # placing general canvas at the end\n", - " self.E=2 # setting up variable to check if .pos/.epos file is selected\n", - " self.R=2 # setting up variable to check if .rrng file is selected \n", - " \n", - " def page_1(self):\n", - " self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34) \n", - " if self.succ==1:self.a_succ=self.canvas_all.create_window(200,260,window=self.label_succ) #placing label on canvas\n", - " if self.R==1:self.aRS=self.canvas_all.create_window(280,190,window=self.label_rrng_selected)\n", - " if self.R==0:self.aR=self.canvas_all.create_window(280,190,window=self.label_rrng_selected)\n", - " if self.E==0:self.aE=self.canvas_all.create_window(120,190,window=self.label_pos_selected)\n", - " if self.E==1:self.aES=self.canvas_all.create_window(120,190,window=self.label_pos_selected)\n", - " \n", - " self.a1=self.canvas_all.create_window(200,50,window=self.utext0) \n", - " self.a2=self.canvas_all.create_window(200,70,window=self.utext1) \n", - " self.a3=self.canvas_all.create_window(200,90,window=self.utext2) \n", - " self.a4=self.canvas_all.create_window(200,110,window=self.utext3) \n", - " self.a5=self.canvas_all.create_window(200,140,window=self.utext4) \n", - " self.a6=self.canvas_all.create_window(120,165,window=self.b_pos_file) \n", - " self.a7=self.canvas_all.create_window(280,165,window=self.b_rrng_file) \n", - " self.a8=self.canvas_all.create_window(200,230,window=self.b_calc_tip)\n", - " self.a9=self.canvas_all.create_window(200,300,window=self.dtext0) \n", - " self.a10=self.canvas_all.create_window(200,320,window=self.dtext1) \n", - " self.a11=self.canvas_all.create_window(200,340,window=self.dtext2) \n", - " self.a12=self.canvas_all.create_window(200,360,window=self.dtext3) \n", - " self.a13=self.canvas_all.create_window(200,400,window=self.dtext4) \n", - " self.a14=self.canvas_all.create_window(200,420,window=self.dtext5) \n", - " self.a15=self.canvas_all.create_window(200,440,window=self.dtext6)\n", - " self.a16=self.canvas_all.create_window(200,460,window=self.dtext7)\n", - " self.a17=self.canvas_all.create_window(200,480,window=self.dtext8)\n", - " self.a18=self.canvas_all.create_window(200,500,window=self.dtext9)\n", - " self.a19=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a20=self.canvas_all.create_window(200,560,window=self.b_help)\n", - " self.a21=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a22=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a23=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a24=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a25=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a26=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a27=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a28=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a29=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a30=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a31=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a32=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a33=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " self.a34=self.canvas_all.create_window(200,520,window=self.label_help)\n", - " \n", - " def page_2(self):\n", - " self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34) \n", - " if self.R==1:self.canvas_all.delete(self.aRS)\n", - " if self.R==0:self.canvas_all.delete(self.aR)\n", - " if self.E==0:self.canvas_all.delete(self.aE)\n", - " if self.E==1:self.canvas_all.delete(self.aES)\n", - " if self.succ==1: self.canvas_all.delete(self.a_succ)\n", - " ############## setting up buttons, Scales, comboboxes, etc. for plot options ################### \n", - " self.a1=self.canvas_all.create_window(200,50,window=self.label_plot_tip) \n", - " self.a2=self.canvas_all.create_window(100,80,window=self.label_image_size) \n", - " self.a3=self.canvas_all.create_window(30,105,window=self.label_slider_res) \n", - " self.a4=self.canvas_all.create_window(170,105,window=self.label_slider_res2) \n", - " self.a5=self.canvas_all.create_window(100,105,window=self.slider_image_size) \n", - " self.a6=self.canvas_all.create_window(250,300,window=self.b_plot1) \n", - " self.a7=self.canvas_all.create_window(280,170,window=self.check_axis) \n", - " self.a8=self.canvas_all.create_window(100,145,window=self.label_resolution) \n", - " self.a9=self.canvas_all.create_window(280,80,window=self.label_select_atom) \n", - " self.a10=self.canvas_all.create_window(30,170,window=self.label_slider_res3) \n", - " self.a11=self.canvas_all.create_window(170,170,window=self.label_slider_res4) \n", - " self.a12=self.canvas_all.create_window(100,170,window=self.slider_res) \n", - " self.a13=self.canvas_all.create_window(100,210,window=self.label_select_atom_size) \n", - " self.a14=self.canvas_all.create_window(30,230,window=self.label_slider_res5) \n", - " self.a15=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a16=self.canvas_all.create_window(100,230,window=self.slider_size) \n", - " self.a17=self.canvas_all.create_window(280,230,window=self.cb_inverse) \n", - " self.a18=self.canvas_all.create_window(280,110,window=self.cb_atom) # putting combobox with element selection on canvas\n", - " self.a19=self.canvas_all.create_window(200,350,window=self.label_control) \n", - " self.a20=self.canvas_all.create_window(200,450,window=self.text_box) \n", - " self.a21=self.canvas_all.create_window(100,560,window=self.b_control_print) \n", - " self.a22=self.canvas_all.create_window(300,560,window=self.b_control_clear) \n", - " self.a23=self.canvas_all.create_window(200,560,window=self.check_points) \n", - " self.a24=self.canvas_all.create_window(200,600,window=self.b_adjust_cly)\n", - " self.a25=self.canvas_all.create_window(100,310,window=self.cb_color_cp)\n", - " self.a26=self.canvas_all.create_window(100,290,window=self.label_color_cp)\n", - " self.a27=self.canvas_all.create_window(200,630,window=self.check_plane) \n", - " self.a28=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a29=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a30=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a31=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a32=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a33=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " self.a34=self.canvas_all.create_window(170,230,window=self.label_slider_res6)\n", - " def page_3(self):\n", - " self.canvas_all.delete(self.a1,self.a2,self.a3,self.a4,self.a5,self.a6,self.a7,self.a8,self.a9,self.a10,self.a11,self.a12,self.a13,self.a14,self.a15,self.a16,self.a17,self.a18,self.a19,self.a20,self.a21,self.a22,self.a23,self.a24,self.a25,self.a26,self.a27,self.a28,self.a29,self.a30,self.a31,self.a32,self.a33,self.a34) \n", - " if self.R==1:self.canvas_all.delete(self.aRS)\n", - " if self.R==0:self.canvas_all.delete(self.aR)\n", - " if self.E==0:self.canvas_all.delete(self.aE)\n", - " if self.E==1:self.canvas_all.delete(self.aES)\n", - " if self.succ==1: self.canvas_all.delete(self.a_succ)\n", - " ########### setting up buttons, Scales, comboboxes etc. for cylinder selection and concentration calculations ###################\n", - " self.label_exp=Label(self.canvas_all,text='For calcuating the excess select 4 points') \n", - " self.entry_cly_x=Entry(self.canvas_all,textvariable=self.cly_x,width=10) \n", - " self.entry_cly_y=Entry(self.canvas_all,textvariable=self.cly_y,width=10)\n", - " self.entry_cly_z=Entry(self.canvas_all,textvariable=self.cly_z,width=10)\n", - " self.entry_cly_alpha=Entry(self.canvas_all,textvariable=self.alpha)\n", - " self.entry_cly_beta=Entry(self.canvas_all,textvariable=self.beta)\n", - " \n", - " self.a1=self.canvas_all.create_window(200,50,window=self.label_conc) \n", - " self.a2=self.canvas_all.create_window(200,90,window=self.check_cylinder) \n", - " self.a3=self.canvas_all.create_window(100,450,window=self.b_calc_conc) \n", - " self.a4=self.canvas_all.create_window(100,500,window=self.b_calc_excess) \n", - " self.a5=self.canvas_all.create_window(300,400,window=self.b_plot_cyl) \n", - " self.a6=self.canvas_all.create_window(300,500,window=self.b_print_ex) \n", - " self.a7=self.canvas_all.create_window(200,120,window=self.label_cly_pos) \n", - " self.a8=self.canvas_all.create_window(100,140,window=self.label_cly_x) \n", - " self.a9=self.canvas_all.create_window(100,170,window=self.entry_cly_x) \n", - " self.a10=self.canvas_all.create_window(200,140,window=self.label_cly_y) \n", - " self.a11=self.canvas_all.create_window(200,170,window=self.entry_cly_y) \n", - " self.a12=self.canvas_all.create_window(300,140,window=self.label_cly_z) \n", - " self.a13=self.canvas_all.create_window(300,170,window=self.entry_cly_z)\n", - " self.a14=self.canvas_all.create_window(100,200,window=self.label_cly_radius)\n", - " self.a15=self.canvas_all.create_window(100,225,window=self.entry_cly_radius) \n", - " self.a16=self.canvas_all.create_window(300,200,window=self.label_cly_height) \n", - " self.a17=self.canvas_all.create_window(300,225,window=self.entry_cly_height) \n", - " self.a18=self.canvas_all.create_window(100,255,window=self.label_cly_beta) \n", - " self.a19=self.canvas_all.create_window(100,280,window=self.entry_cly_beta) \n", - " self.a20=self.canvas_all.create_window(300,255,window=self.label_cly_alpha) \n", - " self.a21=self.canvas_all.create_window(300,280,window=self.entry_cly_alpha) \n", - " self.a22=self.canvas_all.create_window(100,330,window=self.label_color_cyl) \n", - " self.a23=self.canvas_all.create_window(100,355,window=self.cb_color) \n", - " self.a24=self.canvas_all.create_window(300,310,window=self.label_inter) \n", - " self.a25=self.canvas_all.create_window(300,330,window=self.label_slider_inter) \n", - " self.a26=self.canvas_all.create_window(300,355,window=self.slider_inter) \n", - " self.a27=self.canvas_all.create_window(100,400,window=self.b_plot2) \n", - " self.a28=self.canvas_all.create_window(300,450,window=self.b_print_conc)\n", - " self.a29=self.canvas_all.create_window(100,550,window=self.check_norm)\n", - " self.a30=self.canvas_all.create_window(260,550,window=self.check_switch)\n", - " self.a31=self.canvas_all.create_window(220,580,window=self.label_astrix)\n", - " self.a32=self.canvas_all.create_window(280,550,window=self.cb_bulk)\n", - " self.a33=self.canvas_all.create_window(200,610,window=self.label_exp)\n", - " self.a34=self.canvas_all.create_window(200,675,window=self.text_box_ex)\n", - " \n", - " def help_web(self):\n", - " url='https://github.com/areichm/APT_analyzer'\n", - " new=1\n", - " webbrowser.open(url,new=new)\n", - " \n", - " def clear_text(self): \n", - " self.text_box.delete('1.0', END)\n", - " \n", - " def save(self):\n", - " points=self.text_box.get(1.0,END)\n", - " points=points.split('\\n')\n", - " points=[x for x in points if x!='']\n", - " xyz=[]\n", - " for i in range(0,len(points)):\n", - " points_inner=points[i].split(',')\n", - " for j in points_inner:\n", - " m=j.split('=')\n", - " xyz.append(m[1])\n", - " # with np.unique now contains only the unique data\n", - " data=np.unique(np.array(xyz).reshape(int(len(xyz)/3),3), axis=0)\n", - " # ##MK::sprint 09\n", - " # using here df.to_hdf via pandas needs pandas==1.4.4 with pytables compiled under the hood !\n", - " # pytables however is not directly available as a compiled package via pypi\n", - " # in conda pytables is precompiled inside the conda package already\n", - " # label=('x','y','z') \n", - " # df=pd.DataFrame(data,columns=label)\n", - " h5File = \"controlpoints.h5\"\n", - " # df.to_hdf(h5File,'data')\n", - " # instead use h5py directly\n", - " h5w = h5py.File(h5File, 'w')\n", - " dst = h5w.create_dataset('/xyz', data=np.asarray(data, np.float32))\n", - " dst.attrs[\"units\"] = \"nm\"\n", - " h5w.close()\n", - " messagebox.showinfo(title='APT_analyzer',message='Control points saved to hdf5 file: \"controlpoints.h5\" inside the APT-analyzer folder.')\n", - "\n", - " def save_conc(self):\n", - " if self.conc_check==0:messagebox.showinfo(title='APT_analyzer',message='please plot concentration first')\n", - " else: \n", - " self.df_con.to_csv('APT_analyzer_concentration.csv')\n", - " messagebox.showinfo(title='APT_analyzer',message='Control points saved to csv file: \"APT_analyzer_concentration.csv\" inside the APT-analyzer folder.')\n", - " \n", - " def save_excess(self):\n", - " if self.excess_check==0:messagebox.showinfo(title='APT_analyzer',message='please plot excess first')\n", - " else: \n", - " self.df_ex.to_csv('APT_analyzer_excess.csv')\n", - " messagebox.showinfo(title='APT_analyzer',message='Control points saved to csv file: \"APT_analyzer_excess.csv\" inside the APT-analyzer folder.')\n", - " \n", - " def adjust(self): # adjust cylinder according to controlpoints\n", - " self.var_cyl.set(1)\n", - " XX=[] # setting up arrays\n", - " YY=[]\n", - " ZZ=[]\n", - " points=self.text_box.get(1.0,END) # get text from text box\n", - " points=points.split('\\n') # split the text into each row\n", - " points=[x for x in points if x!=''] # remove any rows that dont contain information\n", - " for i in range(0,len(points)): # loop over all rows\n", - " points_inner=points[i].split(',') # split each row into parts of each coordinates\n", - " xyz2=[]\n", - " for j in points_inner: # loop over all values inside row\n", - " m=j.split('=') # isolate actual number\n", - " xyz2.append(m[1]) # save number\n", - " XX.append(float(xyz2[0])) # save x,y and z coordinate\n", - " YY.append(float(xyz2[1]))\n", - " if self.i_plot.get()==0:ZZ.append(float(xyz2[2]))\n", - " if self.i_plot.get()==1:ZZ.append(-float(xyz2[2])) # if inverse tip is selected reverse z coordinate\n", - " \n", - " if len(XX)>=3: # if 3 or more control points are chosen\n", - " center_x=round(sum(XX)/len(XX),3) # calculate center in x, y and z\n", - " center_y=round(sum(YY)/len(YY),3)\n", - " if self.i_plot.get()==0:center_z=round(sum(ZZ)/len(ZZ),3)\n", - " if self.i_plot.get()==1:center_z=round(-sum(ZZ)/len(ZZ),3)\n", - " self.cly_x=StringVar(value=center_x) #save the center as coordinates for cylinder\n", - " self.cly_y=StringVar(value=center_y)\n", - " self.cly_z=StringVar(value=center_z)\n", - " tmp_C=[]\n", - " for i in range(len(XX)):\n", - " tmp_C.append([XX[i],YY[i],ZZ[i]]) #write x,y and z into one matrix and transpose it below\n", - " C=np.array(tmp_C).T\n", - " svd=np.linalg.svd(C - np.mean(C, axis=1, keepdims=True)) # using singular value decomposition to find fit\n", - " left=svd[0] # upper line has to substract out the centroid first\n", - " fit=left[:,-1]\n", - " normal=np.array([fit[0],fit[1],fit[2]])\n", - " norm=np.linalg.norm(normal)\n", - " n_n=normal/norm # select fitted values\n", - " aa=np.arcsin(-n_n[1])\n", - " bb=math.atan2(n_n[0],n_n[2]) # this is done by applying rotation matrix in reverse order onto normal verctor\n", - " # and then solving the equation for alpha and beta\n", - " #al=round(math.degrees(aa),4) # that rotate the normal vector into x=0 and y=0\n", - " #if normal[2]<0:al=round(math.degrees(-aa),4)\n", - " al=round(math.degrees(aa),4)\n", - " be=round(math.degrees(bb),4)\n", - " self.alpha=StringVar(value=al) # then transforming into degree and \n", - " self.beta=StringVar(value=be) # saving alpha and beta values into entry field\n", - " else: messagebox.showinfo(title='APT_analyzer',message='Choose at least 3 control points') # if less than 3 points are selected show message\n", - " \n", - " def search_pos(self): # function for searching for pos/epos file\n", - " if self.E==0:self.canvas_all.delete(self.aE)\n", - " if self.E==1:self.canvas_all.delete(self.aES)\n", - " self.filename=filedialog.askopenfilename() # getting file from search\n", - " S='.POS' in self.filename # checking if .POS is in the filename\n", - " ES='.EPOS' in self.filename # checking if .EPOS is in the filename\n", - " s='.pos' in self.filename # checking if .pos is in the filename\n", - " es='.epos' in self.filename # checking if .epos is in the filename\n", - " if S or s is True: # if .POS or .pos was selected\n", - " self.label_pos_selected=Label(text='pos file selected') # create label for pos\n", - " self.aE=self.canvas_all.create_window(120,190,window=self.label_pos_selected) #placing label on canvas\n", - " self.E=0 # set variable for later recognition\n", - " if self.succ==1: self.canvas_all.delete(self.a_succ) \n", - " self.succ=0\n", - " elif ES or es is True: # if .EPOS or .epos was selected\n", - " self.label_pos_selected=Label(text='epos file selected') # creating label for epos\n", - " self.aES=self.canvas_all.create_window(120,190,window=self.label_pos_selected) #put label on canvas\n", - " self.E=1 # set variable for later recognition\n", - " if self.succ==1: self.canvas_all.delete(self.a_succ) \n", - " self.succ=0\n", - " else: # if any other filetype was selected\n", - " messagebox.showinfo(title='APT_analyzer',message='select .pos or .epos file. Warning: Notation has to be either .pos /.epos or .POS / .EPOS')\n", - " self.filename=[] # leave filename empty\n", - " self.E=2 # set variable back to 2\n", - " \n", - " def search_rrng(self): # function for searching for rrng file\n", - " if self.R==1:self.canvas_all.delete(self.aRS)\n", - " if self.R==0:self.canvas_all.delete(self.aR)\n", - " self.filename2=filedialog.askopenfilename() # getting file from search\n", - " S='.RRNG' in self.filename2 # checking if .RRNG is in the filename\n", - " s='.rrng' in self.filename2 # checking if .rrng is in the filename\n", - " SR='.RNG' in self.filename2\n", - " sr='.rng' in self.filename2\n", - " if S or s is True: # if .RRNG or .rrng was selected\n", - " self.label_rrng_selected=Label(text='.rrng file selected') # create label for rrng\n", - " self.aR=self.canvas_all.create_window(280,190,window=self.label_rrng_selected) #placing label on canvas\n", - " self.R=0 # setting variable for later recognition\n", - " if self.succ==1: self.canvas_all.delete(self.a_succ) \n", - " self.succ=0\n", - " elif SR or sr is True:\n", - " self.label_rrng_selected=Label(text='.rng file selected') # create label for rrng\n", - " self.aRS=self.canvas_all.create_window(280,190,window=self.label_rrng_selected) #placing label on canvas\n", - " self.R=1 \n", - " if self.succ==1: self.canvas_all.delete(self.a_succ) \n", - " self.succ=0\n", - " else: # if no correct file was selected\n", - " messagebox.showinfo(title='APT_analyzer',message='select .rrng file. Warning: Notation has to be either .rrng or .RRNG')\n", - " self.filename2=[] # leaving filename empty\n", - " self.R=2 # set variable back to 2\n", - " \n", - " def calculate_tip(self): # function for reading and converting the pos and rrng file and creating the tip\n", - " if self.E==2:messagebox.showinfo(title='APT_analyzer',message='no file .pos/.epos file selected') # checking if no pos/epos file is selected (E=2)\n", - " elif self.R==2:messagebox.showinfo(title='APT_analyzer',message='no file .rrng file selected') # checking if no rrng file is selected (R=2)\n", - " else: # if pos/epos and rrng file is selected\n", - " with open(self.filename, 'rb') as f: # opening pos/epos data from file1\n", - " data = f.read() # reading pos/epos data from file1\n", - " data_rrng=self.filename2 # reading rrng data from file2\n", - " if self.E==0:pos=apt.read_pos(data) # converting pos data if pos file was selected (E==0)\n", - " elif self.E==1:pos=apt.read_epos(data) # converting epos data if epos file was selected (E==1)\n", - " if self.R==0:rrngs=apt.read_rrng(data_rrng) # converting rrng data\n", - " elif self.R==1:rrngs=apt.read_rng(data_rrng)\n", - " self.tip=apt.label_ions(pos, rrngs) # label ions using apt_importers functions\n", - " self.ele=apt.unique(list(self.tip['comp'])) # determining how many unique elements in tip using apt_importers functions\n", - " string=['all'] # setting up strings for atom selection combobox\n", - " for i in range (0,len(self.ele)): # loop over all unique elements\n", - " string.append(self.ele[i]) # creating strings with all unique elements\n", - " self.data_atom=(string) # data for combobox containing all unique elements + 'all' at start\n", - " self.cb_atom = Combobox(tk, values=self.data_atom) # creating combobox with unique elements data \n", - " self.atom=1\n", - " \n", - " self.cb_atom.current(0) # setting initial value of combobox to 'all' \n", - " self.fig.clear() # if plot single was selected clear all previous plots\n", - " self.canvas_all.delete('message') \n", - " self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[2,1],wspace=0.5,hspace=0.5,height_ratios=[2,1]) #adjust the size of the figure compared to (111)\n", - " self.ax=self.fig.add_subplot(self.spec[0],projection='3d')\n", - " N=5000\n", - " u_ele=self.ele\n", - " x=np.array(self.tip['x'])[::N] # select x cooridant (only take every Nth atom to plot later)\n", - " y=np.array(self.tip['y'])[::N] # select y cooridant from tip data\n", - " z=np.array(self.tip['z'])[::N] # select z cooridant from tip data\n", - " c=np.array(self.tip['colour'])[::N] # select the colour column in the tip data\n", - " label=np.array(self.tip['comp'])[::N] # select the composition column in the tip data\n", - " for i in range(0,len(u_ele)): # loop that goes over every different elements\n", - " e=label==u_ele[i] # seperation of the elements\n", - " x_new=x[e] # select the x values of each element indiviually\n", - " y_new=y[e]\n", - " z_new=z[e]\n", - " c_new=c[e]\n", - " self.ax.scatter3D(x_new,y_new,z_new,c=c_new,label=u_ele[i],s=1) # scatter plot each element seperatly and assign label\n", - " x_N=len(x) \n", - " self.ax.set_title('preview (number of atoms={:.0f}, 1/{:.0f} of all atoms)'.format(x_N,N)) # assigne x_N value to show the number of plotted atoms in title\n", - " self.canvas.draw_idle()\n", - " apt.set_axes_equal(self.ax) # function for setting the axes equal for 3d plot\n", - " self.ax.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))#, fontsize=7) # show legends of each element \n", - " self.ax.set_xlabel('X-axis',fontweight='bold') # label x axis\n", - " self.ax.set_ylabel('Y-axis',fontweight='bold') # label y axis\n", - " self.ax.set_zlabel('Z-axis',fontweight='bold') # label z axis\n", - " self.label_succ=Label(text='Sucessfully loaded files!') # create label for rrng\n", - " self.a_succ=self.canvas_all.create_window(200,260,window=self.label_succ) #placing label on canvas\n", - " self.succ=1\n", - " \n", - " def clear(self): # function for clearing canvas\n", - " self.fig.clear() # clearing canvas\n", - " self.canvas.draw_idle() # drawing \n", - " self.canvas_all.delete('message') # deleting message about concentration data\n", - " \n", - " def plot_tip(self): # function about plotting tip\n", - " if self.plot_exist==1: # if plot already exists get the parameters of old plot\n", - " azim=self.ax.azim # get azimutal angle of old plot\n", - " elev=self.ax.elev\n", - " xlim=self.ax.get_xlim() # get x,y and z limit of old plot\n", - " ylim=self.ax.get_ylim()\n", - " zlim=self.ax.get_zlim()\n", - " if self.i_plot.get()==0:self.invert=0 # if inversion checkbox is unmarked set value=0\n", - " else: self.invert=1 # if inversion checkbox is marked set value=1\n", - " \n", - " color_zyl=str(self.cb_color.get()) # get color of cylinder from color entry box\n", - " color_cp=str(self.cb_color_cp.get())\n", - " self.canvas_all.delete('message') # clearing message about concentration data\n", - " Z= self.cb_atom.get() # getting variable from combobox of atom selection\n", - " M = self.slider_res.get() # getting variable from combobox of resolution selection\n", - " SS=self.slider_size.get() # getting variable from combobox of atom size selection\n", - " S=float(SS)/10 # transforming entry into float and deviding by 10 so values 0.1 to 1 are also included\n", - " image_size=self.slider_image_size.get()\n", - " image_size=float(image_size)**2\n", - " u_ele=self.ele\n", - " self.fig.clear() # if plot single was selected clear all previous plots\n", - " self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.1,hspace=0.1,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n", - " self.ax=self.fig.add_subplot(self.spec[0],projection='3d') # make new figure with size depending on the image size slider\n", - " if self.plot_exist==1: # if plot already exist set old parameters of plot as new ones\n", - " self.ax.view_init(elev=elev,azim=azim) # set azimuthal angle and elevation of old plot as new one\n", - " self.ax.set_xlim3d(xlim[0],xlim[1]) # set x,y and z limit of old plot as new one\n", - " self.ax.set_ylim3d(ylim[0],ylim[1])\n", - " if self.i_plot.get()==0 and self.invert==0:self.ax.set_zlim3d(zlim[0],zlim[1]) # depending on if the plot should be inverted or not\n", - " if self.i_plot.get()==1 and self.invert==1:self.ax.set_zlim3d(zlim[0],zlim[1]) # reset the z limit of new plot to center it again\n", - " self.plot_exist=1 # set plot exist as one in order to mark that plot exists\n", - " n=len(np.array(self.tip['x'])) # get the number of atoms\n", - " N=int(50000/(10**M)) # calc N (the number how many atoms should be plotted)\n", - " if N==0:N=1\n", - " \n", - " x=np.array(self.tip['x'])[::N] # select x cooridant (only take every Nth atom to plot later)\n", - " y=np.array(self.tip['y'])[::N] # select y cooridant from tip data\n", - " z=np.array(self.tip['z'])[::N] # select z cooridant from tip data\n", - " c=np.array(self.tip['colour'])[::N] # select the colour column in the tip data\n", - " label=np.array(self.tip['comp'])[::N] # select the composition column in the tip data\n", - "\n", - " max_x=max(x)\n", - " min_x=min(x)\n", - " max_z=max(z)\n", - " min_z=min(z)\n", - " max_y=max(y)\n", - " min_y=min(y)\n", - " for i in range(0,len(u_ele)): # loop that goes over every different elements\n", - " e=label==u_ele[i] # seperation of the elements\n", - " x_new=x[e] # select the x values of each element indiviually\n", - " y_new=y[e]\n", - " z_new=z[e]\n", - " c_new=c[e] \n", - " if self.i_plot.get()==1: z_new=-z_new # if inverse tip is selected change the sign of the z coordinates\n", - " if Z=='all': # if all was selected plot all of them together\n", - " X=np.array([x,y,z]).T \n", - " c_new[c_new=='#FFFFFF']='#000000'\n", - " self.ax.scatter(x_new,y_new,z_new,c=c_new,label=u_ele[i],s=S,zorder = 1,depthshade = False,picker=True) # scatter plot each element seperatly and assign label\n", - " x_N=len(x) \n", - " self.ax.set_title('number of atoms={:.0f}, 1/{:.0f} of all atoms'.format(x_N,N)) # assigne x_N value to show the number of plotted atoms in title\n", - " elif u_ele[i]==Z: # if a certain element was selected in combobox for element selection\n", - " X=np.array([x_new,y_new,z_new]).T # putting all \n", - " c_new[c_new=='#FFFFFF']='#000000'\n", - " self.ax.scatter(X[:,0],X[:,1],X[:,2],c=c_new,label=u_ele[i],s=S,zorder = 1, depthshade = False,picker=True) #scatter plot each element seperatly and assign label \n", - " x_N=len(x_new) # assigne x_N only to show the number of plotted atoms of selected element \n", - " self.ax.set_title('number of atoms={:.0f}, 1/{:.0f} of all atoms of this type'.format(x_N,N)) \n", - " apt.set_axes_equal(self.ax) # function for setting the axes equal for 3d plot\n", - " self.ax.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))#, fontsize=7) # show legends of each element\n", - " if self.var_axis.get()==0: # if show axis was selected\n", - " self.ax.set_xlabel('X-axis',fontweight='bold') # label x axis\n", - " self.ax.set_ylabel('Y-axis',fontweight='bold') # label y axis\n", - " self.ax.set_zlabel('Z-axis',fontweight='bold') # label z axis\n", - " elif self.var_axis.get()==1: # if show axis was not selected\n", - " self.ax.set_axis_off() # dont show axis\n", - " \n", - " if self.var_cyl.get()==1: # if show clyinder was selected\n", - " x_pos=self.cly_x.get() # get x value from x entry box\n", - " if x_pos=='': x_pos=0\n", - " else:x_pos = float(x_pos)\n", - " y_pos =self.cly_y.get() # get y value from y entry box\n", - " if y_pos=='': y_pos=0\n", - " else:y_pos = float(y_pos)\n", - " z_pos = self.cly_z.get() # get z value from z entry box\n", - " if z_pos=='': z_pos=0\n", - " else:z_pos = float(z_pos) \n", - " if self.i_plot.get()==1: z_pos = -z_pos # if inverse tip is selected inverse the z coordinates of the cylinder \n", - " height = float(self.height.get()) # get height value from height entry box\n", - " alpha = float(self.alpha.get()) # get tilt along y value from alpha entry box\n", - " beta = float(self.beta.get()) # get tilt along x value from beta entry box\n", - " r = float(self.radius.get()) # get radius value from radius entry box \n", - " theta=np.linspace(0,2*np.pi,201) # create linspace variable for plotting the circle\n", - " alpha=math.radians(alpha) # transform alpha from deg in rad\n", - " beta=math.radians(beta) # transfrom beta from deg in rad\n", - " Xc,Yc,Zc=data_for_cylinder_along_z(0,0,0,r,height) # calculating cylinder\n", - " Z=np.array([Xc,Yc,Zc]).T\n", - " matrix_l=np.array([(np.cos(beta), np.sin(alpha)*np.sin(beta), np.cos(alpha)*np.sin(beta)),\n", - " (0, np.cos(alpha), -np.sin(alpha)),\n", - " (-np.sin(beta), np.sin(alpha)*np.cos(beta), np.cos(alpha)*np.cos(beta))])\n", - " pro=[]\n", - " for j in range(0,len(Z)):\n", - " for i in range (0,len(Z[j])):\n", - " pro.append(matrix_l.dot(Z[i][j])) \n", - " pro=np.array(pro) \n", - " Z_new=pro.reshape(50,50,3).T\n", - " self.ax.plot_surface(Z_new[0]+x_pos,Z_new[1]+y_pos,Z_new[2]+z_pos,alpha=0.4,color=color_zyl) # plotting cylinder\n", - " apt.set_axes_equal(self.ax)\n", - " \n", - " if self.var_points.get()==1:\n", - " XX=[]\n", - " YY=[]\n", - " ZZ=[]\n", - " points=[]\n", - " points=self.text_box.get(1.0,END)\n", - " points=points.split('\\n')\n", - " points=[x for x in points if x!='']\n", - " for i in range(0,len(points)):\n", - " points_inner=points[i].split(',')\n", - " xyz2=[]\n", - " for j in points_inner:\n", - " m=j.split('=')\n", - " xyz2.append(m[1])\n", - " x2=float(xyz2[0])\n", - " y2=float(xyz2[1])\n", - " z2=float(xyz2[2])\n", - " XX.append(x2)\n", - " YY.append(y2)\n", - " ZZ.append(z2)\n", - " if self.i_plot.get()==1:z2=-z2 # if inverse tip is selected\n", - " self.ax.scatter3D(x2,y2,z2,marker='+',color=color_cp,s=S*100)\n", - " if len(XX)>=3 and self.var_plane.get()==1:\n", - " center_x=sum(XX)/len(XX)\n", - " center_y=sum(YY)/len(YY)\n", - " center_z=sum(ZZ)/len(ZZ)\n", - " self.cly_x=StringVar(value=center_x)\n", - " self.cly_y=StringVar(value=center_y)\n", - " self.cly_z=StringVar(value=center_z)\n", - " tmp_C=[]\n", - " for i in range(len(XX)):\n", - " tmp_C.append([XX[i],YY[i],ZZ[i]])\n", - " C=np.array(tmp_C).T\n", - " svd=np.linalg.svd(C - np.mean(C, axis=1, keepdims=True))\n", - " left=svd[0]\n", - " fit=left[:,-1]\n", - " #print('solution: %f x +%f y +%f z = 0' %(fit[0],fit[1],fit[2]))\n", - " normal=np.array([fit[0],fit[1],fit[2]]) \n", - " r=5\n", - " self.ax.plot([center_x,center_x+r*normal[0]],[center_y,center_y+r*normal[1]],[center_z,center_z+r*normal[2]],color='r',linewidth=5)\n", - " xlim=self.ax.get_xlim()\n", - " ylim=self.ax.get_ylim()\n", - " X,Y=np.meshgrid(np.arange(xlim[0],xlim[1]),np.arange(ylim[0],ylim[1]))\n", - " Z=np.zeros(X.shape)\n", - " for r in range(X.shape[0]):\n", - " for c in range(X.shape[1]):\n", - " #Z[r,c]=fit[0]*X[r,c]+fit[1]*Y[r,c]+fit[2]\n", - " Z[r,c]=-(fit[0]*X[r,c]+fit[1]*Y[r,c])/fit[2]\n", - " #self.ax.plot([cpx,fit[0]],[cpy,fit[1]],[cpz,-1])\n", - " self.ax.plot_wireframe(X+center_x,Y+center_y,Z+center_z,color='k')\n", - " self.canvas.draw_idle() \n", - " \n", - " def distance(point, event):\n", - "# Return distance between mouse position and given data point\n", - "# Args:point (np.array): np.array of shape (3,), with x,y,z in data coords event (MouseEvent): mouse event (which contains mouse position in .x and .xdata)\n", - "# Returns:distance (np.float64): distance (in screen coords) between mouse pos and data point \n", - " assert point.shape == (3,), \"distance: point.shape is wrong: %s, must be (3,)\" % point.shape \n", - " x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], self.ax.get_proj()) # Project 3d data space to 2d data space\n", - " x3, y3 = self.ax.transData.transform((x2, y2)) # Convert 2d data space to 2d screen space\n", - " return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2) # calculate distance\n", - " \n", - " def onclick(event):\n", - " distances = [distance (X[i,0:3], event) for i in range(X.shape[0])] # use function distance to evaluate the closests index to mouse click\n", - " index=np.argmin(distances) # select the closest index\n", - " self.ax.scatter(X[index, 0], X[index, 1], X[index, 2],marker='+',color=color_cp,s=S*100) # plot controlpoint at closest index point\n", - " text='x='+str(np.round(X[index, 0],4))+', y='+str(np.round(X[index, 1],4))+', z='+str(np.round(X[index, 2],4)) # write x,y,z coordinates into text file\n", - " if self.i_plot.get()==1:text='x='+str(np.round(X[index, 0],4))+', y='+str(np.round(X[index, 1],4))+', z='+str(-np.round(X[index, 2],4))\n", - " self.text_box.insert(END,text) # insert text file in textbox\n", - " self.text_box.insert(END,'\\n') # make sure next control point is next row\n", - " self.canvas.draw_idle()\n", - " \n", - " if self.control.get()==1: \n", - " if self.diss==1:self.fig.canvas.mpl_disconnect(self.cid)\n", - " self.cid=self.fig.canvas.mpl_connect('button_press_event',onclick)\n", - " self.diss=1\n", - " elif self.control.get()==0 and self.diss==1: \n", - " self.fig.canvas.mpl_disconnect(self.cid)\n", - " self.diss=0\n", - " \n", - " def calc_con(self): # function for calculating the concentration\n", - " if self.diss2==1:self.fig.canvas.mpl_disconnect(self.cid) \n", - " self.plot_exist=0\n", - " self.print_con=[]\n", - " self.print_con2=[]\n", - " self.canvas_all.delete('message') \n", - " start_end=self.cb_bulk.get()\n", - " atom= self.cb_atom.get()\n", - " u_ele_real=self.ele\n", - " image_size=self.slider_image_size.get()\n", - " image_size=float(image_size)/2\n", - " self.fig.clear()\n", - " self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n", - " self.ax1=self.fig.add_subplot(self.spec[0])\n", - " self.ax1.set_xlabel('z position of cylinder')\n", - " self.ax1.set_ylabel('concentration [%]')\n", - " x_real=np.array(self.tip['x'])\n", - " y_real=np.array(self.tip['y'])\n", - " z_real=np.array(self.tip['z'])\n", - " if self.i_plot.get()==1: # atoms z coordinatines inversion\n", - " z_real = -z_real\n", - " c_real=np.array(self.tip['colour'])\n", - " label_real=np.array(self.tip['comp'])\n", - " inter=float(self.slider_inter.get()/20)\n", - " height = float(self.height.get())\n", - " alpha = float(self.alpha.get())\n", - " beta = float(self.beta.get())\n", - " r = float(self.radius.get())\n", - " x_pos = float(self.cly_x.get())\n", - " y_pos = float(self.cly_y.get())\n", - " z_pos = float(self.cly_z.get())\n", - " if self.i_plot.get()==1: # cylinder z coordinatines inversion\n", - " z_pos = -z_pos\n", - " z_start=-height/2\n", - " z_end=height/2\n", - " alpha=math.radians(-alpha)\n", - " beta=math.radians(-beta)\n", - " ################### tilt and move zylinder ######################################\n", - " pro=[]\n", - " Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n", - " M_ROT1=[(1, 0, 0 ), # rotational matrix along the x-direction\n", - " (0, np.cos(alpha), -np.sin(alpha)),\n", - " (0, np.sin(alpha), np.cos(alpha))]\n", - "\n", - " M_ROT2=[(np.cos(beta), 0, np.sin(beta)), # rotational matrix along the y-direction\n", - " (0, 1, 0 ),\n", - " (-np.sin(beta), 0, np.cos(beta))]\n", - " matrix_l=np.array(M_ROT1).dot(M_ROT2)\n", - " for j in range(0,len(Z)):\n", - " pro.append(matrix_l.dot(Z[j])) \n", - " Z_new=np.array(pro)\n", - " x_real=Z_new[:,0]\n", - " y_real=Z_new[:,1]\n", - " z_real=Z_new[:,2]\n", - " ######################################################################### \n", - " xy=((x_real)**2+(y_real)**2)**(1/2) # cirlce constraint for atoms \n", - " circle=xy<=r # only select atoms inside of circle\n", - " message='concentration: \\n' # initialize the message displayed on the right side of the plot\n", - " for m in range(0,len(u_ele_real)): # loop over each individual elements\n", - " plot_z=[] # x component of concentration plots \n", - " Num=[] # Number of atoms inside the circle and intervals (for concentration calculation)\n", - " Num_all=[] # total number of atoms (of each element) to calculate the % contribution of each\n", - " e=label_real[circle]==u_ele_real[m] # seperation of the elements\n", - " z_circle=z_real[circle] # only selec the atoms with circle constraint\n", - " z_p=z_circle[e] # only select the atoms wth circle constraint of specific element\n", - " c_circle=c_real[circle]\n", - " c_p=c_circle[e]\n", - " for j in range (0,int((z_end-z_start)/inter)+1): # loop of intervals\n", - " init=z_p>=z_start+j*inter # starting condition of interval for each element\n", - " init_all=z_circle>=z_start+j*inter # starting condition of interval for all elements together\n", - " z_all2=z_circle[init_all] # selecting atoms which fulfill starting constraint for all elements\n", - " z_p2=z_p[init] # selecting atoms which fulfill the starting constraint for each individual element\n", - " init2=z_p2<=z_start+(j*inter+inter) # ending constraint of interval\n", - " init2_all=z_all2<=z_start+(j*inter+inter) # ending constraint of interval for all elements\n", - " z_all3=z_all2[init2_all] # selecting atoms which also fulfill ending constraint for all elements\n", - " z_p3=z_p2[init2] # selecting atom which also fulfill ending constraint for each individual elements\n", - " Num_all.append(len(z_all3)) # append the number of atoms which fulfill both contraints\n", - " Num.append(len(z_p3)) # append the number of atoms which fulfill both constraints for each individual element\n", - " plot_z.append(z_start+j*inter)#+inter/2) # append the x-coordinate for the concentration plot\n", - " a=np.array(Num,dtype=float) # transform total number of atoms for each individual element into array of floats\n", - " b=np.array(Num_all,dtype=float) # transform total number of atoms into array of floats\n", - " if self.var_switch.get()==1: \n", - " if start_end=='start':b=np.array(Num_all[0])\n", - " last=len(np.array(Num_all))-1 \n", - " if start_end=='end':b=np.array(Num_all[last])\n", - " if b==0:messagebox.showinfo(title='APT_analyzer',message='Reference bulk concentration is 0')\n", - " self.conc=100*np.divide(a,b, out=np.zeros_like(a), where=b!=0) # calculate concentration, if total amount of atoms == 0, result is 0\n", - " message=message+u_ele_real[m] # append element type into message\n", - " message=message+': maximal value: ' # add text to message\n", - " message=message+str(round(max(self.conc),2)) # add maximum of concentration to message\n", - " message=message+' minimal value: ' # add text to message\n", - " message=message+str(round(min(self.conc),2)) # add minimum of concentration to message\n", - " message=message+'\\n' # add line split to message \n", - " if atom=='all': # seperate if atom select checkbox 'all' is selected\n", - " if c_p[0]=='#FFFFFF':c_p[0]='#000000' # if color of particles is white change it to black so it can be seen with white background\n", - " self.ax1.plot(plot_z,self.conc,c_p[0],label=u_ele_real[m]) # plot the concentration of each element individually\n", - " self.print_con2.append(u_ele_real[m])\n", - " self.print_con.append(self.conc)\n", - " elif u_ele_real[m]==atom: # if certain element is selected in checkbox\n", - " if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n", - " self.ax1.plot(plot_z,self.conc,c_p[0],label=u_ele_real[m]) # only plot selected element from the select atom checkbox\n", - " self.print_con2.append(u_ele_real[m])\n", - " self.print_con.append(self.conc)\n", - " self.print_con2.append('z_cyl')\n", - " plot_z2=plot_z.copy()\n", - " plot_z2=np.array(plot_z2).reshape(np.shape(np.array(self.conc)))\n", - " self.print_con.append(plot_z2)\n", - " self.df_con=pd.DataFrame(np.array(self.print_con).T,columns=self.print_con2)\n", - " self.ax1.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))\n", - " self.ax1.set_title('concentration of elements along cylinder / intervalsize=%1.2f' %inter)\n", - " self.canvas.draw_idle()\n", - " self.message=Text(height = 20,width = 50,relief=FLAT)\n", - " self.message.insert(END, message)\n", - " self.message.configure(state='disabled')\n", - " image_ratio=image_size/2.5\n", - " place_factor=0.2\n", - " place_value=1450-place_factor*(1450-image_ratio*1450)\n", - " self.canvas_all.create_window(place_value,300,window=self.message,tags='message')\n", - " self.conc_check=1\n", - " \n", - " \n", - " \n", - " def calc_excess(self):\n", - " self.plot_exist=0\n", - " self.print_ex=[]\n", - " self.print_ex2=[]\n", - " self.canvas_all.delete('message') \n", - " atom= self.cb_atom.get() \n", - " color_zyl=str(self.cb_color.get())\n", - " u_ele_real=self.ele \n", - " image_size=self.slider_image_size.get()\n", - " image_size=float(image_size)/2\n", - " self.fig.clear()\n", - " self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n", - " self.ax1=self.fig.add_subplot(self.spec[0])\n", - " self.ax1.set_xlabel('z position of cylinder')\n", - " self.ax1.set_ylabel('Total amount of atoms')\n", - " x_real=np.array(self.tip['x'])\n", - " y_real=np.array(self.tip['y'])\n", - " z_real=np.array(self.tip['z']) # atoms z coordinatines inversion\n", - " if self.i_plot.get()==1:\n", - " z_real=-z_real\n", - " c_real=np.array(self.tip['colour'])\n", - " label_real=np.array(self.tip['comp'])\n", - " inter=float(self.slider_inter.get()/20)\n", - " height = float(self.height.get())\n", - " alpha = float(self.alpha.get())\n", - " beta = float(self.beta.get())\n", - " r = float(self.radius.get())\n", - " x_pos = float(self.cly_x.get())\n", - " y_pos = float(self.cly_y.get())\n", - " z_pos = float(self.cly_z.get())\n", - " if self.i_plot.get()==1: # cylinder z coordinatines inversion\n", - " z_pos=-z_pos\n", - " z_start=-height/2\n", - " z_end=height/2\n", - " alpha=math.radians(-alpha) # transfroms radius into radians\n", - " beta=math.radians(-beta) # - because otherwise it tilts the cylinder in the wrong direction (dont know why)\n", - " ################### tilt and move zylinder ######################################\n", - " pro=[]\n", - " Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n", - " M_ROT1=[(1, 0, 0 ), # rotational matrix along the x-direction\n", - " (0, np.cos(alpha), -np.sin(alpha)),\n", - " (0, np.sin(alpha), np.cos(alpha))]\n", - "\n", - " M_ROT2=[(np.cos(beta), 0, np.sin(beta)), # rotational matrix along the y-direction\n", - " (0, 1, 0 ),\n", - " (-np.sin(beta), 0, np.cos(beta))]\n", - " matrix_l=np.array(M_ROT1).dot(M_ROT2)\n", - " for j in range(0,len(Z)):\n", - " pro.append(matrix_l.dot(Z[j])) \n", - " Z_new=np.array(pro)\n", - " x_real=Z_new[:,0]\n", - " y_real=Z_new[:,1]\n", - " z_real=Z_new[:,2]\n", - " ######################################################################### \n", - " xy=((x_real)**2+(y_real)**2)**(1/2)\n", - " circle=xy<=r\n", - " for m in range(0,len(u_ele_real)):\n", - " plot_z=[]\n", - " excess=[]\n", - " ex=0\n", - " e=label_real[circle]==u_ele_real[m] #seperation of the atoms \n", - " z_circle=z_real[circle]\n", - " z_p=z_circle[e]\n", - " c_circle=c_real[circle]\n", - " c_p=c_circle[e]\n", - " for j in range (0,int((z_end-z_start)/inter)+1):\n", - " init=z_p>=z_start+j*inter \n", - " z_p2=z_p[init]\n", - " init2=z_p2<=z_start+(j*inter+inter)\n", - " z_p3=z_p2[init2]\n", - " ex+=len(z_p3)\n", - " excess.append(ex)\n", - " plot_z.append(z_start+j*inter)#+inter/2) \n", - " if self.var_norm.get()==1:excess=np.array(excess)/(max(excess))\n", - " if atom=='all':\n", - " if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n", - " self.ax1.plot(plot_z,excess,c_p[0],label=u_ele_real[m])\n", - " excess_save=excess.copy()\n", - " self.print_ex2.append(u_ele_real[m])\n", - " self.print_ex.append(np.array(excess))\n", - " elif u_ele_real[m]==atom:\n", - " if c_p[0]=='#FFFFFF':c_p[0]='#000000'\n", - " self.ax1.plot(plot_z,excess,c_p[0],label=u_ele_real[m]) \n", - " excess_save=excess.copy()\n", - " self.print_ex2.append(u_ele_real[m])\n", - " self.print_ex.append(np.array(excess)) \n", - " self.print_ex2.append('z_cyl')\n", - " plot_z2=plot_z.copy()\n", - " plot_z2=np.array(plot_z2).reshape(np.shape(np.array(excess)))\n", - " self.print_ex.append(plot_z2)\n", - " self.df_ex=pd.DataFrame(np.array(self.print_ex).T,columns=self.print_ex2)\n", - " self.ax1.set_title('Excess (total atom number of elements along cylinder) / intervalsize=%1.2f ' %inter)\n", - " self.ax1.legend(loc='center left', bbox_to_anchor=(1.07, 0.5))\n", - " \n", - " points_ex=self.text_box_ex.get(1.0,END) # get text from text box\n", - " if points_ex!='\\n':\n", - " points_ex=points_ex.split('\\n') # split the text into each row\n", - " points_ex=[x for x in points_ex if x!=''] # remove any rows that dont contain information\n", - " XX=[]\n", - " YY=[]\n", - " for i in range(0,len(points_ex)): # loop over all rows\n", - " points_inner=points_ex[i].split(',') # split each row into parts of each coordinates\n", - " xy2=[]\n", - " for j in points_inner: # loop over all values inside row\n", - " m=j.split('=') # isolate actual number\n", - " xy2.append(m[1]) # save number\n", - " XX.append(float(xy2[0])) # save x,y and z coordinate\n", - " YY.append(float(xy2[1]))\n", - " if len(XX)==4:\n", - " k1=(YY[0]-YY[1])/(XX[0]-XX[1])\n", - " k3=(YY[2]-YY[3])/(XX[2]-XX[3])\n", - " d1=YY[1]-k1*XX[1]\n", - " d3=YY[3]-k3*XX[3]\n", - " x=np.array([-height/2,height/2])\n", - " y1=gerade(np.array(k1),x,np.array(d1))\n", - " y3=gerade(np.array(k3),x,np.array(d3))\n", - " diff=[]\n", - " for i in range(0,len(excess_save)):\n", - " upper_line=gerade(np.array(k3),plot_z[i],np.array(d3))\n", - " lower_line=gerade(np.array(k1),plot_z[i],np.array(d1)) \n", - " diff.append(np.abs((upper_line-excess_save[i])-(excess_save[i]-lower_line)))\n", - " plot_z=np.array(plot_z)\n", - " x_found=plot_z[diff==min(diff)]\n", - " y_excess_u=gerade(np.array(k3),x_found,np.array(d3))\n", - " y_excess_l=gerade(np.array(k1),x_found,np.array(d1))\n", - " excess_atom_value=y_excess_u[0]-y_excess_l[0]\n", - " excess_value=excess_atom_value/(np.pi*r**2)\n", - " self.ax1.plot([x_found,x_found],[y_excess_l,y_excess_u])\n", - " self.ax1.plot(x,y1,color=color_zyl)\n", - " self.ax1.plot(x,y3,color=color_zyl)\n", - " self.ax1.scatter(XX,YY,color='black',marker='x')\n", - " self.ax1.annotate(\" 1\", (XX[0], YY[0]))\n", - " self.ax1.annotate(\" 2\", (XX[1], YY[1]))\n", - " self.ax1.annotate(\" 3\", (XX[2], YY[2]))\n", - " self.ax1.annotate(\" 4\", (XX[3], YY[3]))\n", - " self.output = Text(height = 10,width = 50,relief=FLAT)\n", - " image_ratio=image_size/2.5\n", - " place_factor=0.25\n", - " place_value=650-place_factor*(650-image_ratio*650)\n", - " self.canvas_all.create_window(650,place_value,window=self.output,tags='message')\n", - " message2='Calculated with the following 4 points: \\n'\n", - " message2=message2+'point 1: x = '+str(XX[0])+' y = '+str(YY[0])+'\\n'\n", - " message2=message2+'point 2: x = '+str(XX[1])+' y = '+str(YY[1])+'\\n'\n", - " message2=message2+'point 3: x = '+str(XX[2])+' y = '+str(YY[2])+'\\n'\n", - " message2=message2+'point 4: x = '+str(XX[3])+' y = '+str(YY[3])+'\\n'+'\\n'\n", - " message2=message2+'the interfacial excess atoms = '+str(np.round(excess_atom_value,3))+' atoms'+'\\n'\n", - " message2=message2+'the interfacial excess = '+str(np.round(excess_value,3))+' atoms/nm²'\n", - " self.output.insert(END, message2)\n", - " self.output.configure(state='disabled')\n", - " self.canvas.draw_idle() \n", - " elif len(XX)>=4:messagebox.showinfo(title='APT_analyzer',message='Too many fit points selected. Reduce to 4 points to fit excess.')\n", - " def onclick(event):\n", - " x=np.round(event.xdata,2)\n", - " y=np.round(event.ydata,2)\n", - " self.ax1.scatter(x,y,color='black',marker='x')\n", - " text='x='+str(x)+', y='+str(y)\n", - " self.text_box_ex.insert(END,text)\n", - " self.text_box_ex.insert(END,'\\n')\n", - " self.canvas.draw_idle() \n", - " if self.diss2==1:self.fig.canvas.mpl_disconnect(self.cid) \n", - " self.cid=self.fig.canvas.mpl_connect('button_press_event',onclick)\n", - " self.diss2=1\n", - " self.canvas.draw_idle() \n", - " self.excess_check=1\n", - " \n", - " def calc_zoom(self): \n", - " self.plot_exist=0\n", - " self.canvas_all.delete('message') \n", - " image_size=self.slider_image_size.get()\n", - " image_size=float(image_size)**2\n", - " self.fig.clear()\n", - " self.spec=gridspec.GridSpec(ncols=2,nrows=2,width_ratios=[image_size,1],wspace=0.5,hspace=0.5,height_ratios=[image_size,1]) #adjust the size of the figure compared to (111)\n", - " self.ax2=self.fig.add_subplot(self.spec[0],projection='3d')\n", - " atom= self.cb_atom.get()\n", - " M = self.slider_res.get()\n", - " SS=self.slider_size.get()\n", - " S=float(SS)/10\n", - " u_ele_real=self.ele\n", - " n=len(np.array(self.tip['x']))\n", - " N_plot=int(50000/(10**M))\n", - " if N_plot==0:N_plot=1\n", - " x_real=np.array(self.tip['x'])\n", - " y_real=np.array(self.tip['y']) \n", - " z_real=np.array(self.tip['z'])\n", - " if self.i_plot.get()==1: # atoms z coordinatines inversion\n", - " z_real = -z_real\n", - " c_real=np.array(self.tip['colour'])\n", - " label_real=np.array(self.tip['comp'])\n", - " height = float(self.height.get())\n", - " alpha = -float(self.alpha.get())\n", - " beta = -float(self.beta.get())\n", - " r = float(self.radius.get())\n", - " x_pos = float(self.cly_x.get())\n", - " y_pos = float(self.cly_y.get())\n", - " z_pos = float(self.cly_z.get())\n", - " if self.i_plot.get()==1: # cylinder z coordinatines inversion\n", - " z_pos = -z_pos\n", - " color_zyl=str(self.cb_color.get())\n", - " z_start=-height/2\n", - " z_end=height/2\n", - " alpha=math.radians(alpha)\n", - " beta=math.radians(beta)\n", - " ################### tilt and move zylinder ######################################\n", - " pro=[]\n", - " Z=np.array([x_real-x_pos,y_real-y_pos,z_real-z_pos]).T\n", - " M_ROT1=[(1, 0, 0 ), # rotational matrix along the x-direction\n", - " (0, np.cos(alpha), -np.sin(alpha)),\n", - " (0, np.sin(alpha), np.cos(alpha))]\n", - "\n", - " M_ROT2=[(np.cos(beta), 0, np.sin(beta)), # rotational matrix along the y-direction\n", - " (0, 1, 0 ),\n", - " (-np.sin(beta), 0, np.cos(beta))]\n", - " matrix_l=np.array(M_ROT1).dot(M_ROT2)\n", - " for j in range(0,len(Z)):\n", - " pro.append(matrix_l.dot(Z[j])) \n", - " Z_new=np.array(pro)\n", - " x_real=Z_new[:,0]\n", - " y_real=Z_new[:,1]\n", - " z_real=Z_new[:,2]\n", - " ######################################################################### \n", - " xy=((x_real)**2+(y_real)**2)**(1/2)\n", - " circle=xy<=r\n", - " for m in range(0,len(u_ele_real)):\n", - " e=label_real[circle]==u_ele_real[m] #seperation of the atoms \n", - " z_circle=z_real[circle]\n", - " x_circle=x_real[circle]\n", - " y_circle=y_real[circle]\n", - " c_circle=c_real[circle]\n", - " z_p=z_circle[e] \n", - " x_p=x_circle[e] \n", - " y_p=y_circle[e]\n", - " c_p=c_circle[e]\n", - " init_plot=z_p>=z_start\n", - " x_pl2=x_p[init_plot]\n", - " y_pl2=y_p[init_plot]\n", - " z_pl2=z_p[init_plot]\n", - " c_pl2=c_p[init_plot]\n", - " init_plot2=z_pl2<=z_end \n", - " x_pl3=x_pl2[init_plot2]\n", - " y_pl3=y_pl2[init_plot2]\n", - " z_pl3=z_pl2[init_plot2]\n", - " c_pl3=c_pl2[init_plot2]\n", - " if atom=='all':\n", - " c_pl3[c_pl3=='#FFFFFF']='#000000'\n", - " x_N=len(x_real[::N_plot])\n", - " self.ax2.scatter3D(x_pl3[::N_plot],y_pl3[::N_plot],z_pl3[::N_plot],c=c_pl3[::N_plot],label=u_ele_real[m],s=S)\n", - " self.ax2.set_title('number of atoms={:.0f}, 1/{:.0f} of all atoms'.format(x_N,N_plot)) \n", - " elif u_ele_real[m]==atom:\n", - " c_pl3[c_pl3=='#FFFFFF']='#000000'\n", - " x_N=len(x_pl3[::N_plot])\n", - " self.ax2.scatter3D(x_pl3[::N_plot],y_pl3[::N_plot],z_pl3[::N_plot],c=c_pl3[::N_plot],label=u_ele_real[m],s=S)\n", - " self.ax2.set_title('number of atoms={:.0f}, 1/{:.0f} of all atoms of this type'.format(x_N,N_plot)) \n", - " if self.var_axis.get()==0: \n", - " #self.ax2.set_title('number of atoms=%i' %x_N)\n", - " self.ax2.set_xlabel('X-axis',fontweight='bold')\n", - " self.ax2.set_ylabel('Y-axis',fontweight='bold')\n", - " self.ax2.set_zlabel('Z-axis',fontweight='bold')\n", - " elif self.var_axis.get()==1:\n", - " self.ax2.set_axis_off() \n", - " apt.set_axes_equal(self.ax2) \n", - " self.ax2.legend() \n", - " if self.var_cyl.get()==1:\n", - " x_pos = float(self.cly_x.get())\n", - " y_pos = float(self.cly_y.get())\n", - " z_pos = float(self.cly_z.get())\n", - " height = float(self.height.get())\n", - " alpha = float(self.alpha.get())\n", - " beta = float(self.beta.get())\n", - " r = float(self.radius.get())\n", - " color_zyl=str(self.cb_color.get())\n", - " theta=np.linspace(0,2*np.pi,201)\n", - " z_start=-height/2\n", - " z_end=height/2\n", - " alpha=math.radians(alpha)\n", - " beta=math.radians(beta)\n", - " \n", - " y_circle=r*np.cos(theta)\n", - " x_circle=r*np.sin(theta)\n", - " z_circle_s=np.ones(201)*z_start\n", - " z_circle_e=np.ones(201)*z_end\n", - "\n", - " x_line1=np.ones(201)*r\n", - " x_line2=np.ones(201)*-r\n", - " y_line=np.ones(201)*0\n", - " z_line=np.linspace(z_start,z_end,201)\n", - " lw=5\n", - " self.ax2.plot(x_line1,y_line,z_line,color_zyl,linewidth=lw)\n", - " self.ax2.plot(x_line2,y_line,z_line,color_zyl,linewidth=lw)\n", - " self.ax2.plot(x_circle,y_circle,z_circle_s,color_zyl,linewidth=lw) \n", - " self.ax2.plot(x_circle,y_circle,z_circle_e,color_zyl,linewidth=lw) \n", - " self.canvas.draw_idle() \n", - "\n", - "tk = Tk() # tkinter\n", - "tk.title(\"APT analyzer\") # select title of tool\n", - "tk.geometry('1100x700') # select size of tool\n", - "tt=APT_analyzer(tk) # select tool \n", - "tk.mainloop() # start tool" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2b4bf9ed-bc19-456f-99b6-c0cfe5691b57", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docker/apmtools/Cheatsheet.ipynb b/docker/apmtools/Cheatsheet.ipynb index cd86404bf13e1f8777ec0a6c80e5dc448a89b328..07614ea6e7ffbfb0958695e2b45f35a87134fb4a 100644 --- a/docker/apmtools/Cheatsheet.ipynb +++ b/docker/apmtools/Cheatsheet.ipynb @@ -5,7 +5,7 @@ "id": "88054eb2", "metadata": {}, "source": [ - "" + "<img src=\"NOMADOasisLogo.png\" alt=\"Drawing\" style=\"height: 149px;\"/>  <img src=\"FAIRmatNewLogo.png\" alt=\"Drawing\" style=\"height: 149px;\"/>" ] }, { @@ -21,17 +21,44 @@ "id": "4091c1e2", "metadata": {}, "source": [ - "The apmtools container offers functionalities to work, i.e. perform data analyses<br>\n", + "The apmtools container offers functionalities to work and perform data analyses<br>\n", "with reconstructed and ranged datasets from atom probe microscopy experiments.<br>\n", "\n", - "This container includes two tools for processing of atom probe data:\n", - "* The **Leoben APT_analyzer** by Alexander Reichmann et al.\n", - "* The **paraprobe-toolbox** by Markus Kühbach et al.\n", + "This container includes three tools:\n", + "* **APTyzer** by Alexander Reichmann et al. https://github.com/areichm/APTyzer\n", + "* **paraprobe-toolbox** by Markus Kühbach et al. https://gitlab.com/paraprobe/paraprobe-toolbox\n", + "* **APAV** by Jesse Smith et al. https://gitlab.com/jesseds/apav\n", "\n", - "Each tool comes with a tutorial-style example.\n", + "Each tool comes shipped with tutorial-style examples.\n", "***" ] }, + { + "cell_type": "markdown", + "id": "e7afeb96-16a6-4d5a-9986-7aacfc9980f4", + "metadata": { + "tags": [] + }, + "source": [ + "<div class=\"alert alert-block alert-info\">\n", + "Having APTyzer, APAV, and paraprobe-toolbox configured in one container comes with the benefit<br>\n", + "that one can switch between using these tools or couple them together via an e.g. jupyter notebook.\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "id": "fd044275-1ce9-4fea-bbe8-9903c3620a18", + "metadata": { + "tags": [] + }, + "source": [ + "<div class=\"alert alert-block alert-info\">\n", + "Containers of the Nomad Remote Tools Hub (NORTH) are configured such that they have access to the data in the uploads section of the Oasis instance.<br>\n", + "Individual examples which exemplify how to use the tools in the apmtools container may have to be unpacked/decompressed before their first use.\n", + "</div>" + ] + }, { "cell_type": "markdown", "id": "69238a64", @@ -39,29 +66,31 @@ "tags": [] }, "source": [ - "# Getting started with the Leoben APT_analyzer" + "# Getting started with APTyzer" ] }, { "cell_type": "markdown", - "id": "6e324fa1", + "id": "4aa12615-4734-4802-b6b9-407d6f1797bd", "metadata": {}, "source": [ - "The Leoben APT_analyzer is a Python-based tool with a GUI which can be used to display tomographic<br>\n", - "reconstructions for performing composition and interfacial excesses analyses. The tool is maintained<br>\n", - "by Alexander Reichmann at the Montanuniversität Leoben.<br>\n", - "\n", - "First you should navigate into the respective directory of the tool.<br>" + "<div class=\"alert alert-block alert-info\">\n", + "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core and say at least 4GB main memory.\n", + "</div>" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "5fd98af7", + "cell_type": "markdown", + "id": "6e324fa1", "metadata": {}, - "outputs": [], "source": [ - "! cd /home/atom_probe_tools/leoben_apt_analyzer" + "APTyzer is a Python-based tool with a graphical user interface (GUI) which can be used for displaying of a tomographically<br>\n", + "reconstructed atom probe dataset thus enabling composition and interfacial excesses analyses. APTyzer can also be used for<br>\n", + "preparing the meshing of single interface patches (grain or phase boundaries) via setting control points manually.<br>\n", + "These points can be exported and loaded with the paraprobe-toolbox. APTyzer is maintained by Alexander Reichmann,<br>\n", + "who is a PhD student with Lorenz Romaner at the Montanuniversität Leoben, Austria.<br>\n", + "\n", + "To use the tool you should navigate into the respective sub-directory.<br>" ] }, { @@ -69,7 +98,17 @@ "id": "1aa22278", "metadata": {}, "source": [ - "### Step 1: Enter the leoben_apt_analyzer sub-directory via the explorer panel on the left side" + "### Step 1: Navigate into the respective sub-directory via the explorer panel on the left side" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fd98af7", + "metadata": {}, + "outputs": [], + "source": [ + "! cd /home/atom_probe_tools/aptyzer" ] }, { @@ -77,7 +116,7 @@ "id": "cc1408cc-45ec-40c6-90cb-dcec5f900619", "metadata": {}, "source": [ - "### Step 2: Download an example dataset to get started with the leoben_apt_analyzer" + "### Step 2: Download and unpack an example dataset to get started" ] }, { @@ -87,7 +126,23 @@ "metadata": {}, "outputs": [], "source": [ - "! cd /home/atom_probe_tools/leoben_apt_analyzer && wget https://www.zenodo.org/record/6794809/files/aut_leoben_leitner.tar.gz && tar -xvf aut_leoben_leitner.tar.gz" + "! cd /home/atom_probe_tools/aptyzer && wget https://www.zenodo.org/record/6794809/files/aut_leoben_leitner.tar.gz && tar -xvf aut_leoben_leitner.tar.gz" + ] + }, + { + "cell_type": "markdown", + "id": "1d7b6c36-5967-46be-835d-3678c4ef8865", + "metadata": {}, + "source": [ + "### Step 3: Start APTyzer by executing the APT_analyzer.ipynb in a new browser tab" + ] + }, + { + "cell_type": "markdown", + "id": "65cc8b4d-3f83-49fd-94f8-4309852499de", + "metadata": {}, + "source": [ + "Open the aptyzer.ipynb via the JupyterLab side bar (on the left side). Clicking through this notebook will start the graphical user interface." ] }, { @@ -95,7 +150,6 @@ "id": "8cea07f1-ccc5-40f4-881a-f9fec8a3f206", "metadata": {}, "source": [ - "### Step 3: Start the apt_analyzer by executing the leoben_apt_analyzer.ipynb in a new browser tab\n", "### Step 4: Run the tool using the POS and RRNG with the aut_leoben_leitner example dataset." ] }, @@ -104,13 +158,13 @@ "id": "051121d5-f318-42a7-81d8-a11349401e4c", "metadata": {}, "source": [ - "There is a detailed tutorial (cheatsheet.pdf) for the APT_analyzer in the sub-directory of the tool.<br>\n", - "\n", - "The APT_analyzer enables to export manually selected control points to support building computational<br>\n", - "geometry models of interfaces. These control points can be exported to an HDF5 file and this file be<br>\n", - "used as input for the paraprobe-toolbox. Specifically, the control points can be used to instruct<br>\n", - "paraprobe-nanochem to attempt an automatic modelling of an interface.\n", - "\n", + "There is a detailed tutorial (tutorial.pdf) how to use APTyzer for arbitary datasets. The tool offers export functionalities<br>\n", + "for manually selected control points to support building computational geometry models of interfaces.<br>\n", + "These control points can be exported to an HDF5 file and this file can be used for example as input for the<br>\n", + "paraprobe-nanochem tool from the paraprobe-toolbox.<br>\n", + "A respective tutorial how to achieve this is available in the paraprobe-toolbox teaching material<br>\n", + "and here specifically the aut_leoben_leitner example. This tutorial will show how to use the<br>\n", + "control points and create an automatically meshed model for an interface in the dataset.<br>\n", "***" ] }, @@ -124,20 +178,42 @@ "# Getting started with paraprobe-toolbox" ] }, + { + "cell_type": "markdown", + "id": "144832aa-b357-406c-84ad-d410d27bd8c0", + "metadata": { + "tags": [] + }, + "source": [ + "<div class=\"alert alert-block alert-info\">\n", + "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core<br>\n", + "and four GB main memory. Having multiple CPU cores can be useful as the tools of the paraprobe-toolbox use multi-threading for most of the<br>\n", + "numerical and geometrical analyses.<br>\n", + "Making guarantees about the maximum data set sizes (in terms of number of ions) is difficult as it strongly depends on which type of analyses are performed<br>\n", + "and how these are parameterized. Noteworthy to mention is that even the largest examples at the time of writing this cheatsheet which are available in the<br>\n", + "paraprobe-toolbox were processable with a laptop with 32GB main memory in total. Examples with a few million ions consumed not more than one to eight GB.<br>\n", + "</div>" + ] + }, { "cell_type": "markdown", "id": "ec70f493", "metadata": {}, "source": [ - "The paraprobe-toolbox is a collection of software tools for applying computational geometry tasks on tomographic<br>\n", - "reconstructions of atom probe data to extract and characterize microstructural features. The tool is developed<br>\n", - "by <a href=\"https://arxiv.org/abs/2205.13510\">Markus Kühbach et al.</a>. The tool is instructed via a jupyter notebook which documents a script of analysis steps.<br>\n", + "The paraprobe-toolbox is a collection of software tools for applying computational geometry tasks on point cloud data<br>\n", + "such as tomographic reconstructions of atom probe data to extract and characterize microstructural features.<br>\n", + "The tool is developed by <a href=\"https://arxiv.org/abs/2205.13510\">Markus Kühbach et al.</a>. The tool is instructed via a jupyter notebook which documents<br>\n", + "how to chain via scripting different analysis steps. Apart from this, it is possible to use the tools via<br>\n", + "Python scripting to perform e.g. batch processing on computer clusters.<br>\n", "\n", - "During the workflow atom probe data are processable with multiple computational steps.<br>\n", - "Each step uses a different scientific speciality tool. These use CPU parallelization and performance libraries.<br>\n", - "The jupyter notebooks enable users to script the steps of the workflow to automate many steps of the<br>\n", - "data analysis in a reproducible and documented way including iso-surface computations, parameter<br>\n", - "studies, mesh processing, and writing reports or creating plots automatically.<br>" + "Tools of the paraprobe-toolbox are chained into computational workflows. Each step uses a different scientific<br>\n", + "speciality tool. All these tools have *paraprobe* as a prefix in their executable name.<br>\n", + "The tools use CPU parallelization and specific libraries of the computational geometry or other specialists'<br>\n", + "communities. The jupyter notebooks enable users to achieve a complete automation of their<br>\n", + "data analyses (if this is desired). Internally, each tools keeps track of input and output files via<br>\n", + "hashes and time stamps to enable provenance tracking and support repeatable and reproducible research.<br>\n", + "All results are openly accessible and documented via so-called <a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">NeXus application definitions (see the NORTH/apmtools pages).</a><br>\n", + "Such workflows can include parameter studies, mesh processing, writing of reports, and creation of plots.<br>" ] }, { @@ -147,14 +223,16 @@ "tags": [] }, "source": [ - "### Step 1: Enter the paraprobe-toolbox/teaching/example_analyses sub-directory using the jupyter explorer panel to the left." + "### Step 1: Enter the paraprobe-toolbox/teaching/example_analyses sub-directory via the explorer panel to the left." ] }, { "cell_type": "code", "execution_count": null, "id": "f6461c64-cbcd-4d0a-8be3-850205382a71", - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ "# analysis results are stored here:\n", @@ -170,13 +248,11 @@ "id": "bce1299f-24fb-4ffc-99d3-99aac8921136", "metadata": {}, "source": [ - "Reconstruction and ranging data (i.e. POS, ePOS, APT, RNG, RRNG, NXS) to be consumed by paraprobe should be stored in *teaching/example_data*<br>\n", - "Analyses with relevant IPYNB jupyter notebooks should be stored in *teaching/example_analyses*\n", + "Reconstruction and ranging data (i.e. POS, ePOS, APT, RNG, RRNG, NXS) to be consumed by paraprobe-toolbox should be stored in *teaching/example_data*.<br>\n", + "Analyses with relevant jupyter notebooks should be stored in *teaching/example_analyses*.\n", "\n", - "**Using NeXus:** the tools have been modified to enable now reading also data from NeXus/HDF5 files\n", - "which have been created<br>\n", - "with the NXapm application definition (see <a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">nexus-fairmat-proposal</a> and here specifically<br>\n", - "the section about atom probe for more details)." + "The tools use NeXus data schemas and HDF5 files. The specification of these files is documented in the so-called<br>\n", + "<a href=\"https://fairmat-experimental.github.io/nexus-fairmat-proposal\">nexus-fairmat-proposal</a> (see specifically the NORTH/apmtools pages)." ] }, { @@ -184,15 +260,7 @@ "id": "670cc82a-2ea2-4a48-bded-793b15e2f58f", "metadata": {}, "source": [ - "### Step 2: Unpack one of the example datasets or use a NeXus/HDF5 file from your upload section." - ] - }, - { - "cell_type": "markdown", - "id": "31c88293-1cc5-48dd-9f3a-ada16de9ac65", - "metadata": {}, - "source": [ - "Individual examples have to be unpacked/decompressed before you can use them.<br>" + "### Step 2: Unpack the example datasets or use a NeXus/HDF5 file from your uploads section." ] }, { @@ -202,7 +270,8 @@ "metadata": {}, "outputs": [], "source": [ - "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/usa_portland_wang && tar -xvf usa_portland_wang.tar.gz" + "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/usa_portland_wang && tar -xvf usa_portland_wang.tar.gz\n", + "! cd /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aut_leoben_leitner && tar -xvf aut_leoben_leitner.tar.gz" ] }, { @@ -210,15 +279,15 @@ "id": "c409e217-e14a-4bba-a07e-e16753288bd8", "metadata": {}, "source": [ - "Alternatively, **If you have already a NeXus/HDF5 file in your upload section you can also use this file.**<br>\n", - "In order to do so you can move that file into one of the example_data analysis section inside<br>\n", - "the container. This works because the container is configured such that the directory which<br>\n", - "represents the upload section is mounted into the container and accessible via the config section.<br>" + "Alternatively, NeXus/HDF5 files in your uploads section can also be used. In order to do so, you can move<br>\n", + "the respective file(s) into one of the example_data analysis sections inside the container.<br>\n", + "This works because the container is configured such that the directory which represents<br>\n", + "the uploads section is mounted into the apmtools container and is accessible via config directory.<br>" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "id": "22c54c6b-fe0d-4e47-9247-4d5f42761134", "metadata": {}, "outputs": [], @@ -231,7 +300,7 @@ "id": "4fa357bd-7e4a-4c78-afeb-cc4debe34f48", "metadata": {}, "source": [ - "### Step 3: Explore the usage of the tool via jupyter notebooks. Start with the unpacked example usa_portland_wang." + "### Step 3: Start with the unpacked example usa_portland_wang." ] }, { @@ -239,8 +308,15 @@ "id": "8c8865e7-70e9-4309-93c3-5eaf73e2d2e0", "metadata": {}, "source": [ - "Each example comes with a detailed jupyter notebook which guides through the analysis. This notebook documents the workflow<br>\n", - "and instructs it by orchestrating the interaction between python tools, C/C++ tools, HDF5, and H5Web for visualization." + "Each example of the paraprobe-toolbox comes with a detailed jupyter notebook which guides through the analysis.<br>\n", + "Especially the usa_portland_wang and the aut_leoben_leitner (see connection to APTyzer tool) examples<br>\n", + "show the multi-faceted analysis features of the tools in the paraprobe-toolbox.<br>\n", + "These examples show how Python and C/C++ applications work together with NeXus, HDF5, and H5Web<br>\n", + "to provide tools which can be flexibly be coupled to other open-source atom probe software and<br>\n", + "used to complement analyses which have been achieved with commercial software like APSuite/IVAS.<br>\n", + "More complex examples with customizable jupyter notebooks are available in the documentation<br>\n", + "of the tool https://paraprobe-toolbox.readthedocs.io/en/latest/.<br>\n", + "***" ] }, { @@ -248,11 +324,153 @@ "id": "80d09ac1-e56d-4923-9ba3-9e869d368a51", "metadata": {}, "source": [ - "The tool is described in further details in various places https://arxiv.org/abs/2205.13510 and<br>\n", - "https://gitlab.com/paraprobe/paraprobe-toolbox <br>\n", - "The notebooks exemplify how individual tools of the toolbox interact.\n", + "# Getting started with APAV" + ] + }, + { + "cell_type": "markdown", + "id": "bfec8daa-59c3-47b9-a0af-8f03afd5c9a6", + "metadata": {}, + "source": [ + "<div class=\"alert alert-block alert-info\">\n", + "Computational requirements: Examples with dataset with a few million ions like most used below should be processable even on a computer with a single core and say at least 4GB main memory.<br>\n", + "Having multiple CPU cores can be useful as APAV uses multi-threading for some costly numerical analyses.\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "id": "c10fcef1-e82f-4400-af22-f6df70687faf", + "metadata": {}, + "source": [ + "APAV (Atom Probe Analysis and Visualization) is a Python package for analysis and visualization of atom probe tomography datasets.<br>\n", + "The tool is developed by <a href=\"https://joss.theoj.org/papers/10.21105/joss.04862\">Jesse Smith et al.</a>. Complementary to the design of the paraprobe-toolbox functionalities,<br>\n", + "APAV can be chained into workflows via e.g. a jupyter notebook. A particular functional strength and focus of APAV<br>\n", + "has been ranging and handling of so-called multi-hit events via a graphical user interface via Python.<br>\n", + "\n", + "APAV has a detailed documentation https://apav.readthedocs.io/en/latest/index.html." + ] + }, + { + "cell_type": "markdown", + "id": "b75f60d5-3151-4986-9222-ddaeb1fa7e5f", + "metadata": { + "tags": [] + }, + "source": [ + "<div class=\"alert alert-block alert-info\">\n", + "Jesse Smith has also made available example data which can be used for learning the multi-hit event analyses capabilities of APAV. If these files are not available <a href=\"https://doi.org/10.5281/zenodo.6794809\">via this Zenodo repository (version >9)</a>,<br>\n", + "users are requested to inspect the respective file share location from the revision of the APAV JOSS paper <a href=\"https://github.com/openjournals/joss-reviews/issues/4862\">see the comment from jdasm from November 30, 2022 here</a><br>\n", + "The respective GBCO dataset relevant here is especially this one R5038_00333-v02.epos. <a href=\"https://doi.org/10.1017/S1431927621012794\">Scientific details can be found here</a>.\n", + "</div>" + ] + }, + { + "cell_type": "markdown", + "id": "f88501b0-a4bd-427d-b303-a45a3556ab35", + "metadata": { + "tags": [] + }, + "source": [ + "### Step 1: Enter the apav sub-directory via the explorer panel to the left." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "474644bb-75fd-4514-bab5-8d9d30e46610", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "! ls /home/atom_probe_tools/apav" + ] + }, + { + "cell_type": "markdown", + "id": "ba59fb6e-2b63-4e95-99f7-75248c2a4f79", + "metadata": {}, + "source": [ + "### Step 2: Use available files in community-specific formats from your uploads section or download the above-mentioned examples from APAV." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9bf1d28-abff-4628-aaa8-cb61f796e412", + "metadata": {}, + "outputs": [], + "source": [ + "import shutil" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d092aaf-663d-4ef3-9ac7-5fc6762d785f", + "metadata": {}, + "outputs": [], + "source": [ + "! cd /home/atom_probe_tools/apav && wget https://www.zenodo.org/record/77885531/files/apm_sprint14_apav_usa_denton_smith.zip && shutil.unpack_archive(\"apm_sprint14_apav_usa_denton_smith.zip\")" + ] + }, + { + "cell_type": "markdown", + "id": "f65c621e-05f5-45ca-9a01-4cbd3206bc55", + "metadata": { + "tags": [] + }, + "source": [ + "The APAV documentation details which formats are supported." + ] + }, + { + "cell_type": "markdown", + "id": "9e3fb02c-1706-4864-a27c-06aaadc5c11b", + "metadata": { + "tags": [] + }, + "source": [ + "### Step 3: Start a new jupyter-notebook and use it to compose your own analysis workflow." + ] + }, + { + "cell_type": "markdown", + "id": "57c641c2-748c-4c8a-a2f1-4d9428f141a5", + "metadata": {}, + "source": [ + "The APAV documentation can support you with starting your own analyses.\n", "***" ] + }, + { + "cell_type": "markdown", + "id": "a27bbf75-8a2a-4df3-8096-f942afc5e656", + "metadata": {}, + "source": [ + "# Version, funding, feedback\n", + "* **APTyzer** https://github.com/areichm/APTyzer 887b82f\n", + "* **paraprobe-toolbox** https://gitlab.com/paraprobe/paraprobe-toolbox e349fd3 (v0.4)\n", + "* **APAV** https://pypi.org/project/APAV v1.4.0\n", + "* **NeXus** https://fairmat-experimental.github.io/nexus-fairmat-proposal latest\n", + "\n", + "Last revision: Markus Kühbach, 2023/04/17\n", + "\n", + "<a href=\"https://www.fairmat-nfdi.eu/fairmat/\">FAIRmat</a> is a consortium on research data management which is part of the German NFDI.<br>\n", + "The project is funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) – project 460197019.\n", + "\n", + "If you spot issues with this container or you would like to suggest how we can improve the apmtools container:<br>\n", + "Please contact the respective maintainer of this container." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff8b1235-d4c8-4ce0-9013-d1d87b7191df", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -271,7 +489,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.8.16" } }, "nbformat": 4, diff --git a/docker/apmtools/Dockerfile b/docker/apmtools/Dockerfile index 559ea7f38469bd974a7584f0c3115fd7aab8b827..bd71db8477b83a684b2b72d68b6a11e0544d32b0 100644 --- a/docker/apmtools/Dockerfile +++ b/docker/apmtools/Dockerfile @@ -1,7 +1,7 @@ # recipe to create the nomad-remote-tools-hub apmtools container via a dockerfile FROM gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/webtop -# # for testing the container locally without running in oauth errors +# for testing the container locally without running in oauth errors # FROM ghcr.io/linuxserver/webtop:amd64-ubuntu-openbox-version-e1079163 # # found that newest system python is 3.8.something # # rest should come only from and be managed through (mini)conda not pip! @@ -16,67 +16,62 @@ FROM gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/webtop USER root -# query version afterwards like so dpkg -s <packagename> | grep '^Version:' -# OS dependencies, low-level system libraries -RUN apt-get update -RUN apt-get install -y git=1:2.25.1-1ubuntu3.5 \ - && apt-get install -y m4=1.4.18-4 \ - && apt-get install -y file=1:5.38-4 \ - && apt-get install -y wget=1.20.3-1ubuntu2 \ - && apt-get install -y mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 \ - && apt-get install -y libglu1-mesa-dev=9.0.1-1build1 \ - && apt-get install -y build-essential=12.8ubuntu1.1 \ - && apt-get install -y mpich=3.3.2-2build1 \ - && apt-get install -y libgmp-dev=2:6.2.0+dfsg-4 \ - && apt-get install -y libmpfr-dev=4.0.2-1 \ - && rm -rf /var/lib/apt/lists/* \ - && mkdir -p /home \ +RUN mkdir -p /home \ && mkdir -p /home/atom_probe_tools \ - && wget https://repo.anaconda.com/miniconda/Miniconda3-py39_4.12.0-Linux-x86_64.sh \ - && mv Miniconda3-py39_4.12.0-Linux-x86_64.sh miniconda3_py3.9_4.12.0_linux_x86_64.sh \ - && chmod +x miniconda3_py3.9_4.12.0_linux_x86_64.sh \ - && bash ./miniconda3_py3.9_4.12.0_linux_x86_64.sh -b -p /usr/local/miniconda3 \ - && rm -f miniconda3_py3.9_4.12.0_linux_x86_64.sh + && mkdir -p /home/atom_probe_tools/apav \ + && mkdir -p /home/atom_probe_tools/aptyzer -# future improvements should use --no-install-recommends to safe space further, but for mpich this created problems when building paraprobe +COPY Cheatsheet.ipynb FAIRmatNewLogo.png NOMADOasisLogo.png /home/atom_probe_tools/ +ENV PATH=/usr/local/miniconda3/bin:/home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cmake/cmake-3.26.3/localinstallation/bin:$PATH -COPY Cheatsheet.ipynb FAIRmat_S.png APT_analyzer.ipynb /home/atom_probe_tools/ - -# add all relevant environment variables that required for building the -# container make sure to reflect eventual changes of the cmake version -ENV PATH=/usr/local/miniconda3/bin:/home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cmake/cmake-3.22.2/localinstallation/bin:$PATH +# query version afterwards like so dpkg -s <packagename> | grep '^Version:' +# OS dependencies, low-level system libraries, --fix-missing, rm -rf /var/lib/apt/lists/* +# future improvements should use --no-install-recommends to safe space further, but for mpich this created problems when building paraprobe-toolbox -RUN mkdir -p /home \ +RUN cd ~ \ + && apt update \ + && apt install -y curl=7.68.0-1ubuntu2.18 \ + && curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh \ + && chmod +x nodesource_setup.sh \ + && ./nodesource_setup.sh \ + && apt install -y nodejs=18.16.0-deb-1nodesource1 \ + && apt install -y m4=1.4.18-4 file=1:5.38-4 git=1:2.25.1-1ubuntu3.11 wget=1.20.3-1ubuntu2 mesa-common-dev=21.2.6-0ubuntu0.1~20.04.2 libglu1-mesa-dev=9.0.1-1build1 build-essential=12.8ubuntu1.1 mpich=3.3.2-2build1 libgmp-dev=2:6.2.0+dfsg-4ubuntu0.1 libmpfr-dev=4.0.2-1 libssl-dev=1.1.1f-1ubuntu2.18 hwloc=2.1.0+dfsg-4 \ + && wget https://repo.anaconda.com/miniconda/Miniconda3-py38_23.1.0-1-Linux-x86_64.sh \ + && mv Miniconda3-py38_23.1.0-1-Linux-x86_64.sh miniconda3-py38_23.1.0-1-Linux-x86_64.sh \ + && chmod +x miniconda3-py38_23.1.0-1-Linux-x86_64.sh \ + && bash ./miniconda3-py38_23.1.0-1-Linux-x86_64.sh -b -p /usr/local/miniconda3 \ + && rm -f miniconda3-py38_23.1.0-1-Linux-x86_64.sh \ && cd /home \ && conda config --add channels conda-forge \ && conda config --set channel_priority strict \ - && conda install python ipykernel=6.15.3 gitpython=3.1.27 nomkl=1.0 pandas=1.4.4 ase=3.22.1 radioactivedecay=0.4.15 scikit-learn=1.1.2 silx=1.0.0 jupyterlab=3.4.7 nodejs=18.9.0 \ - && pip install jupyterlab_h5web[full]==6.0.1 \ + && conda install -c conda-forge nomkl=1.0 jupyterlab-h5web=7.0.0 jupyterlab=3.6.3 hdbscan=0.8.29 gitpython=3.1.31 nodejs=18.15.0 ase=3.19.0 radioactivedecay=0.4.17 pandas=2.0.0 sphinx=6.1.3 \ && conda clean -afy \ - && mkdir -p /home/atom_probe_tools \ - && mkdir -p /home/atom_probe_tools/leoben_apt_analyzer \ - && git clone https://github.com/areichm/APT_analyzer.git \ - && cd APT_analyzer \ - && git checkout 6ee93ca6052c221ae335cbaa2a218911024301fa \ - && cp APT_analyzer_tutorial.pdf /home/atom_probe_tools/leoben_apt_analyzer/cheatsheet.pdf \ - && cp /home/atom_probe_tools/APT_analyzer.ipynb /home/atom_probe_tools/leoben_apt_analyzer/leoben_apt_analyzer.ipynb \ - && cp LICENSE /home/atom_probe_tools/leoben_apt_analyzer/LICENSE \ - && cp README.md /home/atom_probe_tools/leoben_apt_analyzer/README.md \ - && cp apt_importers.py /home/atom_probe_tools/leoben_apt_analyzer/apt_importers.py \ - && cd .. \ - && rm -rf APT_analyzer \ - && rm /home/atom_probe_tools/APT_analyzer.ipynb \ + && cd /home \ + && python3 -m pip install --upgrade pip \ + && python3 -m pip install ecdf==0.7.0 pytictoc==1.5.2 ifes-apt-tc-data-modeling==0.0.8 python-docs-theme==2023.3.1 \ + && cd /home \ + && cd /home/atom_probe_tools/apav \ + && python3 -m pip install apav==1.4.0 \ + && cd /home/atom_probe_tools \ + && git clone https://github.com/areichm/APTyzer.git \ + && cd APTyzer \ + && git checkout 887b82f \ + && cp APTyzer_V_1_2o.ipynb /home/atom_probe_tools/aptyzer/aptyzer.ipynb \ + && cp LICENSE /home/atom_probe_tools/aptyzer/LICENSE \ + && cp README.md /home/atom_probe_tools/aptyzer/README.md \ + && cp Tutorial_APTyzer_V1_2.pdf /home/atom_probe_tools/aptyzer/tutorial.pdf \ + && rm -rf /home/atom_probe_tools/APTyzer \ && cd /home/atom_probe_tools \ && git clone https://gitlab.com/paraprobe/paraprobe-toolbox.git \ && cd paraprobe-toolbox \ - && git checkout b95be8c9e79f044fd8716ffe5d2b7adf4e14208d \ + && git checkout e349fd34d7cfcb4282c2f3f61c69f9e5659f68e6 \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p cmake \ && cd cmake \ - && wget https://cmake.org/files/v3.22/cmake-3.22.2.tar.gz \ - && tar -xvf cmake-3.22.2.tar.gz \ - && rm -rf cmake-3.22.2.tar.gz \ - && cd cmake-3.22.2 \ + && wget https://cmake.org/files/v3.26/cmake-3.26.3.tar.gz \ + && tar -xvf cmake-3.26.3.tar.gz \ + && rm -rf cmake-3.26.3.tar.gz \ + && cd cmake-3.26.3 \ && mkdir -p localinstallation \ && chmod +x bootstrap \ && ./bootstrap --prefix="$PWD/localinstallation/" -- -DCMAKE_USE_OPENSSL=OFF 2>&1 | tee PARAPROBE.CMake.Bootstrap.STDOUTERR.txt \ @@ -85,37 +80,18 @@ RUN mkdir -p /home \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p hdf5 \ && cd hdf5 \ - && wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.13/hdf5-1.13.2/src/CMake-hdf5-1.13.2.tar.gz \ - && gunzip CMake-hdf5-1.13.2.tar.gz \ - && tar -xvf CMake-hdf5-1.13.2.tar \ - && rm -rf CMake-hdf5-1.13.2.tar \ - && cd CMake-hdf5-1.13.2 \ + && wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.14/hdf5-1.14.0/src/CMake-hdf5-1.14.0.tar.gz \ + && tar -xvf CMake-hdf5-1.14.0.tar.gz \ + && rm -rf CMake-hdf5-1.14.0.tar.gz \ + && cd CMake-hdf5-1.14.0 \ && ./build-unix.sh 2>&1 | tee PARAPROBE.Hdf5.Build.STDOUTERR.txt \ - && ./HDF5-1.13.2-Linux.sh --include-subdir --skip-license 2>&1 | tee PARAPROBE.Hdf5.Install.STDOUTERR.txt \ + && ./HDF5-1.14.0-Linux.sh --include-subdir --skip-license 2>&1 | tee PARAPROBE.Hdf5.Install.STDOUTERR.txt \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p boost \ && cd boost \ - && wget https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz \ - && tar -xvf boost_1_80_0.tar.gz \ - && rm -f boost_1_80_0.tar.gz \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ - && mkdir -p fftw \ - && cd fftw \ - && wget https://www.fftw.org/fftw-3.3.10.tar.gz \ - && tar -xvf fftw-3.3.10.tar.gz \ - && rm -f fftw-3.3.10.tar.gz \ - && cd fftw-3.3.10 \ - && mkdir -p localinstallation \ - && ./configure --prefix="$PWD/localinstallation/" --enable-float --enable-sse 2>&1 | tee PARAPROBE.FFTW.Configure.STDOUTERR.txt \ - && make -j4 2>&1 | tee PARAPROBE.FFTW.Make4.STDOUTERR.txt \ - && make check 2>&1 | tee PARAPROBE.FFTW.MakeCheck.STDOUTERR.txt \ - && make install 2>&1 | tee PARAPROBE.FFTW.MakeInstall.STDOUTERR.txt \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ - && mkdir -p tetgen \ - && cd tetgen \ - && tar -xvf tetgen1.6.0.tar.gz \ - && cd tetgen1.6.0 \ - && make -j4 tetlib 2>&1 | tee PARAPROBE.TetGen.Make4.STDOUTERR.txt \ + && wget https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz \ + && tar -xvf boost_1_81_0.tar.gz \ + && rm -f boost_1_81_0.tar.gz \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p eigen \ && cd eigen \ @@ -125,80 +101,54 @@ RUN mkdir -p /home \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p cgal \ && cd cgal \ - && wget https://github.com/CGAL/cgal/releases/download/v5.5/CGAL-5.5.tar.xz \ - && tar -xvf CGAL-5.5.tar.xz \ - && rm -f CGAL-5.5.tar.xz \ + && wget https://github.com/CGAL/cgal/releases/download/v5.5.2/CGAL-5.5.2.tar.xz \ + && tar -xvf CGAL-5.5.2.tar.xz \ + && rm -f CGAL-5.5.2.tar.xz \ && cd /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory \ && mkdir -p voroxx \ && cd voroxx \ && git clone https://github.com/chr1shr/voro.git \ && cd voro \ && git checkout 56d619faf3479313399516ad71c32773c29be859 \ - && cd .. \ - && mv voro voro++-0.4.6 \ && cd /home/atom_probe_tools/paraprobe-toolbox \ - && sed -i 's|set(MYPROJECTPATH "<<YOURPATH>>")|set(MYPROJECTPATH \"'"$PWD"'\/\")|g' /home/atom_probe_tools/paraprobe-toolbox/code/PARAPROBE.Dependencies.cmake \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_ranger /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_ranger \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_surfacer /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_surfacer \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_distancer /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_distancer \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_tessellator /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_tessellator \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_nanochem /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_nanochem \ - && mkdir -p /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \ - && cd /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \ - && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=mpicxx .. \ - && make -j4 \ - && cp paraprobe_intersector /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_intersector \ - && chmod +x /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe_* \ + && sed -i 's|set(MYPROJECTPATH "<<YOURPATH>>/paraprobe-toolbox")|set(MYPROJECTPATH \"'"$PWD"'\/\")|g' code/PARAPROBE.Dependencies.cmake \ && cd /home/atom_probe_tools/paraprobe-toolbox \ - && rm -f PARAPROBE.Step*.sh \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-clusterer \ + && chmod +x PARAPROBE.Step05.Build.Tools.sh \ + && ./PARAPROBE.Step05.Build.Tools.sh \ + && chmod +x PARAPROBE.Step06.Install.Tools.sh \ + && ./PARAPROBE.Step06.Install.Tools.sh \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/boost \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/cgal \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/chrono \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/eigen \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/hdf5 \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/hornus2017 \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/lewiner2002 \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/mandatory/voroxx \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-utils/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-ranger/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-selector/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-surfacer/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-distancer/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-tessellator/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-spatstat/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-nanochem/build \ + && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-intersector/build \ && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-crystalstructure \ && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-miscellaneous \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/paraprobe-spatstat \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/code/thirdparty/ \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/aus_sydney_rielli_primig \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/aut_leoben_mendez_martin \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_analyses/ger_berlin_kuehbach_fairmat \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aus_sydney_rielli_primig \ - && rm -rf /home/atom_probe_tools/paraprobe-toolbox/teaching/example_data/aut_leoben_mendez_martin \ && chown -R ${PUID}:${PGID} /home \ && chown -R ${PUID}:${PGID} /usr/local/miniconda3 +# all rm -rf statements should only be used during container build when we do not like +# to have a version which can be recompiled inside the container # as the entire C/C++ executables for all thirdparty dependencies are linked -# statically the entire thirdparty/mandatory can be deleted +# statically the entire thirdparty/mandatory is deleted during the container build +# which freezes the state of each paraprobe tool but has the disadvantage that the +# tools can then not be recompiled from inside the container COPY 02-exec-cmd /config/custom-cont-init.d/02-exec-cmd ENV HOME=/home/atom_probe_tools WORKDIR $HOME -# further optimization for the future could be to copy the content from conda bin and lib over like done in -# https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/-/blob/develop/docker/nionswift/Dockerfile -# but there might be more low level dependencies from h5web so this is currently not used - -# for running this container standalone e.g. -# docker run -p 3000:8888 <<imagename>> \ No newline at end of file +# for running this container standalone e.g. docker run -p 3000:8888 <<imagename>> diff --git a/docker/apmtools/FAIRmatNewLogo.png b/docker/apmtools/FAIRmatNewLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba8697486c07a914800f7519a978306e12d5637 Binary files /dev/null and b/docker/apmtools/FAIRmatNewLogo.png differ diff --git a/docker/apmtools/FAIRmat_S.png b/docker/apmtools/FAIRmat_S.png deleted file mode 100644 index 43c597e6f09d0850fd1b7c646a481d7c8f0ef3f4..0000000000000000000000000000000000000000 Binary files a/docker/apmtools/FAIRmat_S.png and /dev/null differ diff --git a/docker/apmtools/NOMADOasisLogo.png b/docker/apmtools/NOMADOasisLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..b5f82fd462e34ef25e8e93ba6aa834a212d001dc Binary files /dev/null and b/docker/apmtools/NOMADOasisLogo.png differ diff --git a/tools.json b/tools.json index f416bd9677e21e4bfac9de04a806f888242270ad..047db2d776b9d28230b4911d841ec41cc68298c1 100644 --- a/tools.json +++ b/tools.json @@ -134,7 +134,7 @@ }, "apmtools": { "short_description": "An example for analyzing atom probe data.", - "description": "Miscellaneous tools from the atom probe community:\nCurrently the Leoben APT_analyzer and the paraprobe-toolbox.", + "description": "Miscellaneous tools from the atom probe community:\nCurrently APTyzer, paraprobe-toolbox, and APAV.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.", "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/apmtools-webtop", "privileged": true, "icon": "jupyter_logo.svg", @@ -148,7 +148,7 @@ }, "fiji": { "short_description": "ImageJ and Fiji for image processing", - "description": "ImageJ and Fiji with amongst others several electron-microscopy specific plug-ins", + "description": "ImageJ and Fiji with amongst others several electron-microscopy specific plug-ins.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.", "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/fiji-webtop", "privileged": true, "icon": "jupyter_logo.svg", @@ -162,7 +162,7 @@ }, "frwr": { "short_description": "Inline electron holography by C. Koch", - "description": "FRWR3 in-line holography/focus series reconstruction code", + "description": "FRWR3 in-line holography/focus series reconstruction code.", "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/frwr-webtop", "privileged": true, "icon": "jupyter_logo.svg", @@ -176,7 +176,7 @@ }, "abtem": { "short_description": "Electronic structure supported image simulation for transmission electron microscopy.", - "description": "VESTA, GPAW, and abTEM configured in one container for simulating images and diffraction patterns in transmission electron microscopy", + "description": "VESTA, GPAW, and abTEM configured in one container for simulating images and diffraction patterns in transmission electron microscopy.\nA JupyterLab instance will start which has a detailed Cheatsheet notebook for getting started.", "image": "gitlab-registry.mpcdf.mpg.de/nomad-lab/nomad-remote-tools-hub/abtem-webtop", "privileged": true, "icon": "jupyter_logo.svg",