Merge branch 'devel'
epsi-builds/msspec_python3/pipeline/head There was a failure building this commit Details

This commit is contained in:
Sylvain Tricot 2021-09-24 16:36:53 +02:00
commit 75784d4c01
36 changed files with 1378 additions and 740 deletions

View File

@ -1,22 +1,24 @@
# Get the base Python image # Get the base Python image
FROM python:latest FROM python:latest
# Install system dependencies
RUN apt-get update && apt-get install -y virtualenv gfortran libgtk-3-dev nano
# Add a non-privileged user
RUN useradd -ms /bin/bash -d /opt/msspec msspec
# Set the working directory in the container # Set the working directory in the container
WORKDIR /code USER msspec
RUN mkdir -p /opt/msspec/code
WORKDIR /opt/msspec/code
# Fetch the code # Fetch the code
RUN git clone --branch devel https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git . RUN git clone --branch devel https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git .
#COPY --chown=msspec:msspec . .
# Install system dependencies
RUN apt-get update && apt-get install -y virtualenv gfortran libgtk-3-dev
# Install msspec # Install msspec
ENV PATH=/opt/bin:$PATH ENV PATH=/opt/msspec/.local/bin:$PATH
RUN make install VERBOSE=1 INSTALL_PREFIX=/opt RUN make install VERBOSE=1
# Add a non-privileged user
RUN useradd -ms /bin/bash msspec
USER msspec
# Run the msspec frontend command on startup # Run the msspec frontend command on startup
ENTRYPOINT ["msspec"] ENTRYPOINT ["msspec"]

View File

@ -11,7 +11,7 @@ pybinding:
venv: venv:
ifeq ($(NO_VENV),0) ifeq ($(NO_VENV),0)
@virtualenv --python=$(PYTHON_EXE) --prompt="(msspec-$(VERSION)) " $(VENV_PATH) @virtualenv --python=$(PYTHON_EXE) --prompt="(msspec-$(VERSION)) " $(VENV_PATH)
@$(INSIDE_VENV) pip install --upgrade pip && pip install -r src/pip.freeze $(INSIDE_VENV) wget https://bootstrap.pypa.io/get-pip.py && python get-pip.py && pip install -r src/pip.freeze && rm -f get-pip.py
endif endif
@ -27,7 +27,7 @@ devel: venv pybinding wx
@$(INSIDE_VENV) pip install -e src/ @$(INSIDE_VENV) pip install -e src/
wx: _build_wx/wxPython.target:
@$(INSIDE_VENV) echo "Building wxPython for your `python --version 2>&1` under Linux $(DISTRO_RELEASE)..." @$(INSIDE_VENV) echo "Building wxPython for your `python --version 2>&1` under Linux $(DISTRO_RELEASE)..."
# Create a folder to build wx into # Create a folder to build wx into
@mkdir -p _build_wx @mkdir -p _build_wx
@ -40,16 +40,22 @@ wx:
cd `ls -d wxPython*/`; \ cd `ls -d wxPython*/`; \
pip install requests; \ pip install requests; \
python build.py dox etg --nodoc sip build bdist_wheel; \ python build.py dox etg --nodoc sip build bdist_wheel; \
ln -s `readlink -f dist/wxPython*.whl` ../; \ ln -sf `readlink -f dist/wxPython*.whl` ../; \
fi; fi;
# Finally touch a dummy file to avoid phony target
@touch _build_wx/wxPython.target
wx: _build_wx/wxPython.target
# Install the wheel # Install the wheel
@$(INSIDE_VENV) cd _build_wx && pip install wxPython*.whl @$(INSIDE_VENV) cd _build_wx && pip install wxPython*.whl
doc: doc: VENV_PATH = ./_venv
doc: venv
@echo "Building pdf and html documentation..." @echo "Building pdf and html documentation..."
@$(INSIDE_VENV) pip install sphinx @$(INSIDE_VENV) pip install sphinx
@+$(INSIDE_VENV) $(MAKE) -C doc/ latexpdf # @+$(INSIDE_VENV) $(MAKE) -C doc/ latexpdf
@+$(INSIDE_VENV) $(MAKE) -C doc/ html @+$(INSIDE_VENV) $(MAKE) -C doc/ html

View File

@ -4,8 +4,8 @@ Introduction
This is the Python MsSpec version with support for Python 3.x and dynamic memory allocation for Phagen and Spec This is the Python MsSpec version with support for Python 3.x and dynamic memory allocation for Phagen and Spec
Installation of the devel package Installation
================================= ============
Requirements Requirements
------------ ------------
@ -42,13 +42,14 @@ you need to install it.
Fetching the code Fetching the code
----------------- -----------------
You first need to clone the devel branch with either 2 commands below: You first need to clone the repository with the command below:
```Bash ```Bash
git clone https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git git clone https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git
git checkout devel
``` ```
If you want to pull the devel branch (unstable):
```Bash ```Bash
git clone --branch devel https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git git clone --branch devel https://git.ipr.univ-rennes1.fr/epsi/msspec_python3.git
``` ```
@ -61,21 +62,22 @@ One step install
---------------- ----------------
The command below will do all the stuff to install msspec in its dedicated Python The command below will do all the stuff to install msspec in its dedicated Python
virtual environment provided all the above requirements are fullfilled virtual environment provided all the above requirements are fullfilled:
```Bash ```Bash
cd msspec_python3 cd msspec_python3
make devel make install
``` ```
This will: This will:
- Create a Python virtual environment in the "\_venv" folder inside the msspec\_python3 folder. - Create a Python virtual environment in your '~/.local/src' folder
- Install all the required Python packages in this virtual environment. - Install all the required Python packages in this virtual environment.
- Install (or even maybe build) wxPython for your OS and Python version in this virtual environment. - Install (or even maybe build) wxPython for your OS and Python version in this virtual environment.
- Build the msspec shared librarires. - Build the msspec shared librarires.
- Install msspec in *edit mode* in this virtual environment. - Install the Python msspec package in this virtual environment.
- Install a frontend script called 'msspec' in the '~/.local/bin' folder.
You can tweak the process by specifying space separated key=value pairs on the command line. You can tweak the process by specifying space separated key=value pairs on the command line.
Allowed keys are: Allowed keys are:
@ -89,35 +91,61 @@ Allowed keys are:
- FC, the Fortran compiler to use (gfortran) - FC, the Fortran compiler to use (gfortran)
- F2PY - F2PY
To install msspec in developpment mode, use:
Work with msspec
----------------
All you need to do each time you want to work with msspec is activating the virtual environment.
For example, if *virtualenv* was used to create the virtual environment:
```Bash ```Bash
source msspec_python3/_venv/bin/activate cd msspec_python3
make devel
``` ```
Then you can launch your script with This will do the same steps as above except that the virtual environment will be located in
the "\_venv" folder inside the "msspec\_python3" folder and the frontend script will not be
installed.
Working with msspec
-------------------
Use the frontend command to process a Python script with msspec.
```Bash ```Bash
python myscript.py msspec -p myscript.py
``` ```
This will execute the myscript.py inside the msspec virtual environment.
You can also load a hdf5 file with the '-l' option:
```Bash
msspec -l results.hdf5
```
You can load an iPython console with "msspec -i". It is a good way to modify the virtual environment
of MsSpec since you can add or remove packages withe the "%pip" command.
If you want to activate the MsSpec virtual environment in your current shell session:
```Bash
eval $(msspec -e)
```
You can then run scripts using the 'python' command directly.
Type in 'deactivate' to go back to your standard shell.
See the online [tutorials](https://msspec.cnrs.fr/tutorials/index.html) for more information on how to use msspec. See the online [tutorials](https://msspec.cnrs.fr/tutorials/index.html) for more information on how to use msspec.
When you're done, you can deactivate the virtual environment with
```Bash
deactivate
```
Uninstall MsSpec Uninstall MsSpec
---------------- ----------------
To remove MsSpec, use the command:
```Bash
msspec -u
```
This will simply remove the virtual environment folder in '~/.local/src' and the frontend script in '~/.local/bin'.
When Installed in "devel mode", nothing is created outside the msspec\_python3 folder, so you just have to remove When Installed in "devel mode", nothing is created outside the msspec\_python3 folder, so you just have to remove
that folder to get rid of msspec on your computer that folder to get rid of msspec on your computer

View File

@ -44,7 +44,6 @@ clean:
@rm -f source/spectroscopies/common_parameters.inc @rm -f source/spectroscopies/common_parameters.inc
@rm -f source/spectroscopies/ped/ped_parameters.inc @rm -f source/spectroscopies/ped/ped_parameters.inc
@rm -f source/spectroscopies/eig/eig_parameters.inc @rm -f source/spectroscopies/eig/eig_parameters.inc
@rm -f source/downloads.rst

View File

@ -258,7 +258,7 @@ texinfo_documents = [
# How to display URL addresses: 'footnote', 'no', or 'inline'. # How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote' #texinfo_show_urls = 'footnote'
custom.generate_download_page() #custom.generate_download_page()
custom.generate_parameters() custom.generate_parameters()
custom.generate_parameters(spectroscopy='PED') custom.generate_parameters(spectroscopy='PED')
custom.generate_parameters(spectroscopy='EIG') custom.generate_parameters(spectroscopy='EIG')

View File

@ -29,6 +29,9 @@ def generate_download_page():
Download and install notes Download and install notes
########################## ##########################
.. warning::
The content of this page is outdated. An updated version will be soon available.
click :download:`here <{}>` to download the last version of MsSpec and click :download:`here <{}>` to download the last version of MsSpec and
:download:`here <{}>` for this website as a single pdf file :download:`here <{}>` for this website as a single pdf file

150
doc/source/downloads.rst Normal file
View File

@ -0,0 +1,150 @@
.. |LINUXSCRIPT| replace:: https://git.ipr.univ-rennes1.fr/epsi/msspec_python3/raw/branch/devel/utils/dockerized/linux/msspec
##########################
Download and install notes
##########################
************
Installation
************
There are 2 ways to install MsSpec. You can either:
- Use a Docker image. This is, by far, the most straightforward and easy way to work with MsSpec.
- Compile your own version for your system.
1. Using a Docker image
-----------------------
You first need `Docker <https://www.docker.com>`_ to be installed on your system.
This is really straightforward. Please see the `Docker documentation
<https://docs.docker.com/engine/install/>`_ for more information depending on
your OS.
* **For Linux**,
* Download :download:`this script <../../utils/dockerized/linux/msspec>` and
make it executable (with the *chmod u+x msspec* command)
* Place it in a location known to your $PATH (or add this location to your $PATH if needed).
The *~/.local/bin* folder is a good choice.
* **For Windows**
* You need a running X server. Download and install `VcXsrv <https://sourceforge.net/projects/vcxsrv/>`_
* Install the small :download:`MsSpec frontend <../../utils/dockerized/windows/msspec_setup.exe>`
* While not necessary, it is also a good idea to use a better terminal application than the default one.
`Windows Terminal <https://www.microsoft.com/fr-fr/p/windows-terminal/9n0dx20hk701#activetab=pivot:overviewtab>`_
may be a good choice.
* **For Mac**
* *To be documented*
Open a terminal in Linux, or a powershell in Windows and type in::
msspec
The first time you run the command, it will download the msspec image (it may takes several minutes or half an hour
depending on your internet connexion).
The command will automatically create a new container and start it.
As the command was entered without any argument on the command-line, the help message should be printed on the screen
.. code-block:: text
Usage: 1) msspec -p [PYTHON OPTIONS] SCRIPT [ARGUMENTS...]
2) msspec [-l FILE | -i | -h]
3) msspec [bash | reset]
Form (1) is used to launch a script
Form (2) is used to load a hdf5 data file
Form (3) is used to control the Docker container/image.
List of possible options:
-p Pass every arguments after this option to the msspec
virtual environment Python interpreter.
-i Run the interactive Python interpreter within msspec
virtual environment.
-l Load and display a *.hdf5 data file in a graphical
window.
-v Print the version.
-h Show this help message.
bash This command starts an interactive bash shell in the
MsSpec container.
reset This command removes the MsSpec container (but not the
image). Changes made in the container will be lost and
any new call to msspec will recreate a new fresh container.
2. Compile your own version
---------------------------
To install MsSpec this way, follow the instructions `here <https://git.ipr.univ-rennes1.fr/epsi/msspec_python3/src/branch/devel>`_
***************************
Running your Python scripts
***************************
You can run your MsSpec Python scripts (e.g. *my_script.py*) by typing in::
msspec -p my_script.py
This command is equivalent to activating the Python virtual environment MsSpec is intsalled in
and to run the Python interpreter of that environment (everything that follows the -p option is
passed to the python command).
You can also launch the Interactive Python (iPython) of MsSpec::
msspec -i
Inside this interactive session, you can run a script with the command::
%run my_script.py
You can interact with your filesystem with the classical *cd*, *ls*, *cp*, *rm*... commands.
and you can edit your script with::
%ed my_script.py
.. warning::
**If using the Docker image of MsSpec in Linux**, your home folder on the host machine is bind mounted
in the same location in the container and your UID and GID are also set so that creating files within
your home file hierarchy is totally transparent.
**If using the Docker image of MsSpec in Windows**, the drive containing your "My Documents" folder on the
host machine is bind mounted on the container at the root of the filesystem. For example, if your
"My documents" folder on Windows are in 'D:\\Home\\Bob\\MyDocuments', it will be available in the container as
'/D/Home/Bob/MyDocuments'. It has two consequences:
#. The msspec command will fail if running on another drive than the one where is located "My Documents"
#. You have to specify filenames with the Unix slashes. For example if you want to run the script located
in *.\\results\\my_script.py*, you will have to enter *msspec -p ./results/my_script.py*
**************
Uninstallation
**************
* **Under Linux**, type in::
msspec -u
* **Under Windows**, simply `uninstall the application from the Settings page
<https://support.microsoft.com/en-us/windows/uninstall-or-remove-apps-and-programs-in-windows-10-4b55f974-2cc6-2d2b-d092-5905080eaf98>`_.
A command window will pop-up and you will have to answer 'y' to remove MsSpec.
* **Under Mac OS**, *to be documented.*

View File

@ -7,4 +7,5 @@ FAQ
.. toctree:: .. toctree::
hemispherical_cluster/hemispherical_cluster hemispherical_cluster/hemispherical_cluster
coverage_report/coverage_report
.. coverage_report/coverage_report

View File

@ -135,7 +135,6 @@ Table of Contents
.. only:: html .. only:: html
################## ##################
@ -156,4 +155,4 @@ Table of Contents
.. toctree:: .. toctree::
:glob: :glob:
modules/* modules/*

View File

@ -1,124 +0,0 @@
************
Installation
************
.. |logowin| image:: windows_icon.png
:height: 96px
:target: `win10_install_notes`_
.. |logolinux| image:: linux_icon.png
:height: 96px
:target: `linux_install_notes`_
.. |logomac| image:: apple_icon.png
:height: 96px
:target: `mac_install_notes`_
.. admonition:: Select your Operating System to view specific installation instructions
|logowin| |logolinux| |logomac|
.. _common_install_notes:
In a terminal window, execute the setup program you've just downloaded.
.. code-block:: console
$ sh ./MsSpec-version.setup
Once the install process has competed, you can launch the MsSpec environnement by typing::
msspec
.. _win10_install_notes:
For Windows 10
==============
Windows users can install MsSpec through the Windows Subsystem for Linux
(also known as bash Ubuntu).
Below is a short description of the steps to enable this feature. You can
have more details `here <https://docs.microsoft.com/en-us/windows/wsl/install-win10>`_.
Install the Windows Subsystem for Linux
---------------------------------------
1. Turn on Developer Mode
Open **Settings -> Update and Security -> For developers**
.. figure:: win_step1.png
:align: center
:width: 70%
Select the Developer Mode radio button
2. Open a command prompt. Run::
bash
.. figure:: win_step2.png
:align: center
:width: 70%
Type "y" to accept the license. An Ubuntu system will be installed.
3. Launch a new Ubuntu shell by running *bash* from the command prompt.
If this is the first time that the Windows Subsystem for Linux is installed,
you will be prompted to create a UNIX user. Simply follow the instructions.
This UNIX username and password may be different from your Windows username
and password.
Install an X server
-------------------
To allow graphical windows to popup in this Linux environnement, you need to install
an X server. **Xming** is a good choice. Go to `this website <http://www.straightrunning.com/XmingNotes/>`_
and download and install the public version 6.9.0.31.
Don't forget to start the server after the install. You can configure it to always run automatically at
the startup.
Install MsSpec
--------------
Open a Windows command prompt and launch *bash*. For the Xming server to work, you need to modify
the DISPLAY environnement variable. Enter this command::
echo "export DISPLAY=:0" >> ~/.bashrc && source ~/.bashrc
Then you can launch the setup program::
cd /where/the/setup/program/was/downloaded
sh ./MsSpec-version.setup
where *version* is the actual version number
.. _linux_install_notes:
For Linux
=========
Ubuntu and Mageia based dstributions are supported by the installer, but any Linux
flavour should be able to run MsSpec as long as you have permissions to install
all requirements.
You just need to open a terminal window and execute the setup program.
.. _mac_install_notes:
For Mac 0S
==========
.. note::
to be written...

View File

@ -1,6 +0,0 @@
:orphan:
.. automodule:: config
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,6 @@
:orphan:
.. automodule:: looper
:members:
:undoc-members:
:show-inheritance:

View File

@ -0,0 +1,6 @@
:orphan:
.. automodule:: version
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,181 +1,130 @@
# coding: utf-8 # coding: utf8
from msspec.utils import * from ase.build import bulk
from ase.build import bulk import numpy as np
from ase.visualize import view from msspec.calculator import MSSPEC, XRaySource
import numpy as np from msspec.utils import hemispherical_cluster, get_atom_index
from msspec.calculator import MSSPEC, XRaySource
from msspec.iodata import Data def create_clusters(nplanes=6):
from itertools import product def get_AlN_tags_planes(side, emitter):
AlN = bulk('AlN', crystalstructure='wurtzite', a=3.11, c=4.975)
DATA = None [atom.set('tag', i) for i, atom in enumerate(AlN)]
if side == 'Al':
def AlN_cluster(emitter_tag, emitter_plane, diameter=0, planes=0, term_anion=True, tetra_down=True): AlN.rotate([0,0,1],[0,0,-1])
""" Al_planes = range(0, nplanes, 2)
This function is a kind of overload of the hemispherical_cluster function with specific attributes N_planes = range(1, nplanes, 2)
to the AlN structure else:
N_planes = range(0, nplanes, 2)
:param emitter_tag: An integer that allows to identify the kind of atom to use as the emitter Al_planes = range(1, nplanes, 2)
:param emitter_plane: The plane where the emitter is. 0 means the surface. if emitter == 'Al':
:param diameter: The diameter of the cluster (in Angstroms). tags = [0, 2]
:param planes: The total number of planes. planes = Al_planes
:param term_anion: True if the surface plane is anion terminated, False otherwise else:
:param tetra_down: The orientation of the tetrahedral tags = [1, 3]
:return: planes = N_planes
""" return AlN, tags, planes
# create the initial cluster of AlN clusters = []
cluster = bulk('AlN', crystalstructure='wurtzite', a=3.11, c=4.975) for side in ('Al', 'N'):
for emitter in ('Al', 'N'):
# tag each atom in the unit cell because they are all in a different chemical/geometrical environment AlN, tags, planes = get_AlN_tags_planes(side, emitter)
# (0 and 2 for Aluminum's atoms and 1 and 3 for Nitride's atoms) for emitter_tag in tags:
[atom.set('tag', i) for i, atom in enumerate(cluster)] for emitter_plane in planes:
cluster = hemispherical_cluster(AlN,
# change the orientation of the tetrahedron emitter_tag=emitter_tag,
if not tetra_down: emitter_plane=emitter_plane,
cluster.rotate(180, 'y') planes=emitter_plane+2)
cluster.absorber = get_atom_index(cluster, 0, 0, 0)
# From this base pattern, creat an hemispherically shaped cluster cluster.info.update({
cluster = hemispherical_cluster(cluster, emitter_tag=emitter_tag, emitter_plane=emitter_plane, diameter=diameter, 'emitter_plane': emitter_plane,
planes=planes) 'emitter_tag' : emitter_tag,
'emitter' : emitter,
# Depending on the number of planes above the emitter, the termination may not be the one you wish, 'side' : side,
# we test this and raise an exception in such a case })
clusters.append(cluster)
# Get the termination by finding the kind of one atom located at the topmost z coordinate print("Added cluster {}-side, emitter {}(tag {:d}) in "
termination = cluster[np.argsort(cluster.get_positions()[:, 2])[-1]].symbol "plane #{:d}".format(side, emitter, emitter_tag,
emitter_plane))
# test if the combination of parameters is possible return clusters
assert (termination == 'N' and term_anion) or (termination == 'Al' and not term_anion), (
"This termination isn't compatible with your others parameters, you must change the tag of "
"your emitter, the plane of your emitter or your termination") def compute(clusters, theta=np.arange(-20., 80., 1.), phi=0.):
data = None
return cluster for ic, cluster in enumerate(clusters):
# Retrieve info from cluster object
def create_clusters(side='Al', emitter='Al', diameter=15, planes=6): side = cluster.info['side']
clusters = [] emitter = cluster.info['emitter']
if side == 'Al': plane = cluster.info['emitter_plane']
term_anion = tetra_down = False tag = cluster.info['emitter_tag']
elif side == 'N':
term_anion = tetra_down = True # Set the level and the kinetic energy
if emitter == 'Al':
if emitter == 'Al': level = '2p'
tags = (0, 2) ke = 1407.
level = '2p' elif emitter == 'N':
ke = 1407. level = '1s'
elif emitter == 'N': ke = 1083.
tags = (1, 3)
level = '1s' calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
ke = 1083.
calc.source_parameters.energy = XRaySource.AL_KALPHA
for emitter_tag, emitter_plane in product(tags, range(0, planes)): calc.source_parameters.theta = -35
nplanes = emitter_plane + 2
try: calc.detector_parameters.angular_acceptance = 4.
cluster = AlN_cluster(emitter_tag, emitter_plane, diameter=diameter, planes=nplanes, term_anion=term_anion, calc.detector_parameters.average_sampling = 'medium'
tetra_down=tetra_down)
except AssertionError: calc.calculation_parameters.scattering_order = max(1, min(4, plane))
continue calc.calculation_parameters.path_filtering = 'forward_scattering'
cluster.absorber = get_atom_index(cluster, 0, 0, 0) calc.calculation_parameters.off_cone_events = 1
cluster.info.update({'emitter_plane': emitter_plane, [a.set('forward_angle', 30.) for a in cluster]
'emitter_tag': emitter_tag,
'emitter': emitter, calc.set_atoms(cluster)
'side': side,
'level': level, data = calc.get_theta_scan(level=level, theta=theta, phi=phi,
'ke': ke}) kinetic_energy=ke, data=data)
clusters.append(cluster) dset = data[-1]
dset.title = "\'{}\' side - {}({}) tag #{:d}, plane #{:d}".format(
return clusters side, emitter, level, tag, plane)
def compute_polar_scans(clusters, theta=np.arange(-20., 80., 1.), phi=0., data=DATA): return data
for ic, cluster in enumerate(clusters):
# select the spectroscopy of the calculation and create a new folder for each calculation
side, emitter, tag, plane, level, ke = [cluster.info[k] for k in ('side', 'emitter', 'emitter_tag', def analysis(data):
'emitter_plane', 'level', 'ke')] tmp_data = {}
calc = MSSPEC(spectroscopy='PED', folder='calc{:0>3d}_S{}_E{}_T{:d}_P{:d}'.format(ic, side, emitter, tag, for dset in data:
plane)) info = dset.get_cluster().info
calc.calculation_parameters.scattering_order = max(1, min(4, plane)) side = info['side']
calc.source_parameters.energy = XRaySource.AL_KALPHA emitter = info['emitter']
calc.source_parameters.theta = -35 try:
calc.detector_parameters.angular_acceptance = 4. key = '{}_{}'.format(side, emitter)
calc.detector_parameters.average_sampling = 'medium' tmp_data[key] += dset.cross_section
calc.calculation_parameters.path_filtering = 'forward_scattering' except KeyError:
calc.calculation_parameters.off_cone_events = 1 tmp_data[key] = dset.cross_section.copy()
[a.set('forward_angle', 30.) for a in cluster]
calc.calculation_parameters.vibrational_damping = 'averaged_tl' tmp_data['theta'] = dset.theta.copy()
[a.set('mean_square_vibration', 0.006) for a in cluster] tmp_data['Al_side'] = tmp_data['Al_Al'] / tmp_data['Al_N']
calc.set_atoms(cluster) tmp_data['N_side'] = tmp_data['N_Al'] / tmp_data['N_N']
data = calc.get_theta_scan(level=level, theta=theta, phi=phi, kinetic_energy=ke, data=data) # now add all columns
dset = data[-1] substrate_dset = data.add_dset('Total substrate signal')
dset.title = 'Polar scan {emitter:s}({level:s} tag {tag:d}) in plane #{plane:d}'.format(emitter=emitter, substrate_dset.add_columns(**tmp_data)
level=level, tag=tag,
plane=plane) view = substrate_dset.add_view('Ratios',
for name, value in cluster.info.items(): title=r'Al(2p)/N(1s) ratios on both polar '
dset.add_parameter(group='AlnTuto', name=name, value=str(value), unit="") r'sides of AlN in the (10$\bar{1}$0) '
#data.save('all_polar_scans.hdf5', append=True) r'azimuthal plane',
data.save('all_polar_scans.hdf5') xlabel=r'$\Theta (\degree$)',
ylabel='Intenisty ratio')
def analysis(filename='all_polar_scans.hdf5'): view.select('theta', 'Al_side', legend='Al side',
data=Data.load(filename) where="theta >= 0 and theta <=70")
# create datasets to store the sum of all emitter view.select('theta', 'N_side', legend='N side',
tmp_data = {} where="theta >= 0 and theta <=70")
for dset in data: view.set_plot_options(autoscale=True)
# retrieve some info
side = dset.get_parameter(group='AlnTuto', name='side')['value'] return data
emitter = dset.get_parameter(group='AlnTuto', name='emitter')['value']
try:
key = '{}_{}'.format(side, emitter) clusters = create_clusters()
tmp_data[key] += dset.cross_section data = compute(clusters)
except KeyError: data = analysis(data)
tmp_data[key] = dset.cross_section.copy() data.view()
# get the index of theta = 0;
it0 = np.where(dset.theta == 0)[0][0]
for key, cs in tmp_data.items():
tmp_data[key + '_norm'] = cs / cs[it0]
tmp_data['Al_side'] = tmp_data['Al_Al_norm'] / tmp_data['Al_N_norm']
tmp_data['N_side'] = tmp_data['N_Al_norm'] / tmp_data['N_N_norm']
# now add all columns
substrate_dset = data.add_dset('Total substrate signal')
substrate_dset.add_columns(theta=dset.theta.copy())
substrate_dset.add_columns(**tmp_data)
view = substrate_dset.add_view('Al side',
title=r'AlN Polar scan in the (10$\bar{1}$0) azimuthal plane - Al side polarity',
xlabel=r'$\Theta (\degree$)',
ylabel='Signal (a.u.)')
view.select('theta', 'Al_Al_norm', legend='Al 2p')
view.select('theta', 'Al_N_norm', legend='N 1s')
view.set_plot_options(autoscale=True)
view = substrate_dset.add_view('N side',
title=r'AlN Polar scan in the (10$\bar{1}$0) azimuthal plane - N side polarity',
xlabel=r'$\Theta (\degree$)',
ylabel='Signal (a.u.)')
view.select('theta', 'N_Al_norm', legend='Al 2p')
view.select('theta', 'N_N_norm', legend='N 1s')
view.set_plot_options(autoscale=True)
view = substrate_dset.add_view('Ratios',
title=r'Al(2p)/N(1s) ratios on both polar sides of AlN in the (10$\bar{1}$0) '
r'azimuthal plane',
xlabel=r'$\Theta (\degree$)',
ylabel='Intenisty ratio')
view.select('theta', 'Al_side', legend='Al side', where="theta >= 0 and theta <=70")
view.select('theta', 'N_side', legend='N side', where="theta >= 0 and theta <=70")
view.set_plot_options(autoscale=True)
data.save('analysis.hdf5')
data.view()
DIAMETER = 10
PLANES = 4
clusters = create_clusters(side='Al', emitter='Al', diameter=DIAMETER, planes=PLANES) + \
create_clusters(side='Al', emitter='N', diameter=DIAMETER, planes=PLANES) + \
create_clusters(side='N', emitter='Al', diameter=DIAMETER, planes=PLANES) + \
create_clusters(side='N', emitter='N', diameter=DIAMETER, planes=PLANES)
compute_polar_scans(clusters, phi=0.)
analysis()

View File

@ -1,54 +1,25 @@
# -*- encoding: utf-8 -*- # coding: utf8
# vim: set fdm=indent ts=4 sw=4 sts=4 et ai tw=80 cc=+0 mouse=a nu : #
from msspec.calculator import MSSPEC
from msspec.calculator import MSSPEC, XRaySource from ase.build import fcc111, add_adsorbate
from msspec.utils import * import numpy as np
from ase.build import fcc111, add_adsorbate data = None
from ase.visualize import view all_z = np.arange(1.10, 1.65, 0.05)
from msspec.iodata import cols2matrix for zi, z0 in enumerate(all_z):
# construct the cluster
from matplotlib import pyplot as plt cluster = fcc111('Rh', size = (2,2,1))
import numpy as np cluster.pop(3)
import sys add_adsorbate(cluster, 'O', z0, position = 'fcc')
cluster.absorber = len(cluster) - 1
data = None
all_z = np.arange(1.10, 1.50, 0.02) # Define a calculator
all_z=(1.1,) calc = MSSPEC(spectroscopy='PED', algorithm='inversion')
for zi, z0 in enumerate(all_z): calc.set_atoms(cluster)
# construct the cluster
cluster = fcc111('Rh', size = (2,2,1)) # Compute
add_adsorbate(cluster, 'O', z0, position = 'fcc') data = calc.get_theta_phi_scan(level='1s', kinetic_energy=723, data=data)
cluster.pop(3) dset = data[-1]
#cluster.rotate('z',np.pi/3.) dset.title = "{:d}) z = {:.2f} angstroms".format(zi, z0)
#view(cluster)
data.view()
cluster.absorber = len(cluster) - 1
calc = MSSPEC(spectroscopy = 'PED', folder = './RhO_z')
calc.set_atoms(cluster)
calc.calculation_parameters.scattering_order = 3
calc.calculation_parameters.RA_cutoff = 1
calc.source_parameters.energy = XRaySource.AL_KALPHA
# compute
level = '1s'
ke = 723.
data = calc.get_theta_phi_scan(level=level, kinetic_energy=ke, data=data)
# OPTIONAL, this will create an image of the data that you can combine
# in an animated gif
dset = data[-1]
theta, phi, Xsec = cols2matrix(dset.theta, dset.phi, dset.cross_section)
X, Y = np.meshgrid(np.radians(phi), 2*np.tan(np.radians(theta/2.)))
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
im = ax.pcolormesh(X, Y, Xsec)
theta_ticks = np.arange(0, 91, 15)
plt.yticks(2 * np.tan(np.radians(theta_ticks/2.)), theta_ticks)
plt.title(r"$z_0 = {:.2f} \AA$".format(z0))
plt.savefig('image{:03d}.png'.format(zi))
data.view()

View File

@ -1,31 +1,17 @@
# -*- encoding: utf-8 -*- # coding: utf8
# vim: set fdm=indent ts=4 sw=4 sts=4 et ai tw=80 cc=+0 mouse=a nu : #
from msspec.calculator import MSSPEC, XRaySource
from msspec.utils import *
from msspec.calculator import MSSPEC
from ase import Atoms from ase import Atoms
import numpy as np # Create an atomic chain O-Rh
cluster = Atoms(['O', 'Rh'], positions = [(0,0,0), (0,0,4.)])
# Defining global variables # Create the calculator
a0 = 6.0 calc = MSSPEC(spectroscopy = 'PED')
symbols = ('Rh', 'O') calc.set_atoms(cluster)
ke = 723. cluster.absorber = 0
level = '1s'
data = None # compute
for symbol in symbols: data = calc.get_scattering_factors(level='1s', kinetic_energy=723)
cluster = Atoms(symbol*2, positions = [(0,0,0), (0,0,a0)])
[a.set('mt_radius', 1.5) for a in cluster]
# Create the calculator
calc = MSSPEC(spectroscopy = 'PED')
calc.source_parameters.energy = XRaySource.AL_KALPHA
calc.set_atoms(cluster)
cluster.absorber = 0
# compute
data = calc.get_scattering_factors(level=level, kinetic_energy=ke, data=data)
data.view() data.view()

View File

@ -82,13 +82,13 @@ Here is the script for the computation. (:download:`download <RhO.py>`)
.. literalinclude:: RhO.py .. literalinclude:: RhO.py
:linenos: :linenos:
.. note:: .. .. note::
After runing this script, you will get 20 images in your folder. You can merge them in one animated gif image .. After runing this script, you will get 20 images in your folder. You can merge them in one animated gif image
like this: .. like this:
..
.. code-block:: bash .. .. code-block:: bash
..
convert -delay 50 -loop 0 image*.png animation.gif .. convert -delay 50 -loop 0 image*.png animation.gif
.. seealso:: .. seealso::

View File

@ -1,7 +1,7 @@
# coding: utf-8 # coding: utf8
from msspec.calculator import MSSPEC from msspec.calculator import MSSPEC
from msspec.utils import * from msspec.utils import hemispherical_cluster, get_atom_index
from ase.build import bulk from ase.build import bulk
from ase.visualize import view from ase.visualize import view
@ -9,20 +9,15 @@ from ase.visualize import view
a0 = 3.6 # The lattice parameter in angstroms a0 = 3.6 # The lattice parameter in angstroms
# Create the copper cubic cell # Create the copper cubic cell
cluster = bulk('Cu', a=a0, cubic=True) copper = bulk('Cu', a=a0, cubic=True)
# Repeat the cell many times along x, y and z cluster = hemispherical_cluster(copper, planes=3, emitter_plane=2)
cluster = cluster.repeat((4, 4, 4))
# Put the center of the structure at the origin
center_cluster(cluster)
# Keep atoms inside a given radius
cluster = cut_sphere(cluster, radius=a0 + .01)
# Keep only atoms below the plane z <= 0
cluster = cut_plane(cluster, z=0.1)
# Set the absorber (the deepest atom centered in the xy-plane) # Set the absorber (the deepest atom centered in the xy-plane)
cluster.absorber = get_atom_index(cluster, 0, 0, -a0) cluster.absorber = get_atom_index(cluster, 0, 0, 0)
# Create a calculator for the PhotoElectron Diffration # Create a calculator for the PhotoElectron Diffration
calc = MSSPEC(spectroscopy='PED') calc = MSSPEC(spectroscopy='PED')
# Set the cluster to use for the calculation # Set the cluster to use for the calculation
calc.set_atoms(cluster) calc.set_atoms(cluster)
@ -31,4 +26,6 @@ data = calc.get_theta_scan(level='2p3/2')
# Show the results # Show the results
data.view() data.view()
#calc.shutdown()
# Clean temporary files
calc.shutdown()

View File

@ -16,7 +16,7 @@ Begin by typing:
:linenos: :linenos:
:lineno-start: 1 :lineno-start: 1
# coding: utf-8 # coding: utf8
from msspec.calculator import MSSPEC from msspec.calculator import MSSPEC
from msspec.utils import * from msspec.utils import *
@ -45,27 +45,37 @@ This is the job of the *ase* module, so load the module
from ase.build import bulk from ase.build import bulk
from ase.visualize import view from ase.visualize import view
a0 = 3.6 a0 = 3.6 # The lattice parameter in angstroms
cluster = bulk('Cu', a = a0, cubic = True)
# Create the copper cubic cell
copper = bulk('Cu', a=a0, cubic=True)
view(cluster) view(cluster)
In line 6 we load the :py:func:`bulk` function to create our atomic object and, In line 6 we load the :py:func:`bulk` function to create our atomic object and,
in line 7, we load the :py:func:`view` function to actually view our cluster. in line 7, we load the :py:func:`view` function to actually view our cluster.
The creation of the cluster is done line 10. The :py:func:`bulk` needs one The creation of the cluster starts on line 12. We create first the copper cubic
argument which are the chemical species ('Cu' in our example). We also pass 2 cell with the The :py:func:`bulk` function. It needs one argument which are the
keyword (optional) arguments here: chemical species ('Cu' in our example). We also pass 2 keyword (optional) arguments
here:
* The lattice parameter *a* in units of angströms. * The lattice parameter *a* in units of angströms.
* The *cubic* keyword, to obtain a cubic cell rather than the fully * The *cubic* keyword, to obtain a cubic cell rather than the fully
reduced one which is not cubic reduced one which is not cubic
From now on, you can save your script as 'Cu.py' and open a terminal window in From now on, you can save your script as 'Cu.py' and open a terminal window in
the same directory as this file. Launch your script using python: the same directory as this file. Launch your script using 'python' or 'msspec -p'
(depending on your installation):
.. code-block:: bash .. code-block:: bash
python2 Cu.py python Cu.py
or
.. code-block:: bash
msspec -p Cu.py
and a graphical window (the ase-gui) should open with a cubic cell of copper and a graphical window (the ase-gui) should open with a cubic cell of copper
like this one: like this one:
@ -80,34 +90,38 @@ like this one:
Obviously, multiple scattering calculations need more atoms to be accurate. Due Obviously, multiple scattering calculations need more atoms to be accurate. Due
to the forward focusing effect in photo-electron diffraction, the best suited to the forward focusing effect in photo-electron diffraction, the best suited
geometry for the cluster is hemispherical. Obtaining such a cluster is a geometry for the cluster is hemispherical. Obtaining such a cluster is a
straightforward process: straightforward process thanks to the :py:func:`utils.hemispherical_cluster` function.
This function will basically create a cluster based on a pattern (the cubic copper
1. Repeat the previous cell in all 3 directions cell here).
2. center the structure
3. Keep only atoms within a given radius from center
4. Keep only atoms within one halh of the sphere.
Modify your script like this and run it again. Modify your script like this and run it again.
.. literalinclude:: Cu_simple.py .. literalinclude:: Cu.py
:linenos: :linenos:
:lineno-start: 1 :lineno-start: 1
:lines: 1-21 :lines: 1-13
Don't forget to add the line to view the cluster at the end of the script and run Don't forget to add the line to view the cluster at the end of the script and run
the script again. the script again. The :py:func:`hemispherical_cluster` works in 3 simple steps:
#. Repeat the given *pattern* in all 3 directions
#. Center this new set of atoms and cut a sphere from the center
#. Remove the upper half of the created 'sphere'.
To get more information about how to use this function, have a look at the :ref:`hemispherical_cluster_faq` section in the :ref:`faq`.
.. figure:: Cu_fig2.png .. figure:: Cu_fig2.png
:align: center :align: center
:width: 60% :width: 60%
Figure 2. The different steps to output a cluster. Figure 2. The different steps to output a cluster.
a) After repeat, b) after cut_sphere, c) after cut_plane a) After repeat, b) after cutting a sphere, c) final cluster
Once you a cluster is built the next step is to define which atom in the cluster Once your cluster is built the next step is to define which atom in the cluster
will absorbe the light. This atom is called the *absorber*. will absorb the light. This atom is called the *absorber* (or the *emitter* since
it emits the photoelectron).
To specify which atom is the absorber, you need to understand that the cluster To specify which atom is the absorber, you need to understand that the cluster
object is like a list of atoms. Each member of this list is an atom with its object is like a list of atoms. Each member of this list is an atom with its
@ -115,7 +129,7 @@ own position. You need to locate the index of the atom in the list that you want
it to be the absorber. Then, put that number in the *cluster.absorber* attribute it to be the absorber. Then, put that number in the *cluster.absorber* attribute
For example, suppose that you want the first atom of the list to be the For example, suppose that you want the first atom of the list to be the
absorber. You should write: absorber. You would write:
.. code-block:: python .. code-block:: python
@ -123,24 +137,27 @@ absorber. You should write:
To find what is the index of the atom you'd like to be the absorber, you can To find what is the index of the atom you'd like to be the absorber, you can
either get it while you are visualizing the structure within the ase-gui either get it while you are visualizing the structure within the ase-gui
program. Or, you can use :py:func:`get_atom_index` function. This function takes program (select an atom with the left mouse button and look at its index in the
4 arguments: the cluster to look the index for, and the x, y and z coordinates. status line). Or, you can use :py:func:`utils.get_atom_index` function. This function
takes 4 arguments: the cluster to look the index for, and the x, y and z coordinates.
It will return the index of the closest atom to these coordinates. In our It will return the index of the closest atom to these coordinates. In our
example, to get the deepest atom centered in the xy-plane, we write: example, as we used the :py:func:`utils.hemispherical_cluster` function to create our
cluster, the *emitter* (*absorber*) is always located at the origin, so defining it
is straightforward:
.. literalinclude:: Cu_simple.py .. literalinclude:: Cu.py
:linenos: :linenos:
:lineno-start: 22 :lineno-start: 15
:lines: 22-23 :lines: 15-16
That's all for the cluster part. We now need to create a calculator for that That's all for the cluster part. We now need to create a calculator for that
object. This is a 2 lines procedure: object. This is a 2 lines procedure:
.. literalinclude:: Cu_simple.py .. literalinclude:: Cu.py
:linenos: :linenos:
:lineno-start: 24 :lineno-start: 18
:lines: 24-28 :lines: 18-22
When creating a new calculator, you must choose the kind of spectroscopy you When creating a new calculator, you must choose the kind of spectroscopy you
will work with. In this example we choose 'PED' for *PhotoElectron Diffraction*. will work with. In this example we choose 'PED' for *PhotoElectron Diffraction*.
@ -153,14 +170,14 @@ Other types of spectroscopies are:
Now that everything is ready you can actually perform a calculation. The 2 lines Now that everything is ready you can actually perform a calculation. The lines
below will produce a polar scan of the Cu(2p3/2) level with default parameters, below will produce a polar scan of the Cu(2p3/2) level with default parameters,
store the results in the data object and display it in a graphical window. store the results in the data object and display it in a graphical window.
.. literalinclude:: Cu_simple.py .. literalinclude:: Cu.py
:linenos: :linenos:
:lineno-start: 29 :lineno-start: 24
:lines: 29-33 :lines: 24-28
running this script will produce the following output running this script will produce the following output
@ -177,7 +194,6 @@ By default, the program computes for :math:`\theta` angles in the -70°..+70°
range. This can be changed by using the *angles* keyword. range. This can be changed by using the *angles* keyword.
.. code-block:: python .. code-block:: python
:linenos:
#For a polar scan between 0° and 60° with 100 points #For a polar scan between 0° and 60° with 100 points
import numpy as np import numpy as np
@ -201,7 +217,6 @@ work function of the sample, arbitrary set to 4.5 eV.
Of course, you can choose any kinetic energy you'd like: Of course, you can choose any kinetic energy you'd like:
.. code-block:: python .. code-block:: python
:linenos:
# To set the kinetic energy... # To set the kinetic energy...
data = calc.get_theta_scan(level = '2p3/2', kinetic_energy = 300) data = calc.get_theta_scan(level = '2p3/2', kinetic_energy = 300)
@ -209,9 +224,9 @@ Of course, you can choose any kinetic energy you'd like:
Below is the full code of this example. You can download it :download:`here Below is the full code of this example. You can download it :download:`here
<Cu_simple.py>` <Cu.py>`
.. literalinclude:: Cu_simple.py .. literalinclude:: Cu.py
:linenos: :linenos:
.. seealso:: .. seealso::

View File

@ -1,77 +1,78 @@
# coding: utf-8 # coding: utf-8
# import all we need and start by msspec # import all we need and start by msspec
from msspec.calculator import MSSPEC from msspec.calculator import MSSPEC
# we will build a simple atomic chain # we will build a simple atomic chain
from ase import Atom, Atoms from ase import Atom, Atoms
# we need some numpy functions # we need some numpy functions
import numpy as np import numpy as np
symbol = 'Ni' # The kind of atom for the chain symbol = 'Ni' # The kind of atom for the chain
orders = (1, 5) # We will run the calculation for single scattering orders = (1, 5) # We will run the calculation for single scattering
# and multiple scattering (5th diffusion order) # and multiple scattering (5th diffusion order)
chain_lengths = (2,3,5) # We will run the calculation for differnt lengths chain_lengths = (2,3,5) # We will run the calculation for differnt lengths
# of the atomic chain # of the atomic chain
a = 3.5 # The distance bewteen 2 atoms a = 3.499 * np.sqrt(2)/2 # The distance bewteen 2 atoms
# Define an empty variable to store all the results # Define an empty variable to store all the results
all_data = None all_data = None
# 2 for nested loops over the chain length and the order of diffusion # 2 for nested loops over the chain length and the order of diffusion
for chain_length in chain_lengths: for chain_length in chain_lengths:
for order in orders: for order in orders:
# We build the atomic chain by # We build the atomic chain by
# 1- stacking each atom one by one along the z axis # 1- stacking each atom one by one along the z axis
chain = Atoms([Atom(symbol, position = (0., 0., i*a)) for i in chain = Atoms([Atom(symbol, position = (0., 0., i*a)) for i in
range(chain_length)]) range(chain_length)])
# 2- rotating the chain by 45 degrees with respect to the y axis # 2- rotating the chain by 45 degrees with respect to the y axis
chain.rotate('y', np.radians(45.)) #chain.rotate('y', np.radians(45.))
# 3- setting a custom Muffin-tin radius of 1.5 angstroms for all chain.rotate(45., 'y')
# atoms (needed if you want to enlarge the distance between # 3- setting a custom Muffin-tin radius of 1.5 angstroms for all
# the atoms while keeping the radius constant) # atoms (needed if you want to enlarge the distance between
[atom.set('mt_radius', 1.5) for atom in chain] # the atoms while keeping the radius constant)
# 4- defining the absorber to be the first atom in the chain at #[atom.set('mt_radius', 1.5) for atom in chain]
# x = y = z = 0 # 4- defining the absorber to be the first atom in the chain at
chain.absorber = 0 # x = y = z = 0
chain.absorber = 0
# We define a new PED calculator
calc = MSSPEC(spectroscopy = 'PED') # We define a new PED calculator
calc.set_atoms(chain) calc = MSSPEC(spectroscopy = 'PED')
# Here is how to tweak the scattering order calc.set_atoms(chain)
calc.calculation_parameters.scattering_order = order # Here is how to tweak the scattering order
# This line below is where we actually run the calculation calc.calculation_parameters.scattering_order = order
all_data = calc.get_theta_scan(level='3s', kinetic_energy=1000., # This line below is where we actually run the calculation
theta=np.arange(0., 80.), data=all_data) all_data = calc.get_theta_scan(level='3s', #kinetic_energy=1000.,
theta=np.arange(0., 80.), data=all_data)
# OPTIONAL, to improve the display of the data we will change the dataset
# default title as well as the plot title # OPTIONAL, to improve the display of the data we will change the dataset
t = "order {:d}, n = {:d}".format(order, chain_length) # A useful title # default title as well as the plot title
dset = all_data[-1] # get the last dataset t = "order {:d}, n = {:d}".format(order, chain_length) # A useful title
dset.title = t # change its title dset = all_data[-1] # get the last dataset
# get its last view (there is only one defined for each dataset) dset.title = t # change its title
v = dset.views()[-1] # get its last view (there is only one defined for each dataset)
v.set_plot_options(title=t) # change the title of the figure v = dset.views()[-1]
v.set_plot_options(title=t) # change the title of the figure
# OPTIONAL, set the same scale for all plots
# 1. iterate over all computed cross_sections to find the absolute minimum and # OPTIONAL, set the same scale for all plots
# maximum of the data # 1. iterate over all computed cross_sections to find the absolute minimum and
min_cs = max_cs = 0 # maximum of the data
for dset in all_data: min_cs = max_cs = 0
min_cs = min(min_cs, np.min(dset.cross_section)) for dset in all_data:
max_cs = max(max_cs, np.max(dset.cross_section)) min_cs = min(min_cs, np.min(dset.cross_section))
max_cs = max(max_cs, np.max(dset.cross_section))
# 2. for each view in each dataset, change the scale accordingly
for dset in all_data: # 2. for each view in each dataset, change the scale accordingly
v = dset.views()[-1] for dset in all_data:
v.set_plot_options(ylim=[min_cs, max_cs]) v = dset.views()[-1]
v.set_plot_options(ylim=[min_cs, max_cs])
# Pop up the graphical window
all_data.view() # Pop up the graphical window
# You can end your script with the line below to remove the temporary all_data.view()
# folder needed for the calculation # You can end your script with the line below to remove the temporary
calc.shutdown() # folder needed for the calculation
calc.shutdown()

View File

@ -30,7 +30,7 @@ trajectory for this electron which in turn lowers the signal.
:align: center :align: center
:width: 80% :width: 80%
Figure 4. Polar scan of a Ni chain of 2-5 atoms for single and mutliple (5th order) Figure 1. Polar scan of a Ni chain of 2-5 atoms for single and mutliple (5th order)
scattering. scattering.

View File

@ -1,153 +1,129 @@
# coding: utf-8 # coding: utf8
from msspec.calculator import MSSPEC, XRaySource from ase.build import bulk
from msspec.utils import * import numpy as np
from msspec.iodata import Data from msspec.calculator import MSSPEC, XRaySource
from ase.build import bulk from msspec.utils import hemispherical_cluster, get_atom_index
import numpy as np
import sys def create_clusters(nplanes=3):
copper = bulk('Cu', a=3.6, cubic=True)
a0 = 3.6 # The lattice parameter in angstroms clusters = []
phi = np.arange(0, 100) # An array of phi angles for emitter_plane in range(nplanes):
all_T = np.arange(300, 1000, 100) # All temperatures used for the calculation cluster = hemispherical_cluster(copper,
all_theta = np.array([45, 83]) # 2 polar angles, 83° is grazing detection emitter_plane=emitter_plane,
eps = 0.01 # a useful small value planes=emitter_plane+2,
shape='cylindrical')
DATA_FNAME = 'all_data.hdf5' # Where to store all the data cluster.absorber = get_atom_index(cluster, 0, 0, 0)
ANALYSIS_FNAME = 'analysis.hdf5' cluster.info.update({
'emitter_plane': emitter_plane,
})
def compute(filename): clusters.append(cluster)
"""Will compute a phi scan for an emitter in the first, second and third plane return clusters
of a copper substrate for various polar angles and temperatures.
In a second step (outside this function), intensities from all these emitters def compute(clusters, all_theta=[45., 83.],
are added to get the signal of a substrate.""" all_T=np.arange(300., 1000., 400.)):
calc = MSSPEC(spectroscopy='PED') data = None
calc.source_parameters.energy = XRaySource.AL_KALPHA for ic, cluster in enumerate(clusters):
calc.muffintin_parameters.interstitial_potential = 14.1 # Retrieve info from cluster object
plane = cluster.info['emitter_plane']
calc.calculation_parameters.vibrational_damping = 'averaged_tl'
calc.calculation_parameters.use_debye_model = True calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
calc.calculation_parameters.debye_temperature = 343 calc.source_parameters.energy = XRaySource.AL_KALPHA
calc.calculation_parameters.vibration_scaling = 1.2 calc.muffintin_parameters.interstitial_potential = 14.1
calc.detector_parameters.average_sampling = 'high' calc.calculation_parameters.vibrational_damping = 'averaged_tl'
calc.detector_parameters.angular_acceptance = 5.7 calc.calculation_parameters.use_debye_model = True
calc.calculation_parameters.debye_temperature = 343
filters = ['forward_scattering', 'backward_scattering'] calc.calculation_parameters.vibration_scaling = 1.2
calc.calculation_parameters.path_filtering = filters
calc.detector_parameters.average_sampling = 'high'
calc.calculation_parameters.RA_cutoff = 3 calc.detector_parameters.angular_acceptance = 5.7
# You can also choose a real potential and manually define the for atom in cluster:
# electron mean free path atom.set('forward_angle', 30)
# atom.set('backward_angle', 30)
# calc.tmatrix_parameters.exchange_correlation = 'hedin_lundqvist_real' filters = ['forward_scattering', 'backward_scattering']
# calc.calculation_parameters.mean_free_path = 10. calc.calculation_parameters.path_filtering = filters
data = None # init an empty data object calc.calculation_parameters.RA_cutoff = 2
for temperature in all_T:
for plane in range(3): for T in all_T:
# We create a cylindrical cluster here with one plane below the emitter for theta in all_theta:
# and 0, 1 or to planes above the emitter calc.calculation_parameters.temperature = T
cluster = bulk('Cu', a=a0, cubic=True) calc.calculation_parameters.scattering_order = min(1 + plane, 3)
cluster = cluster.repeat((20, 20, 8)) calc.set_atoms(cluster)
center_cluster(cluster) data = calc.get_phi_scan(level='2p3/2', theta=theta,
cluster = cut_cylinder(cluster, radius=1.5 * a0 + eps) phi=np.linspace(0, 100),
cluster = cut_plane(cluster, z=-( a0/2 + eps)) kinetic_energy=560, data=data)
cluster = cut_plane(cluster, z=(plane) * a0 / 2 + eps) dset = data[-1]
cluster.absorber = get_atom_index(cluster, 0, 0, 0) dset.title = "plane #{:d}, T={:f}K, theta={:f}°".format(plane,
T,
calc.calculation_parameters.temperature = temperature theta)
# the scattering order depends on the number of planes above
# the emitter to speed up calculations dset.add_parameter(group='misc', name='plane', value=plane, unit='')
calc.calculation_parameters.scattering_order = 1 + plane dset.add_parameter(group='misc', name='T', value=T, unit='')
dset.add_parameter(group='misc', name='theta', value=theta, unit='')
calc.set_atoms(cluster) return data
# Here starts the calculation
data = calc.get_phi_scan(level='2p3/2', theta=all_theta, phi=phi,
kinetic_energy=560, data=data) def analysis(data):
all_plane = []
data.save(filename) all_T = []
all_theta = []
def process_data(datafile, outputfile): for dset in data:
"""Will create another Data file with some phi-scans corresponding to 3 plane = dset.get_parameter('misc', 'plane')['value']
planes at different temperatures and the anisotropy curve for 45° and T = dset.get_parameter('misc', 'T')['value']
grazing detection. theta = dset.get_parameter('misc', 'theta')['value']
""" cs = dset.cross_section.copy()
def get_signal(datafile, T=300, theta=45): phi = dset.phi.copy()
data = Data.load(datafile)
total = None if plane not in all_plane: all_plane.append(plane)
for dset in data: if T not in all_T: all_T.append(T)
p = {_['group'] + '.' + _['name']: _['value'] for _ in dset.parameters()} if theta not in all_theta: all_theta.append(theta)
temperature = np.float(p['CalculationParameters.temperature'])
if temperature != T: continue def get_anisotropy(theta, T):
i = np.where(dset.plane == -1) cs = None
j = np.where(dset.theta[i] == theta) for dset in data:
signal = dset.cross_section[i][j] try:
try: _T = dset.get_parameter('misc', 'T')['value']
total += signal _theta = dset.get_parameter('misc', 'theta')['value']
except: _cs = dset.cross_section.copy()
total = signal phi = dset.phi.copy()
phi = dset.phi[i][j] except:
return phi, total continue
if _theta == theta and _T == T:
analysis = Data('Temperature tutorial') try:
scans_dset = analysis.add_dset('Phi scans') cs += _cs
scans_view = scans_dset.add_view('Figure 1', except:
title=r'Cu(2p) Azimuthal scan for $\theta = 83\degree$', cs = _cs
xlabel=r'$\Phi (\degree$)', Imax = np.max(cs)
ylabel='Signal (a.u.)') Imin = np.min(cs)
anisotropy_dset = analysis.add_dset('Anisotropies') return (Imax - Imin)/Imax
anisotropy_view = anisotropy_dset.add_view('Figure 2',
title='Relative anisotropies for Cu(2p)', # create a substrate dataset for each T and theta
marker='o', anisotropy_dset = data.add_dset("all")
xlabel='T (K)', anisotropy_view = anisotropy_dset.add_view('Anisotropies',
ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300} / I_{max}(300)} (\%)$') title='Relative anisotropies for Cu(2p)',
for theta in all_theta: marker='o',
for T in all_T: xlabel='T (K)',
PHI, SIGNAL = get_signal(datafile, T=T, theta=theta) ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300}'
for phi, signal in zip(PHI, SIGNAL): r'/ I_{max}(300)} (\%)$')
scans_dset.add_row(phi=phi, signal=signal, theta=theta, temperature=T)
for theta in all_theta:
middleT = all_T[np.abs(all_T - np.mean(all_T)).argmin()] for T in all_T:
if theta == 83 and T in [np.min(all_T), middleT, np.max(all_T)]: A = get_anisotropy(theta, T)
scans_view.select('phi', 'signal', A0 = get_anisotropy(theta, np.min(all_T))
where='temperature == {:f} and theta == {:f}'.format(T, theta),
legend='{:.0f} K'.format(T)) anisotropy_dset.add_row(temperature=T, theta=theta, anisotropy=A/A0)
PHI, SIGNAL0 = get_signal(datafile, T=np.min(all_T), theta=theta) anisotropy_view.select('temperature', 'anisotropy',
Imax = np.max(SIGNAL) where='theta == {:f}'.format(theta),
Imax0 = np.max(SIGNAL0) legend=r'$\theta = {:.0f} \degree$'.format(theta))
dI = Imax - np.min(SIGNAL) return data
dI0 = Imax0 - np.min(SIGNAL0)
ani = (dI / Imax) / (dI0 / Imax0)
anisotropy_dset.add_row(temperature=T, anisotropy=ani, theta=theta) clusters = create_clusters()
data = compute(clusters)
anisotropy_view.select('temperature', 'anisotropy', data = analysis(data)
where='theta == {:f}'.format(theta), data.view()
legend=r'$\theta = {:.0f} \degree$'.format(theta))
analysis.save(outputfile)
# A convenient way to run the script, just specify one or more of these calc, analyse or
# view keywords as arguments
# ... to calculate all the data, analyse the data and view the results, run
# python Cu_temperature.py calc analyse view
# ... to just view the results, simply run
# python Cu_temperature.py view
if 'calc' in sys.argv:
compute(DATA_FNAME)
if 'analyse' in sys.argv:
process_data(DATA_FNAME, ANALYSIS_FNAME)
if 'view' in sys.argv:
data = Data.load(ANALYSIS_FNAME)
data.view()

View File

@ -12,7 +12,7 @@ if ! [ -d "$VENV_PATH" ]; then
fi fi
launch_script() { launch_script() {
. "$VENV_PATH/bin/activate" && python $@ . "$VENV_PATH/bin/activate" && python "$@"
} }
show_help () { show_help () {

View File

@ -747,15 +747,30 @@ class _PED(_MSCALCULATOR):
proto_index = i+1 proto_index = i+1
title = 'Scattering factor at {:.3f} eV'.format(kinetic_energy) title = 'Scattering factor at {:.3f} eV'.format(kinetic_energy)
mini = min(map(np.min, [dset.sf_real, dset.sf_imag, dset.sf_module]))
maxi = max(map(np.max, [dset.sf_real, dset.sf_imag, dset.sf_module]))
view = dset.add_view("Proto. atom #{:d}".format(proto_index), view = dset.add_view("Proto. atom #{:d}".format(proto_index),
title=title, projection='polar') title=title, projection='polar',
ylim=[mini, maxi])
where = "proto_index=={:d}".format(proto_index) where = "proto_index=={:d}".format(proto_index)
view.select('theta', 'sf_module', where=where, view.select('theta', 'sf_module', where=where,
legend=r'$|f(\theta)|$') legend=r'$|f(\theta)|$')
view.select('theta', 'sf_real', where=where, view.select('theta', 'sf_real', where=where,
legend=r'$\Im(f(\theta))$')
view.select('theta', 'sf_imag', where=where,
legend=r'$\Re(f(\theta))$') legend=r'$\Re(f(\theta))$')
view.select('theta', 'sf_imag', where=where,
legend=r'$\Im(f(\theta))$')
if scan_type == 'energy':
absorber_symbol = self.atoms[self.atoms.absorber].symbol
title = (r'Energy scan of {}({}) at $\theta$={:.2f}$\degree$ and '
'$\phi$={:.2f}$\degree$').format(
absorber_symbol, level, theta, phi)
xlabel = r'Photoelectron kinetic energy (eV)'
ylabel = r'Signal (a. u.)'
view = dset.add_view("EnergyScan".format(ke), title=title,
xlabel=xlabel, ylabel=ylabel)
view.select('energy', 'cross_section')
# save the cluster # save the cluster
#clusbuf = StringIO() #clusbuf = StringIO()
@ -922,6 +937,27 @@ class _PED(_MSCALCULATOR):
malloc={'NPH_M': 8000}) malloc={'NPH_M': 8000})
return data return data
def get_energy_scan(self, phi=0, theta=0,
level=None, kinetic_energy=None, data=None):
"""Computes an energy scan of the emitted photoelectrons.
:param phi: All the values of the azimuthal angle to be computed. See
:ref:`scanparameters-phi`.
:param theta: The polar angle in degrees. See
:ref:`scanparameters-theta`.
:param level: The electronic level. See :ref:`pedparameters-level`.
:param kinetic_energy: see :ref:`scanparameters-kinetic_energy`.
:param data: a :py:class:`iodata.Data` object to append the results to
or None.
:returns: The modified :py:class:`iodata.Data` object passed as an
argument or a new :py:class:`iodata.Data` object.
"""
data = self._get_scan(scan_type='energy', level=level, theta=theta,
phi=phi, kinetic_energy=kinetic_energy, data=data)
return data
class _EIG(_MSCALCULATOR): class _EIG(_MSCALCULATOR):
""" """

View File

@ -12,7 +12,6 @@ import pandas as pd
import time import time
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -236,7 +235,22 @@ class Looper:
df = pd.DataFrame(dfdata, columns=columns) df = pd.DataFrame(dfdata, columns=columns)
self.data = df self.data = df
return df
#return df
# return a list of [x0, y0, x1, y1,...xn, yn] and a list
# of corresponding dict of parameters {'keyA': [val0,...valn],
# 'keyB': [val0,...valn], ...}
all_xy = []
for irow, row in df.iterrows():
all_xy.append(row.output[0])
all_xy.append(row.output[1])
parameters = df.to_dict()
parameters.pop('output')
return all_xy, parameters
@ -282,7 +296,7 @@ if __name__ == "__main__":
looper = Looper() looper = Looper()
looper.pipeline = bar looper.pipeline = bar
data = looper.run(emitter, emitter_plane, uij, theta, levels, ncpu=1, data = looper.run(emitter, emitter_plane, uij, theta, levels, ncpu=4,
passindex=True) passindex=True)
print(data)
print(data[data.emitter_plane.eq(0)].theta.unique()) #print(data[data.emitter_plane.eq(0)].theta.unique())

View File

@ -853,8 +853,8 @@ class MuffintinParameters(BaseParameters):
def __init__(self, phagen_parameters, spec_parameters): def __init__(self, phagen_parameters, spec_parameters):
parameters = ( parameters = (
Parameter('charge_relaxation', types=bool, default=True, doc=""" Parameter('charge_relaxation', types=bool, default=True, doc="""
Used to specify wether the charge density of the photoabsorbing atom, which is used Used to specify whether the charge density of the photoabsorbing atom, which is used
to construct the potential, is allowaed to relax around the core hole or not. to construct the potential, is allowed to relax around the core hole or not.
"""), """),
Parameter('ionicity', types=dict, default={}, doc=""" Parameter('ionicity', types=dict, default={}, doc="""
A dictionary to specify the ionicity of each kind of atoms. If empty, the atoms are considered to be A dictionary to specify the ionicity of each kind of atoms. If empty, the atoms are considered to be

View File

@ -17,7 +17,7 @@ c
c Local variables c Local variables
c c
integer :: lwork integer :: lwork
complex*16 :: wquery complex*16 :: wquery(1)
complex*16 :: vl(1,1), vr(1,1) complex*16 :: vl(1,1), vr(1,1)
c c
real*8, allocatable :: rwork(:) real*8, allocatable :: rwork(:)
@ -39,7 +39,7 @@ c
write(iuo1,*) ' ' write(iuo1,*) ' '
end if end if
c c
lwork = int(wquery) lwork = int(wquery(1))
allocate(work(lwork)) allocate(work(lwork))
c c
call zgeev('n','n',n,a,lda,w,vl,1,vr,1,work,lwork,rwork,info) call zgeev('n','n',n,a,lda,w,vl,1,vr,1,work,lwork,rwork,info)

View File

@ -113,7 +113,7 @@ C
CST PROGRAM COMP_CURVE CST PROGRAM COMP_CURVE
SUBROUTINE COMP_CURVES() SUBROUTINE COMP_CURVES()
C C
PARAMETER (N_SIZE=1000,N_FILES=100,NMAX=9999) PARAMETER (N_SIZE=1000,N_FILES=1000,NMAX=9999)
C C
INTEGER CC_EXP(N_SIZE),CC_CAL(N_SIZE),VALUE,NVALUE INTEGER CC_EXP(N_SIZE),CC_CAL(N_SIZE),VALUE,NVALUE
C C
@ -1634,7 +1634,7 @@ C Author : D. Sébilleau
C C
C Last modified : 9 Sep 2014 C Last modified : 9 Sep 2014
C C
PARAMETER (N_SIZE=1000,N_FILES=100) PARAMETER (N_SIZE=1000,N_FILES=1000)
C C
REAL*4 X_CAL(N_SIZE),I_CAL,X,Y REAL*4 X_CAL(N_SIZE),I_CAL,X,Y
REAL*4 DIFF,STEP1,STEP2 REAL*4 DIFF,STEP1,STEP2
@ -2955,7 +2955,7 @@ C Author : D. Sébilleau
C C
C Last modified : 5 Sep 2014 C Last modified : 5 Sep 2014
C C
PARAMETER (N_SIZE=1000,N_FILES=100) PARAMETER (N_SIZE=1000,N_FILES=1000)
C C
REAL*4 EXPE(N_SIZE),CALCULATION(N_SIZE,N_FILES) REAL*4 EXPE(N_SIZE),CALCULATION(N_SIZE,N_FILES)
REAL*4 MIN_EXP,MIN_CAL,MINIMUM,SHIFT REAL*4 MIN_EXP,MIN_CAL,MINIMUM,SHIFT
@ -9748,7 +9748,7 @@ C Author : D. Sébilleau
C C
C Last modified : 19 Aug 2014 C Last modified : 19 Aug 2014
C C
PARAMETER (N_SIZE=1000,N_FILES=100) PARAMETER (N_SIZE=1000,N_FILES=1000)
C C
REAL*4 EXPE(N_SIZE),CALC(N_SIZE),Y_MEAN(N_SIZE) REAL*4 EXPE(N_SIZE),CALC(N_SIZE),Y_MEAN(N_SIZE)
real*4 x(N_SIZE) real*4 x(N_SIZE)

View File

@ -3,7 +3,7 @@ PYMAJ = 3
PYMIN = 6 PYMIN = 6
FC = gfortran FC = gfortran
F2PY = f2py3 F2PY = f2py3 --f77exec=$(FC) --f90exec=$(FC)
NO_VENV = 0 NO_VENV = 0
DEBUG = 0 DEBUG = 0

View File

@ -5,6 +5,7 @@ lxml
matplotlib matplotlib
numpy numpy
Pint Pint
pandas
pycairo pycairo
scipy scipy
setuptools-scm setuptools-scm

View File

@ -0,0 +1,163 @@
#!/usr/bin/env bash
#
# Copyright © 2016-2021 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : utils/dockerized/linux/msspec
# Last modified: Thu, 23 Sep 2021 16:55:16 +0200
# Committed by : sylvain tricot <sylvain.tricot@univ-rennes1.fr>
THIS_SCRIPT="$0"
IMAGE_NAME="iprcnrs/msspec:latest"
Logln () {
echo "$1" >&2
}
Log () {
echo -n "$1" >&2
}
Read_YesNo () {
PROMPT="$1"
DEFAULT="$2"
ANSWER=""
RESPONSE=""
VALID=1
while test $VALID -ne 0; do
read -p "${PROMPT} (y/n) [${DEFAULT}]? " "RESPONSE"
ANSWER="${RESPONSE:-${DEFAULT}}"
case "${ANSWER}" in
y|n) VALID=0 ;;
*) echo "Invalid choice, please answer \"y\" or \"n\"."; VALID=1 ;;
esac
done
}
Get_MsSpecContainerID () {
CID=$(docker ps -a -q --filter ancestor=$IMAGE_NAME)
echo $CID
}
Get_MsSpecImageID () {
IID=$(docker images -q $IMAGE_NAME)
echo $IID
}
Add_MsSpecImage () {
docker pull $IMAGE_NAME 1>&2
}
Add_MsSpecContainer () {
CID=$(Get_MsSpecContainerID)
if [ -z "$CID" ]; then
IID=$(Get_MsSpecImageID)
if [ -z "$IID" ]; then
Logln "Pulling MsSpec image..."
Add_MsSpecImage
fi
Log "Creating the MsSpec container... "
USERNAME=$(whoami)
USERID=$(id -u $USERNAME)
GROUPID=$(id -g $USERNAME)
CID=$(docker create -i --net=host -e DISPLAY=$DISPLAY -v $HOME:$HOME -u ${USERID}:${GROUPID} --entrypoint /bin/bash $IMAGE_NAME)
Logln "done."
fi
echo $CID
}
Start_MsSpecContainer () {
CID=$(Add_MsSpecContainer)
status=$(docker container inspect -f '{{.State.Status}}' $CID)
if [ $status != "running" ]; then
Log "Starting MsSpec container... "
# Start the container
CID=$(docker start $CID)
Logln "done."
fi
}
Remove_MsSpecContainer () {
Log "Removing MsSpec container... "
CID=$(Get_MsSpecContainerID)
docker stop -t 1 $CID >/dev/null 2>&1
docker rm $CID >/dev/null 2>&1
Logln "done."
}
Run_MsSpec () {
# Run msspec command
CID=$(Get_MsSpecContainerID)
xhost +localhost >/dev/null 2>&1
docker exec -i -t -w "$PWD" $CID msspec "$@"
}
Run_Bash () {
# Run msspec command
CID=$(Get_MsSpecContainerID)
xhost +localhost >/dev/null 2>&1
docker exec -i -t -w "$PWD" -e HOME=$HOME -e PS1="MsSpec:\w> " $CID /bin/bash --norc --noprofile
}
Uninstall_MsSpecImage () {
Read_YesNo "You are about to remove the MsSpec Docker image, its container and this script. Are you sure" "n"
case $ANSWER in
y) Remove_MsSpecContainer;
Log "Removing ${IMAGE_NAME}...";
docker rmi $IMAGE_NAME >/dev/null 2>&1;
Logln "done.";
Log "Removing ${THIS_SCRIPT}...";
rm -f $THIS_SCRIPT;
Logln "done.";
;;
n) echo "Uninstallation aborted."
esac
}
Show_Help () {
echo "Usage: 1) msspec -p [PYTHON OPTIONS] SCRIPT [ARGUMENTS...]"
echo " 2) msspec [-l FILE | -i | -h]"
echo " 3) msspec [bash | reset]"
echo ""
echo "Form (1) is used to launch a script"
echo "Form (2) is used to load a hdf5 data file"
echo "Form (3) is used to control the Docker container/image."
echo ""
echo "List of possible options:"
echo " -p Pass every arguments after this option to the msspec"
echo " virtual environment Python interpreter."
echo " -i Run the interactive Python interpreter within msspec"
echo " virtual environment."
echo " -l Load and display a *.hdf5 data file in a graphical"
echo " window."
echo " -v Print the version."
echo " -h Show this help message."
echo ""
echo " bash This command starts an interactive bash shell in the"
echo " MsSpec container."
echo " reset This command removes the MsSpec container (but not the"
echo " image). Changes made in the container will be lost and"
echo " any new call to msspec will recreate a new fresh container."
}
case $1 in
reset) Remove_MsSpecContainer ;;
bash) Start_MsSpecContainer; Run_Bash ;;
"-u") Uninstall_MsSpecImage ;;
"-h"|"") Start_MsSpecContainer; Show_Help ;;
*) Start_MsSpecContainer; Run_MsSpec "$@" ;;
esac

View File

@ -0,0 +1,219 @@
// ----------------------------------------------------------------------------
//
// Inno Setup Ver: 5.4.2
// Script Version: 1.4.2
// Author: Jared Breland <jbreland@legroom.net>
// Homepage: http://www.legroom.net/software
// License: GNU Lesser General Public License (LGPL), version 3
// http://www.gnu.org/licenses/lgpl.html
//
// Script Function:
// Allow modification of environmental path directly from Inno Setup installers
//
// Instructions:
// Copy modpath.iss to the same directory as your setup script
//
// Add this statement to your [Setup] section
// ChangesEnvironment=true
//
// Add this statement to your [Tasks] section
// You can change the Description or Flags
// You can change the Name, but it must match the ModPathName setting below
// Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
//
// Add the following to the end of your [Code] section
// ModPathName defines the name of the task defined above
// ModPathType defines whether the 'user' or 'system' path will be modified;
// this will default to user if anything other than system is set
// setArrayLength must specify the total number of dirs to be added
// Result[0] contains first directory, Result[1] contains second, etc.
// const
// ModPathName = 'modifypath';
// ModPathType = 'user';
//
// function ModPathDir(): TArrayOfString;
// begin
// setArrayLength(Result, 1);
// Result[0] := ExpandConstant('{app}');
// end;
// #include "modpath.iss"
// ----------------------------------------------------------------------------
procedure ModPath();
var
oldpath: String;
newpath: String;
updatepath: Boolean;
pathArr: TArrayOfString;
aExecFile: String;
aExecArr: TArrayOfString;
i, d: Integer;
pathdir: TArrayOfString;
regroot: Integer;
regpath: String;
begin
// Get constants from main script and adjust behavior accordingly
// ModPathType MUST be 'system' or 'user'; force 'user' if invalid
if ModPathType = 'system' then begin
regroot := HKEY_LOCAL_MACHINE;
regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
end else begin
regroot := HKEY_CURRENT_USER;
regpath := 'Environment';
end;
// Get array of new directories and act on each individually
pathdir := ModPathDir();
for d := 0 to GetArrayLength(pathdir)-1 do begin
updatepath := true;
// Modify WinNT path
if UsingWinNT() = true then begin
// Get current path, split into an array
RegQueryStringValue(regroot, regpath, 'Path', oldpath);
oldpath := oldpath + ';';
i := 0;
while (Pos(';', oldpath) > 0) do begin
SetArrayLength(pathArr, i+1);
pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
i := i + 1;
// Check if current directory matches app dir
if pathdir[d] = pathArr[i-1] then begin
// if uninstalling, remove dir from path
if IsUninstaller() = true then begin
continue;
// if installing, flag that dir already exists in path
end else begin
updatepath := false;
end;
end;
// Add current directory to new path
if i = 1 then begin
newpath := pathArr[i-1];
end else begin
newpath := newpath + ';' + pathArr[i-1];
end;
end;
// Append app dir to path if not already included
if (IsUninstaller() = false) AND (updatepath = true) then
newpath := newpath + ';' + pathdir[d];
// Write new path
RegWriteStringValue(regroot, regpath, 'Path', newpath);
// Modify Win9x path
end else begin
// Convert to shortened dirname
pathdir[d] := GetShortName(pathdir[d]);
// If autoexec.bat exists, check if app dir already exists in path
aExecFile := 'C:\AUTOEXEC.BAT';
if FileExists(aExecFile) then begin
LoadStringsFromFile(aExecFile, aExecArr);
for i := 0 to GetArrayLength(aExecArr)-1 do begin
if IsUninstaller() = false then begin
// If app dir already exists while installing, skip add
if (Pos(pathdir[d], aExecArr[i]) > 0) then
updatepath := false;
break;
end else begin
// If app dir exists and = what we originally set, then delete at uninstall
if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
aExecArr[i] := '';
end;
end;
end;
// If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
if (IsUninstaller() = false) AND (updatepath = true) then begin
SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
// If uninstalling, write the full autoexec out
end else begin
SaveStringsToFile(aExecFile, aExecArr, False);
end;
end;
end;
end;
// Split a string into an array using passed delimeter
procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
var
i: Integer;
begin
i := 0;
repeat
SetArrayLength(Dest, i+1);
if Pos(Separator,Text) > 0 then begin
Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
i := i + 1;
end else begin
Dest[i] := Text;
Text := '';
end;
until Length(Text)=0;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
taskname: String;
begin
taskname := ModPathName;
if CurStep = ssPostInstall then
if WizardIsTaskSelected(taskname) then
ModPath();
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
aSelectedTasks: TArrayOfString;
i: Integer;
taskname: String;
regpath: String;
regstring: String;
appid: String;
begin
// only run during actual uninstall
if CurUninstallStep = usUninstall then begin
// get list of selected tasks saved in registry at install time
appid := '{#emit SetupSetting("AppId")}';
if appid = '' then appid := '{#emit SetupSetting("AppName")}';
regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
// check each task; if matches modpath taskname, trigger patch removal
if regstring <> '' then begin
taskname := ModPathName;
MPExplode(aSelectedTasks, regstring, ',');
if GetArrayLength(aSelectedTasks) > 0 then begin
for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
if comparetext(aSelectedTasks[i], taskname) = 0 then
ModPath();
end;
end;
end;
end;
end;
function NeedRestart(): Boolean;
var
taskname: String;
begin
taskname := ModPathName;
if WizardIsTaskSelected(taskname) and not UsingWinNT() then begin
Result := True;
end else begin
Result := False;
end;
end;

Binary file not shown.

View File

@ -0,0 +1,69 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "MsSpec"
#define MyAppVersion ""
#define MyAppPublisher "IPR"
#define MyAppURL "https://msspec.cnrs.fr"
#define MyAppExeName "msspec.exe"
#define MyAppInstallerName "msspec_setup"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{BB2F7A31-BDDF-4D22-BDBD-C77BEB6D3780}}
AppName={#MyAppName}
;AppVersion={#MyAppVersion}
AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog
OutputBaseFilename={#MyAppInstallerName}
Compression=lzma
SolidCompression=yes
WizardStyle=modern
ChangesEnvironment=true
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: ".\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
;Source: "D:\Home\stricot\Documents\WindowsPowerShell\Scripts\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
;[Icons]
;Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
;[Run]
;Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Tasks]
Name: modifypath; Description: Add application directory to your environmental path;
;Flags: unchecked
[UninstallRun]
Filename: "{app}\{#MyAppExeName}"; Parameters: "-u";
[Messages]
FinishedLabelNoIcons=Setup has finished installing [name] on your computer. To launch MsSpec, open a terminal window and enter 'msspec'.
[Code]
const
ModPathName = 'modifypath';
ModPathType = 'user';
function ModPathDir(): TArrayOfString;
begin
setArrayLength(Result, 1)
Result[0] := ExpandConstant('{app}');
end;
#include "modpath.iss"

View File

@ -0,0 +1,171 @@
##[Ps1 To Exe]
##
##Kd3HDZOFADWE8uK1
##Nc3NCtDXThU=
##Kd3HFJGZHWLWoLaVvnQnhQ==
##LM/RF4eFHHGZ7/K1
##K8rLFtDXTiW5
##OsHQCZGeTiiZ4tI=
##OcrLFtDXTiW5
##LM/BD5WYTiiZ4tI=
##McvWDJ+OTiiZ4tI=
##OMvOC56PFnzN8u+Vs1Q=
##M9jHFoeYB2Hc8u+Vs1Q=
##PdrWFpmIG2HcofKIo2QX
##OMfRFJyLFzWE8uK1
##KsfMAp/KUzWJ0g==
##OsfOAYaPHGbQvbyVvnQX
##LNzNAIWJGmPcoKHc7Do3uAuO
##LNzNAIWJGnvYv7eVvnQX
##M9zLA5mED3nfu77Q7TV64AuzAgg=
##NcDWAYKED3nfu77Q7TV64AuzAgg=
##OMvRB4KDHmHQvbyVvnQX
##P8HPFJGEFzWE8tI=
##KNzDAJWHD2fS8u+Vgw==
##P8HSHYKDCX3N8u+Vgw==
##LNzLEpGeC3fMu77Ro2k3hQ==
##L97HB5mLAnfMu77Ro2k3hQ==
##P8HPCZWEGmaZ7/K1
##L8/UAdDXTlGDjpra7jFL9l/8S2skevm/trWyyYSy6/nQjCzXTZUDWmR4gSzuN0O4Vf4uZvYHvcEFRiEnPOEb57GeHv+sJQ==
##Kc/BRM3KXhU=
##
##
##fd6a9f26a06ea3bc99616d4851b372ba
# PowerShell
$SCRIPT_PATH = $MyInvocation.MyCommand.Path
$IMAGE_NAME = "iprcnrs/msspec:latest"
Function Read-YesNo($PROMPT, $DEFAULT) {
$VALID = 1
While($VALID -ne 0) {
$ANSWER = Read-Host "$PROMPT (y/n) [$DEFAULT]? "
Switch($ANSWER) {
"" {$ANSWER=$DEFAULT; $VALID=0; Break}
"y" {$VALID=0; Break}
"n" {$VALID=0; Break}
Default {Write-Host "Invalid choice, please answer 'y' or 'n'."; $VALID=1; Break}
}
}
Return $ANSWER
}
Function Get-MsSpecContainerID {
Return docker ps -a -q --filter ancestor=$IMAGE_NAME
}
Function Get-MsSpecImageID {
Return docker images -q $IMAGE_NAME
}
Function Add-MsSpecImage {
Write-Host "Pulling MsSpec image...";
docker pull $IMAGE_NAME;
Write-Host "done."
$IID = Get-MsSpecImageID;
Return $IID;
}
Function Add-MsSpecContainer {
$CID = Get-MsSpecContainerID
If($CID -eq $NULL) {
$IID = Get-MsSpecImageID
If($IID -eq $NULL) {
#Add-MsSpecImage;
}
Write-Host -nonewline "Creating the MsSpec container... "
$mydocuments = [environment]::GetFolderPath("mydocuments")
$drive = ($mydocuments -split ":",2)[0]
docker create -i -v ${drive}:\:/$drive --entrypoint /bin/bash $IMAGE_NAME >$NULL
$CID = Get-MsSpecContainerID
Write-Host "done."
}
Return $CID
}
Function Start-MsSpecContainer {
$CID = Add-MsSpecContainer;
$status = docker container inspect -f '{{.State.Status}}' $CID;
IF($status -ne "running") {
Write-Host -nonewline "Starting MsSpec container...";
$CID = docker start $CID;
Write-Host "done.";
}
}
Function Remove-MsSpecContainer {
Write-Host -nonewline "Removing MsSpec container...";
$CID = Get-MsSpecContainerID;
IF($CID -ne $NULL) {
docker stop -t 1 $CID >$NULL;
docker rm $CID >$NULL;
}
Write-Host "done."
}
Function Run-MsSpec($opts) {
# Run msspec command
$CID = Get-MsSpecContainerID;
$nixPath = "/" + (${PWD} -replace "\\","/") -replace ":",""
docker exec -i -t -e DISPLAY=host.docker.internal:0 -w $nixPath $CID msspec $opts
}
Function Run-Bash {
# Run bash
$CID = Get-MsSpecContainerID;
$nixPath = "/" + (${PWD} -replace "\\","/") -replace ":",""
docker exec -i -t -w $nixPath -e DISPLAY=host.docker.internal:0 $CID /bin/bash
}
Function Uninstall-MsSpecImage {
$ANSWER = Read-YesNo "You are about to remove the MsSpec Docker image, its container and this script. Are you sure" "n"
Switch($ANSWER) {
"y" {Remove-MsSpecContainer;
Write-Host -nonewline "Removing $IMAGE_NAME...";
$IID = Get-MsSpecImageID;
If($IID -ne $NULL) {
docker rmi $IMAGE_NAME >$NULL;
}
Write-Host "done.";
# Remove-Item $THIS_SCRIPT;
Break;
}
"n" {Write-Host "Uninstallation aborted."; Break}
}
}
Function Show-Help {
Write-Host "Usage: 1) msspec -p [PYTHON OPTIONS] SCRIPT [ARGUMENTS...]"
Write-Host " 2) msspec [-l FILE | -i | -h]"
Write-Host " 3) msspec [bash | reset]"
Write-Host ""
Write-Host "Form (1) is used to launch a script"
Write-Host "Form (2) is used to load a hdf5 data file"
Write-Host "Form (3) is used to control the Docker container/image."
Write-Host ""
Write-Host "List of possible options:"
Write-Host " -p Pass every arguments after this option to the msspec"
Write-Host " virtual environment Python interpreter."
Write-Host " -i Run the interactive Python interpreter within msspec"
Write-Host " virtual environment."
Write-Host " -l Load and display a *.hdf5 data file in a graphical"
Write-Host " window."
Write-Host " -v Print the version."
Write-Host " -h Show this help message."
Write-Host ""
Write-Host " bash This command starts an interactive bash shell in the"
Write-Host " MsSpec container."
Write-Host " reset This command removes the MsSpec container (but not the"
Write-Host " image). Changes made in the container will be lost and"
Write-Host " any new call to msspec will recreate a new fresh container."
}
Switch($args[0]) {
"reset" {Remove-MsSpecContainer; Break}
"bash" {Start-MsSpecContainer; Run-Bash; Break}
"-u" {Uninstall-MsSpecImage; Break}
"-h" {Start-MsSpecContainer; Show-Help; Break}
"" {Start-MsSpecContainer; Show-Help; Break}
Default {Start-MsSpecContainer; Run-MsSpec $args; Break}
pull {Add-MsSpecImage; Break}
}

Binary file not shown.