Startup
This commit is contained in:
1
script/__Lib/diffcalc_old/.cache/v/cache/lastfailed
vendored
Normal file
1
script/__Lib/diffcalc_old/.cache/v/cache/lastfailed
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
9
script/__Lib/diffcalc_old/.gitignore
vendored
Normal file
9
script/__Lib/diffcalc_old/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
*.class
|
||||
*~
|
||||
*.pyc
|
||||
doc/build/
|
||||
.pydevproject
|
||||
.project
|
||||
.tox
|
||||
.DS_Store
|
||||
.idea
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<project>
|
||||
<owner>Diamond Light Source Ltd.</owner>
|
||||
<copyright><![CDATA[ Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
This file is part of Diffcalc.
|
||||
|
||||
Diffcalc 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.
|
||||
|
||||
Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.]]></copyright>
|
||||
<header contentId="org.eclipse.core.runtime.text" postBlankLines="2" lineFormat="false" preserveFirstLine="false">
|
||||
<beginLine><![CDATA[###]]></beginLine>
|
||||
<linePrefix><![CDATA[#]]></linePrefix>
|
||||
<endLine><![CDATA[###]]></endLine>
|
||||
</header>
|
||||
<header contentId="org.python.pydev.pythonfile" postBlankLines="1" lineFormat="false" preserveFirstLine="false">
|
||||
<beginLine><![CDATA[###]]></beginLine>
|
||||
<linePrefix><![CDATA[#]]></linePrefix>
|
||||
<endLine><![CDATA[###]]></endLine>
|
||||
</header>
|
||||
</project>
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//doc/source/conf.py=utf-8
|
||||
encoding/<project>=UTF-8
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
line.separator=\n
|
||||
23
script/__Lib/diffcalc_old/.travis.yml
Normal file
23
script/__Lib/diffcalc_old/.travis.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
# based on https://www.topbug.net/blog/2012/05/27/use-travis-ci-with-jython/
|
||||
|
||||
language: python
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
env:
|
||||
- JYTHON=false
|
||||
- JYTHON=true
|
||||
|
||||
before_install:
|
||||
- if [ "$JYTHON" == "true" ]; then . install-jython-environment.sh; fi
|
||||
- if [ "$JYTHON" == "false" ]; then pip install --upgrade pytest; pip install pytest-xdist; fi
|
||||
|
||||
install: pip install --upgrade pytest
|
||||
|
||||
before_script:
|
||||
- if [ "$JYTHON" == "true" ]; then export PYTEST=$HOME/jython/bin/pytest; else export PYTEST=pytest; fi
|
||||
- echo PYTEST:- $PYTEST
|
||||
|
||||
script: $PYTEST
|
||||
|
||||
674
script/__Lib/diffcalc_old/COPYING
Normal file
674
script/__Lib/diffcalc_old/COPYING
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
52
script/__Lib/diffcalc_old/Makefile
Normal file
52
script/__Lib/diffcalc_old/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
test-all: test-python test-jython test-integration test-launcher
|
||||
|
||||
test-python:
|
||||
py.test
|
||||
|
||||
test-jython:
|
||||
export CLASSPATH=$(HOME)/lib/Jama-1.0.3.jar:$(CLASSPATH); echo $$CLASSPATH; $(HOME)/jython/bin/py.test
|
||||
|
||||
test-integration:
|
||||
py.test --boxed integration_checks.py
|
||||
|
||||
test-launcher:
|
||||
./diffcalc.py --help
|
||||
./diffcalc.py --modules
|
||||
./diffcalc.py --non-interactive --python sixcircle
|
||||
|
||||
install-jython:
|
||||
./install-jython-environment.sh
|
||||
|
||||
doc-source:
|
||||
./diffcalc.py --non-interactive --make-manuals-source
|
||||
|
||||
doc-html:
|
||||
cd doc; make html
|
||||
|
||||
doc-pdf:
|
||||
cd doc; make pdf
|
||||
|
||||
doc-all:
|
||||
cd doc; make all
|
||||
|
||||
doc-clean:
|
||||
cd doc; make clean
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo
|
||||
@echo " test-all"
|
||||
@echo " test-python"
|
||||
@echo " test-jython"
|
||||
@echo " test-integration"
|
||||
@echo " test-launcher"
|
||||
@echo " install-jython"
|
||||
@echo
|
||||
@echo " doc-source : to expand *_template.rst to *.rst"
|
||||
@echo " doc-html"
|
||||
@echo " doc-pdf"
|
||||
@echo " doc-all"
|
||||
@echo " doc-clean"
|
||||
@echo
|
||||
479
script/__Lib/diffcalc_old/README.rst
Normal file
479
script/__Lib/diffcalc_old/README.rst
Normal file
@@ -0,0 +1,479 @@
|
||||
Diffcalc - A Diffraction Condition Calculator for Diffractometer Control
|
||||
========================================================================
|
||||
|
||||
Diffcalc is a python/jython based diffraction condition calculator used for
|
||||
controlling diffractometers within reciprocal lattice space. It performs the
|
||||
same task as the fourc, sixc, twoc, kappa, psic and surf macros from SPEC.
|
||||
|
||||
There is a `user guide <https://diffcalc.readthedocs.io/en/latest/youmanual.html>`_ and `developer guide <https://diffcalc.readthedocs.io/en/latest/developer/contents.html>`_, both at `diffcalc.readthedocs.io <https://diffcalc.readthedocs.io>`_
|
||||
|
||||
|Travis| |Read the docs|
|
||||
|
||||
.. |Travis| image:: https://travis-ci.org/DiamondLightSource/diffcalc.svg?branch=master
|
||||
:target: https://travis-ci.org/DiamondLightSource/diffcalc
|
||||
:alt: Build Status
|
||||
|
||||
.. |Read the docs| image:: https://readthedocs.org/projects/diffcalc/badge/?version=latest
|
||||
:target: http://diffcalc.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. contents::
|
||||
|
||||
.. section-numbering::
|
||||
|
||||
Software compatibility
|
||||
----------------------
|
||||
|
||||
- Written in Python using numpy
|
||||
- Works in Jython using Jama
|
||||
- Runs directly in `OpenGDA<http://www.opengda.org>`
|
||||
- Runs in in Python or IPython using minimal OpenGda emulation (included)
|
||||
- Contact us for help running in your environment
|
||||
|
||||
Diffractometer compatibility
|
||||
----------------------------
|
||||
|
||||
Diffcalc’s standard calculation engine is an implementation of [You1999]_ and
|
||||
[Busing1967]_. Diffcalc works with any diffractometer which is a subset of:
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/DiamondLightSource/diffcalc/master/doc/source/youmanual_images/4s_2d_diffractometer.png
|
||||
:alt: 4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
Diffcalc can be configured to work with any diffractometer geometry which is a
|
||||
subset of this. For example, a five-circle diffractometer might be missing the
|
||||
nu circle above.
|
||||
|
||||
Note that the first versions of Diffcalc were based on [Vlieg1993]_ and
|
||||
[Vlieg1998]_ and a ‘Vlieg’ engine is still available. There is also an engine
|
||||
based on [Willmott2011]_. The ‘You’ engine is more generic and the plan is to
|
||||
remove the old ‘Vlieg’ engine once beamlines have been migrated.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Check it out::
|
||||
|
||||
$ git clone https://github.com/DiamondLightSource/diffcalc.git
|
||||
Cloning into 'diffcalc'...
|
||||
|
||||
At Diamond Diffcalc may be installed within an OpenGDA deployment and is
|
||||
available via the 'module' system from bash.
|
||||
|
||||
Starting
|
||||
--------
|
||||
|
||||
Start diffcalc in ipython using a sixcircle dummy diffractometer::
|
||||
|
||||
$ cd diffcalc
|
||||
$ ./diffcalc.py --help
|
||||
...
|
||||
|
||||
$ ./diffcalc.py sixcircle
|
||||
|
||||
Running: "ipython --no-banner --HistoryManager.hist_file=/tmp/ipython_hist_zrb13439.sqlite -i -m diffcmd.start sixcircle False"
|
||||
|
||||
---------------------------------- DIFFCALC -----------------------------------
|
||||
Startup script: '/Users/zrb13439/git/diffcalc/startup/sixcircle.py'
|
||||
Loading ub calculation: 'test'
|
||||
------------------------------------ Help -------------------------------------
|
||||
Quick: https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst
|
||||
Manual: https://diffcalc.readthedocs.io
|
||||
Type: > help ub
|
||||
> help hkl
|
||||
-------------------------------------------------------------------------------
|
||||
In [1]:
|
||||
|
||||
Within Diamond use::
|
||||
|
||||
$ module load diffcalc
|
||||
$ diffcalc --help
|
||||
...
|
||||
$ diffcalc sixcircle
|
||||
|
||||
Trying it out
|
||||
-------------
|
||||
|
||||
Type ``demo.all()`` to see it working and then move try the following quick
|
||||
start guide::
|
||||
|
||||
>>> demo.all()
|
||||
...
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
To view help with orientation and then moving in hkl space::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
Configuring a UB calculation
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
To create a new UB-calculation::
|
||||
|
||||
>>> newub 'example'
|
||||
>>> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
>>> pos wl 1
|
||||
wl: 1.0000
|
||||
>>> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
>>> pos sixc [0 60 0 30 90 0]
|
||||
sixc: mu: 0.0000 delta: 60.0000 gam: 0.0000 eta: 30.0000 chi: 90.0000 phi: 0.0000
|
||||
>>> addref [0 0 1]
|
||||
|
||||
>>> pos sixc [0 90 0 45 45 90]
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
>>> addref [0 1 1]
|
||||
Calculating UB matrix.
|
||||
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
>>> checkub
|
||||
|
||||
ENERGY H K L H_COMP K_COMP L_COMP TAG
|
||||
1 12.3984 0.00 0.00 1.00 0.0000 0.0000 1.0000
|
||||
2 12.3984 0.00 1.00 1.00 0.0000 1.0000 1.0000
|
||||
|
||||
To see the resulting UB-calculation::
|
||||
|
||||
>>> ub
|
||||
UBCALC
|
||||
|
||||
name: example
|
||||
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
|
||||
CRYSTAL
|
||||
|
||||
name: 1Acube
|
||||
|
||||
a, b, c: 1.00000 1.00000 1.00000
|
||||
90.00000 90.00000 90.00000
|
||||
|
||||
B matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
UB MATRIX
|
||||
|
||||
U matrix: 1.00000 0.00000 0.00000
|
||||
0.00000 1.00000 0.00000
|
||||
0.00000 0.00000 1.00000
|
||||
|
||||
U angle: 0
|
||||
|
||||
UB matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
REFLECTIONS
|
||||
|
||||
ENERGY H K L MU DELTA GAM ETA CHI PHI TAG
|
||||
1 12.398 0.00 0.00 1.00 0.0000 60.0000 0.0000 30.0000 90.0000 0.0000
|
||||
2 12.398 0.00 1.00 1.00 0.0000 90.0000 0.0000 45.0000 45.0000 90.0000
|
||||
|
||||
Setting the reference vector
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
>>> con
|
||||
DET REF SAMP
|
||||
------ ------ ------
|
||||
delta --> a_eq_b --> mu
|
||||
--> gam alpha eta
|
||||
qaz beta chi
|
||||
naz psi phi
|
||||
mu_is_gam
|
||||
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
Type 'help con' for instructions
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
>>> sim hkl [0 1 1]
|
||||
sixc would move to:
|
||||
mu : 0.0000
|
||||
delta : 90.0000
|
||||
gam : 0.0000
|
||||
eta : 45.0000
|
||||
chi : 45.0000
|
||||
phi : 90.0000
|
||||
|
||||
alpha : 30.0000
|
||||
beta : 30.0000
|
||||
naz : 35.2644
|
||||
psi : 90.0000
|
||||
qaz : 90.0000
|
||||
tau : 45.0000
|
||||
theta : 45.0000
|
||||
|
||||
Move to reflection::
|
||||
|
||||
>>> pos hkl [0 1 1]
|
||||
hkl: h: 0.00000 k: 1.00000 l: 1.00000
|
||||
|
||||
>>> pos sixc
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
|
||||
|
||||
Scanning in hkl space
|
||||
---------------------
|
||||
|
||||
Scan an hkl axis (and read back settings)::
|
||||
|
||||
>>> scan l 0 1 .2 sixc
|
||||
l mu delta gam eta chi phi
|
||||
------- ------- -------- ------- -------- ------- --------
|
||||
0.00000 0.0000 60.0000 0.0000 30.0000 0.0000 90.0000
|
||||
0.20000 0.0000 61.3146 0.0000 30.6573 11.3099 90.0000
|
||||
0.40000 0.0000 65.1654 0.0000 32.5827 21.8014 90.0000
|
||||
0.60000 0.0000 71.3371 0.0000 35.6685 30.9638 90.0000
|
||||
0.80000 0.0000 79.6302 0.0000 39.8151 38.6598 90.0000
|
||||
1.00000 0.0000 90.0000 0.0000 45.0000 45.0000 90.0000
|
||||
|
||||
Scan a constraint (and read back virtual angles and eta)::
|
||||
|
||||
>>> con psi
|
||||
gam : 0.0000
|
||||
! psi : ---
|
||||
mu : 0.0000
|
||||
>>> scan psi 70 110 10 hklverbose [0 1 1] eta
|
||||
psi eta h k l theta qaz alpha naz tau psi beta
|
||||
-------- -------- ------- ------- ------- -------- -------- -------- -------- -------- -------- --------
|
||||
70.00000 26.1183 0.00000 1.00000 1.00000 45.00000 90.00000 19.20748 45.28089 45.00000 70.00000 42.14507
|
||||
80.00000 35.1489 -0.00000 1.00000 1.00000 45.00000 90.00000 24.40450 40.12074 45.00000 80.00000 35.93196
|
||||
90.00000 45.0000 0.00000 1.00000 1.00000 45.00000 90.00000 30.00000 35.26439 45.00000 90.00000 30.00000
|
||||
100.00000 54.8511 -0.00000 1.00000 1.00000 45.00000 90.00000 35.93196 30.68206 45.00000 100.00000 24.40450
|
||||
110.00000 63.8817 -0.00000 1.00000 1.00000 45.00000 90.00000 42.14507 26.34100 45.00000 110.00000 19.20748
|
||||
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **STATE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- newub** {'name'} | start a new ub calculation name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- loadub** 'name' | num | load an existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- lastub** | load the last used ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- listub** | list the ub calculations available to load |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- rmub** 'name'|num | remove existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- saveubas** 'name' | save the ub calculation with a new name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **LATTICE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** | interactively enter lattice parameters (Angstroms |
|
||||
| | and Deg) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a | assumes cubic |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b | assumes tetragonal |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes ortho |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes mon/hex with gam not equal to 90 |
|
||||
| gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | arbitrary |
|
||||
| alpha beta gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- c2th** [h k l] | calculate two-theta angle for reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFERENCE (SURFACE)** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnphi** {[x y z]} | sets or displays n_phi reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnhkl** {[h k l]} | sets or displays n_hkl reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFLECTIONS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- showref** | shows full reflection list |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** | add reflection interactively |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] | add reflection with current position and energy |
|
||||
| {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] (p1, | add arbitrary reflection |
|
||||
| .., pN) energy {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- editref** num | interactively edit a reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- delref** num | deletes a reflection (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- clearref** | deletes all the reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** | swaps first two reflections used for calulating U |
|
||||
| | matrix |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** num1 num2 | swaps two reflections (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **UB MATRIX** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- checkub** | show calculated and entered hkl values for |
|
||||
| | reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setu** | manually set u matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setub** | manually set ub matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- calcub** | (re)calculate u matrix from ref1 and ref2 |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- trialub** | (re)calculate u matrix from ref1 only (check |
|
||||
| | carefully) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
Motion Commands
|
||||
---------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **CONSTRAINTS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** | list available constraints and values |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | constrains and optionally sets one constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | clears and then fully constrains |
|
||||
| <name> {val} <name> {val} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- uncon** <name> | remove constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HKL** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- allhkl** [h k l] | print all hkl solutions ignoring limits |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HARDWARE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hardware** | show diffcalc limits and cuts |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setcut** {name {val}} | sets cut angle |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmin** {axis {val}} | set lower limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmax** {name {val}} | sets upper limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **MOTION** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl scn | simulates moving scannable (not all) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sixc** | show Eularian position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** sixc [mu, delta, | move to Eularian position(None holds an axis |
|
||||
| gam, eta, chi, phi] | still) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** sixc [mu, delta, | simulate move to Eulerian positionsixc |
|
||||
| gam, eta, chi, phi] | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hkl** | show hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** hkl [h k l] | move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** {h | k | l} val | move h, k or l to val |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl [h k l] | simulate move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
|
||||
.. [Vlieg1993] Martin Lohmeier and Elias Vlieg. *Angle calculations for a six-circle
|
||||
surface x-ray diffractometer.* J. Appl. Cryst. (1993). **26**, 706-716. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1993/05/00/la0044/la0044.pdf>`__.
|
||||
|
||||
.. [Vlieg1998] Elias Vlieg. *A (2+3)-type surface diffractometer: mergence of the z-axis and
|
||||
(2+2)-type geometries.* J. Appl. Cryst. (1998). **31**, 198-203. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1998/02/00/pe0028/pe0028.pdf>`__.
|
||||
|
||||
.. [Willmott2011] C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans'l and
|
||||
P. R. Willmott. *Angle calculations for a (2+3)-type diffractometer: focus
|
||||
on area detectors.* J. Appl. Cryst. (2011). **44**, 73-83. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/2011/01/00/db5088/db5088.pdf>`__.
|
||||
267
script/__Lib/diffcalc_old/README_template.rst
Normal file
267
script/__Lib/diffcalc_old/README_template.rst
Normal file
@@ -0,0 +1,267 @@
|
||||
Diffcalc - A Diffraction Condition Calculator for Diffractometer Control
|
||||
========================================================================
|
||||
|
||||
Diffcalc is a python/jython based diffraction condition calculator used for
|
||||
controlling diffractometers within reciprocal lattice space. It performs the
|
||||
same task as the fourc, sixc, twoc, kappa, psic and surf macros from SPEC.
|
||||
|
||||
There is a `user guide <https://diffcalc.readthedocs.io/en/latest/youmanual.html>`_ and `developer guide <https://diffcalc.readthedocs.io/en/latest/developer/contents.html>`_, both at `diffcalc.readthedocs.io <https://diffcalc.readthedocs.io>`_
|
||||
|
||||
|Travis| |Read the docs|
|
||||
|
||||
.. |Travis| image:: https://travis-ci.org/DiamondLightSource/diffcalc.svg?branch=master
|
||||
:target: https://travis-ci.org/DiamondLightSource/diffcalc
|
||||
:alt: Build Status
|
||||
|
||||
.. |Read the docs| image:: https://readthedocs.org/projects/diffcalc/badge/?version=latest
|
||||
:target: http://diffcalc.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation Status
|
||||
|
||||
.. contents::
|
||||
|
||||
.. section-numbering::
|
||||
|
||||
Software compatibility
|
||||
----------------------
|
||||
|
||||
- Written in Python using numpy
|
||||
- Works in Jython using Jama
|
||||
- Runs directly in `OpenGDA<http://www.opengda.org>`
|
||||
- Runs in in Python or IPython using minimal OpenGda emulation (included)
|
||||
- Contact us for help running in your environment
|
||||
|
||||
Diffractometer compatibility
|
||||
----------------------------
|
||||
|
||||
Diffcalc’s standard calculation engine is an implementation of [You1999]_ and
|
||||
[Busing1967]_. Diffcalc works with any diffractometer which is a subset of:
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/DiamondLightSource/diffcalc/master/doc/source/youmanual_images/4s_2d_diffractometer.png
|
||||
:alt: 4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
:width: 50%
|
||||
:align: center
|
||||
|
||||
Diffcalc can be configured to work with any diffractometer geometry which is a
|
||||
subset of this. For example, a five-circle diffractometer might be missing the
|
||||
nu circle above.
|
||||
|
||||
Note that the first versions of Diffcalc were based on [Vlieg1993]_ and
|
||||
[Vlieg1998]_ and a ‘Vlieg’ engine is still available. There is also an engine
|
||||
based on [Willmott2011]_. The ‘You’ engine is more generic and the plan is to
|
||||
remove the old ‘Vlieg’ engine once beamlines have been migrated.
|
||||
|
||||
If we choose the x axis parallel to b, the yaxis intheplaneofblandb2,andthezaxis perpendicular to that plane,
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Check it out::
|
||||
|
||||
$ git clone https://github.com/DiamondLightSource/diffcalc.git
|
||||
Cloning into 'diffcalc'...
|
||||
|
||||
At Diamond Diffcalc may be installed within an OpenGDA deployment and is
|
||||
available via the 'module' system from bash.
|
||||
|
||||
Starting
|
||||
--------
|
||||
|
||||
Start diffcalc in ipython using a sixcircle dummy diffractometer::
|
||||
|
||||
$ cd diffcalc
|
||||
$ ./diffcalc.py --help
|
||||
...
|
||||
|
||||
$ ./diffcalc.py sixcircle
|
||||
|
||||
Running: "ipython --no-banner --HistoryManager.hist_file=/tmp/ipython_hist_zrb13439.sqlite -i -m diffcmd.start sixcircle False"
|
||||
|
||||
---------------------------------- DIFFCALC -----------------------------------
|
||||
Startup script: '/Users/zrb13439/git/diffcalc/startup/sixcircle.py'
|
||||
Loading ub calculation: 'test'
|
||||
------------------------------------ Help -------------------------------------
|
||||
Quick: https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst
|
||||
Manual: https://diffcalc.readthedocs.io
|
||||
Type: > help ub
|
||||
> help hkl
|
||||
-------------------------------------------------------------------------------
|
||||
In [1]:
|
||||
|
||||
Within Diamond use::
|
||||
|
||||
$ module load diffcalc
|
||||
$ diffcalc --help
|
||||
...
|
||||
$ diffcalc sixcircle
|
||||
|
||||
Trying it out
|
||||
-------------
|
||||
|
||||
Type ``demo.all()`` to see it working and then move try the following quick
|
||||
start guide::
|
||||
|
||||
>>> demo.all()
|
||||
...
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
To view help with orientation and then moving in hkl space::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
Configuring a UB calculation
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
To create a new UB-calculation::
|
||||
|
||||
==> newub 'example'
|
||||
==> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
where the basis is defined by Busing & Levy:
|
||||
|
||||
"...we choose the x axis parallel to b, the y axis in the plane of bl
|
||||
and b2, and the zaxis perpendicular to that plane."
|
||||
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
==> pos wl 1
|
||||
==> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
==> pos sixc [0 60 0 30 90 0]
|
||||
==> addref [0 0 1]
|
||||
|
||||
==> pos sixc [0 90 0 45 45 90]
|
||||
==> addref [0 1 1]
|
||||
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
==> checkub
|
||||
|
||||
To see the resulting UB-calculation::
|
||||
|
||||
==> ub
|
||||
|
||||
Setting the reference vector
|
||||
----------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
See the full `user manual<https://diffcalc.readthedocs.io`> for many more
|
||||
options and an explanation of what this all means.
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
==> con
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
==> con gam 0 mu 0 a_eq_b
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
==> sim hkl [0 1 1]
|
||||
|
||||
Move to reflection::
|
||||
|
||||
==> pos hkl [0 1 1]
|
||||
|
||||
==> pos sixc
|
||||
|
||||
|
||||
Scanning in hkl space
|
||||
---------------------
|
||||
|
||||
Scan an hkl axis (and read back settings)::
|
||||
|
||||
==> scan l 0 1 .2 sixc
|
||||
|
||||
Scan a constraint (and read back virtual angles and eta)::
|
||||
|
||||
==> con psi
|
||||
==> scan psi 70 110 10 hklverbose [0 1 1] eta
|
||||
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
==> UB_HELP_TABLE
|
||||
|
||||
Motion Commands
|
||||
---------------
|
||||
|
||||
==> HKL_HELP_TABLE
|
||||
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
|
||||
.. [Vlieg1993] Martin Lohmeier and Elias Vlieg. *Angle calculations for a six-circle
|
||||
surface x-ray diffractometer.* J. Appl. Cryst. (1993). **26**, 706-716. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1993/05/00/la0044/la0044.pdf>`__.
|
||||
|
||||
.. [Vlieg1998] Elias Vlieg. *A (2+3)-type surface diffractometer: mergence of the z-axis and
|
||||
(2+2)-type geometries.* J. Appl. Cryst. (1998). **31**, 198-203. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1998/02/00/pe0028/pe0028.pdf>`__.
|
||||
|
||||
.. [Willmott2011] C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans'l and
|
||||
P. R. Willmott. *Angle calculations for a (2+3)-type diffractometer: focus
|
||||
on area detectors.* J. Appl. Cryst. (2011). **44**, 73-83. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/2011/01/00/db5088/db5088.pdf>`__.
|
||||
5
script/__Lib/diffcalc_old/buckminster.cspec
Normal file
5
script/__Lib/diffcalc_old/buckminster.cspec
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><cs:cspec xmlns:cs="http://www.eclipse.org/buckminster/CSpec-1.0" name="diffcalc" componentType="buckminster" version="1.1.0">
|
||||
<cs:artifacts>
|
||||
<cs:public name="containsDocumentationSource"/>
|
||||
</cs:artifacts>
|
||||
</cs:cspec>
|
||||
9
script/__Lib/diffcalc_old/diffcalc.py
Executable file
9
script/__Lib/diffcalc_old/diffcalc.py
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
|
||||
from diffcmd.diffcalc_launcher import main
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
0
script/__Lib/diffcalc_old/diffcalc/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/dc/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/dc/__init__.py
Normal file
24
script/__Lib/diffcalc_old/diffcalc/dc/common.py
Normal file
24
script/__Lib/diffcalc_old/diffcalc/dc/common.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from diffcalc.util import allnum, command, DiffcalcException
|
||||
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError()
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
|
||||
def energy_to_wavelength(energy):
|
||||
try:
|
||||
return 12.39842 / energy
|
||||
except ZeroDivisionError:
|
||||
raise DiffcalcException(
|
||||
"Cannot calculate hkl position as Energy is set to 0")
|
||||
76
script/__Lib/diffcalc_old/diffcalc/dc/dcvlieg.py
Normal file
76
script/__Lib/diffcalc_old/diffcalc/dc/dcvlieg.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.hkl.vlieg.transform import VliegTransformSelector,\
|
||||
TransformCommands, VliegPositionTransformer
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
import diffcalc.hkl.vlieg.calc
|
||||
|
||||
|
||||
# reload to aid testing only
|
||||
import diffcalc.ub.ub as _ub
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
import diffcalc.hkl.vlieg.hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.vlieg.hkl import * # @UnusedWildImport
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
|
||||
_transform_selector = VliegTransformSelector()
|
||||
_transform_commands = TransformCommands(_transform_selector)
|
||||
_transformer = VliegPositionTransformer(settings.geometry, settings.hardware,
|
||||
_transform_selector)
|
||||
|
||||
transform = _transform_commands.transform
|
||||
transforma = _transform_commands.transforma
|
||||
transformb = _transform_commands.transformb
|
||||
transformc = _transform_commands.transformc
|
||||
|
||||
|
||||
on = 'on'
|
||||
off = 'off'
|
||||
auto = 'auto'
|
||||
manual = 'manual'
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
position, params = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
position = _transformer.transform(position)
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(position) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
((h, k, l), paramDict)=angles_to_hkl(self, (a1, a2,aN), energy=None)"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
|
||||
settings.ubcalc_strategy = diffcalc.hkl.vlieg.calc.VliegUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.vlieg.calc.vliegAnglesToHkl
|
||||
settings.include_sigtau = True
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
|
||||
hkl_commands_for_help = (_hkl.commands_for_help +
|
||||
_hardware.commands_for_help +
|
||||
['Transform',
|
||||
transform,
|
||||
transforma,
|
||||
transformb,
|
||||
transformc] +
|
||||
compile_extra_motion_commands_for_help())
|
||||
|
||||
47
script/__Lib/diffcalc_old/diffcalc/dc/dcwillmot.py
Normal file
47
script/__Lib/diffcalc_old/diffcalc/dc/dcwillmot.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# This file differs from dcyou in only two places
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
import diffcalc.hkl.willmott.calc
|
||||
|
||||
|
||||
# reload to aid testing only
|
||||
from diffcalc.ub import ub as _ub
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
from diffcalc.hkl.you import hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.willmot.hkl import * # @UnusedWildImport
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
(pos, params) = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(pos) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
((h, k, l), paramDict)=angles_to_hkl(self, (a1, a2,aN), energy=None)"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
settings.ubcalc_strategy = diffcalc.hkl.willmott.calc.WillmottHorizontalUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.willmott.calc.angles_to_hkl
|
||||
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
|
||||
hkl_commands_for_help = _hkl.commands_for_help + _hardware.commands_for_help + compile_extra_motion_commands_for_help()
|
||||
56
script/__Lib/diffcalc_old/diffcalc/dc/dcyou.py
Normal file
56
script/__Lib/diffcalc_old/diffcalc/dc/dcyou.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from diffcalc import settings
|
||||
from diffcalc.dc.common import energy_to_wavelength
|
||||
from diffcalc.dc.help import compile_extra_motion_commands_for_help
|
||||
|
||||
import diffcalc.hkl.you.calc
|
||||
settings.ubcalc_strategy = diffcalc.hkl.you.calc.YouUbCalcStrategy()
|
||||
settings.angles_to_hkl_function = diffcalc.hkl.you.calc.youAnglesToHkl
|
||||
settings.include_reference = True
|
||||
|
||||
# reload to aid testing only
|
||||
from diffcalc.ub import ub as _ub
|
||||
|
||||
reload(_ub)
|
||||
from diffcalc import hardware as _hardware
|
||||
#reload(_hardware)
|
||||
from diffcalc.hkl.you import hkl as _hkl
|
||||
reload(_hkl)
|
||||
|
||||
from diffcalc.ub.ub import * # @UnusedWildImport
|
||||
from diffcalc.hardware import * # @UnusedWildImport
|
||||
from diffcalc.hkl.you.hkl import * # @UnusedWildImport
|
||||
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles
|
||||
|
||||
return angle tuple and params dictionary
|
||||
|
||||
"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
|
||||
(pos, params) = hklcalc.hklToAngles(h, k, l, energy_to_wavelength(energy))
|
||||
angle_tuple = settings.geometry.internal_position_to_physical_angles(pos) # @UndefinedVariable
|
||||
angle_tuple = settings.hardware.cut_angles(angle_tuple) # @UndefinedVariable
|
||||
|
||||
return angle_tuple, params
|
||||
|
||||
|
||||
def angles_to_hkl(angleTuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
|
||||
Return hkl tuple and params dictionary
|
||||
|
||||
"""
|
||||
if energy is None:
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
i_pos = settings.geometry.physical_angles_to_internal_position(angleTuple) # @UndefinedVariable
|
||||
return hklcalc.anglesToHkl(i_pos, energy_to_wavelength(energy))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ub_commands_for_help = _ub.commands_for_help
|
||||
hkl_commands_for_help = _hkl.commands_for_help + _hardware.commands_for_help + compile_extra_motion_commands_for_help()
|
||||
161
script/__Lib/diffcalc_old/diffcalc/dc/help.py
Normal file
161
script/__Lib/diffcalc_old/diffcalc/dc/help.py
Normal file
@@ -0,0 +1,161 @@
|
||||
'''
|
||||
Created on 6 May 2016
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
from diffcalc import settings
|
||||
from diffcalc.gdasupport.scannable.sim import sim
|
||||
import textwrap
|
||||
from diffcalc.util import bold
|
||||
|
||||
|
||||
class ExternalCommand(object):
|
||||
"""Instances found in a command_list by format_command_help will
|
||||
result in documentation for a command without there actually being one.
|
||||
"""
|
||||
def __init__(self, docstring):
|
||||
"""Set the docstring that will be pulled off by format_command_help.
|
||||
"""
|
||||
self.__doc__ = docstring
|
||||
self.__name__ = ''
|
||||
|
||||
|
||||
WIDTH = 27
|
||||
INDENT = 3
|
||||
|
||||
|
||||
def format_command_help(command_list):
|
||||
|
||||
row_list = _command_list_to_table_cells(command_list)
|
||||
lines = []
|
||||
for row_cells in row_list:
|
||||
if len(row_cells) == 1:
|
||||
heading = row_cells[0]
|
||||
lines.append('')
|
||||
lines.append(bold(heading))
|
||||
lines.append('')
|
||||
elif len(row_cells) == 2:
|
||||
cell1, cell2 = row_cells
|
||||
|
||||
cell1_lines = textwrap.wrap(cell1, WIDTH, subsequent_indent=' ')
|
||||
cell2_lines = textwrap.wrap(cell2, 79 - INDENT - 3 - WIDTH)
|
||||
|
||||
first_line = True
|
||||
while cell1_lines or cell2_lines:
|
||||
line = ' ' * INDENT
|
||||
if cell1_lines:
|
||||
line += cell1_lines.pop(0).ljust(WIDTH)
|
||||
else:
|
||||
line += ' ' * (WIDTH)
|
||||
line += ' : ' if first_line else ' '
|
||||
if cell2_lines:
|
||||
line += cell2_lines.pop(0)
|
||||
lines.append(line)
|
||||
first_line = False
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def format_commands_for_rst_table(title, command_list):
|
||||
W1 = WIDTH # internal width
|
||||
W2 = 79 - W1 - 3 # internal width
|
||||
HORIZ_LINE = '+-' + '-' * W1 + '-+-' + '-' * W2 + '-+'
|
||||
|
||||
row_list = _command_list_to_table_cells(command_list)
|
||||
|
||||
lines = []
|
||||
|
||||
lines.append(HORIZ_LINE) # Top line
|
||||
for row_cells in row_list:
|
||||
if len(row_cells) == 1:
|
||||
lines.append('| ' + ('**' + row_cells[0] + '**').ljust(W1 + W2 + 3) + ' |')
|
||||
|
||||
elif len(row_cells) == 2:
|
||||
cmd_and_args = row_cells[0].split(' ', 1)
|
||||
cmd = cmd_and_args[0]
|
||||
args = cmd_and_args[1] if len(cmd_and_args) == 2 else ''
|
||||
cell1 = '**-- %s** %s' % (cmd, args)
|
||||
cell1_lines = textwrap.wrap(cell1, W1) #, subsequent_indent=' ')
|
||||
cell2_lines = textwrap.wrap(row_cells[1], W2)
|
||||
|
||||
while cell1_lines or cell2_lines:
|
||||
line = '| '
|
||||
line += (cell1_lines.pop(0) if cell1_lines else '').ljust(W1)
|
||||
line += ' | '
|
||||
line += (cell2_lines.pop(0) if cell2_lines else '').ljust(W2)
|
||||
line += ' |'
|
||||
lines.append(line)
|
||||
|
||||
else:
|
||||
assert False
|
||||
|
||||
lines.append(HORIZ_LINE)
|
||||
return lines
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _command_list_to_table_cells(command_list):
|
||||
row_list = []
|
||||
for obj in command_list:
|
||||
|
||||
if isinstance(obj, basestring): # group heading
|
||||
row_list.append([obj.upper()])
|
||||
|
||||
else: # individual command
|
||||
doc_before_empty_line = obj.__doc__.split('\n\n')[0]
|
||||
doc_lines = [s.strip() for s in doc_before_empty_line.split('\n')]
|
||||
for doc_line in doc_lines:
|
||||
if doc_line == '':
|
||||
continue
|
||||
if obj.__name__ in ('ub', 'hkl'):
|
||||
continue
|
||||
name, args, desc = _split_doc_line(doc_line)
|
||||
desc = desc.strip()
|
||||
args = args.strip()
|
||||
if desc and desc[-1] == '.':
|
||||
desc = desc[:-1]
|
||||
|
||||
row_list.append([name + (' ' if args else '') + args, desc])
|
||||
|
||||
return row_list
|
||||
|
||||
|
||||
def _split_doc_line(docLine):
|
||||
name, _, right = docLine.partition(' ')
|
||||
args, _, desc = right.partition('-- ')
|
||||
return name, args, desc
|
||||
|
||||
|
||||
def compile_extra_motion_commands_for_help():
|
||||
|
||||
_hwname = settings.hardware.name # @UndefinedVariable
|
||||
_angles = ', '.join(settings.hardware.get_axes_names()) # @UndefinedVariable
|
||||
|
||||
commands = []
|
||||
|
||||
commands.append('Motion')
|
||||
commands.append(sim)
|
||||
commands.append(ExternalCommand(
|
||||
'%(_hwname)s -- show Eularian position' % vars()))
|
||||
commands.append(ExternalCommand(
|
||||
'pos %(_hwname)s [%(_angles)s] -- move to Eularian position'
|
||||
'(None holds an axis still)' % vars()))
|
||||
commands.append(ExternalCommand(
|
||||
'sim %(_hwname)s [%(_angles)s] -- simulate move to Eulerian position'
|
||||
'%(_hwname)s' % vars()))
|
||||
|
||||
commands.append(ExternalCommand(
|
||||
'hkl -- show hkl position'))
|
||||
commands.append(ExternalCommand(
|
||||
'pos hkl [h k l] -- move to hkl position'))
|
||||
commands.append(ExternalCommand(
|
||||
'pos {h | k | l} val -- move h, k or l to val'))
|
||||
commands.append(ExternalCommand(
|
||||
'sim hkl [h k l] -- simulate move to hkl position'))
|
||||
|
||||
# if engine_name != 'vlieg':
|
||||
# pass
|
||||
# # TODO: remove sigtau command and 'Surface' string
|
||||
return commands
|
||||
322
script/__Lib/diffcalc_old/diffcalc/gdasupport/minigda/command.py
Normal file
322
script/__Lib/diffcalc_old/diffcalc/gdasupport/minigda/command.py
Normal file
@@ -0,0 +1,322 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
#try:
|
||||
# from gda.device import Scannable
|
||||
#except ImportError:
|
||||
# from diffcalc.gdasupport.minigda.scannable import Scannable
|
||||
from diffcalc.gdasupport.minigda.scannable import Scannable
|
||||
from diffcalc.util import getMessageFromException, allnum, bold
|
||||
import math
|
||||
|
||||
|
||||
ROOT_NAMESPACE_DICT = {}
|
||||
|
||||
class Pos(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__name__ = 'pos'
|
||||
|
||||
def __call__(self, *posargs):
|
||||
if len(posargs) == 0:
|
||||
|
||||
keys = dict(ROOT_NAMESPACE_DICT).keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
val = ROOT_NAMESPACE_DICT[key]
|
||||
if isinstance(val, Scannable):
|
||||
print self.posReturningReport(val)
|
||||
else:
|
||||
print self.posReturningReport(*posargs)
|
||||
|
||||
def posReturningReport(self, *posargs):
|
||||
# report position of this scannable
|
||||
if len(posargs) == 1:
|
||||
scannable = posargs[0]
|
||||
self._assert_scannable(scannable)
|
||||
return self._generatePositionReport(scannable)
|
||||
|
||||
# Move the scannable and report
|
||||
elif len(posargs) == 2:
|
||||
scannable = posargs[0]
|
||||
self._assert_scannable(scannable)
|
||||
# Move it
|
||||
scannable.asynchronousMoveTo(posargs[1])
|
||||
# TODO: minigda assumes all moves complete instantly, so no need
|
||||
# yet to check the move is complete
|
||||
return self._generatePositionReport(scannable)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invlaid arguements: 'pos [ scannable [ value ] ]'")
|
||||
|
||||
def _assert_scannable(self, obj):
|
||||
if not isinstance(obj, Scannable):
|
||||
raise TypeError(
|
||||
"The first argument to the pos command must be scannable. "
|
||||
"Not: " + str(type(obj)))
|
||||
|
||||
def _generatePositionReport(self, scannable):
|
||||
fieldNames = (tuple(scannable.getInputNames()) +
|
||||
tuple(scannable.getExtraNames()))
|
||||
# All scannables
|
||||
result = "%s:" % scannable.getName()
|
||||
result = result.ljust(10)
|
||||
try:
|
||||
pos = scannable.getPosition()
|
||||
except Exception, e:
|
||||
return result + "Error: %s" % getMessageFromException(e)
|
||||
if pos is None:
|
||||
return result + "---"
|
||||
# Single field scannable:
|
||||
if len(fieldNames) == 1:
|
||||
try:
|
||||
result += "%s" % scannable.formatPositionFields(pos)[0]
|
||||
except AttributeError:
|
||||
result += str(scannable())
|
||||
# Multi field scannable:
|
||||
else:
|
||||
try:
|
||||
formatted = scannable.formatPositionFields(pos)
|
||||
for name, formattedValue in zip(fieldNames, formatted):
|
||||
result += "%s: %s " % (name, formattedValue)
|
||||
except AttributeError:
|
||||
result += str(scannable())
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class ScanDataHandler:
|
||||
def __init__(self):
|
||||
self.scannables = None
|
||||
|
||||
def callAtScanStart(self, scannables):
|
||||
pass
|
||||
|
||||
def callWithScanPoint(self, PositionDictIndexedByScannable):
|
||||
pass
|
||||
|
||||
def callAtScanEnd(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScanDataPrinter(ScanDataHandler):
|
||||
|
||||
def __init__(self):
|
||||
self.first_point_printed = False
|
||||
self.widths = []
|
||||
self.scannables = []
|
||||
|
||||
def callAtScanStart(self, scannables):
|
||||
self.first_point_printed = False
|
||||
self.scannables = scannables
|
||||
|
||||
def print_first_point(self, position_dict):
|
||||
# also sets self.widths
|
||||
header_strings = []
|
||||
for scn in self.scannables:
|
||||
field_names = list(scn.getInputNames()) + list(scn.getExtraNames())
|
||||
if len(field_names) == 1:
|
||||
header_strings.append(scn.getName())
|
||||
else:
|
||||
for field_name in field_names:
|
||||
header_strings.append(field_name)
|
||||
|
||||
first_row_strings = []
|
||||
for scn in self.scannables:
|
||||
pos = position_dict[scn]
|
||||
first_row_strings.extend(scn.formatPositionFields(pos))
|
||||
|
||||
self.widths = []
|
||||
for header, pos_string in zip(header_strings, first_row_strings):
|
||||
self.widths.append(max(len(header), len(pos_string)))
|
||||
|
||||
header_cells = []
|
||||
for heading, width in zip(header_strings, self.widths):
|
||||
header_cells.append(heading.rjust(width))
|
||||
|
||||
underline_cells = ['-' * w for w in self.widths]
|
||||
|
||||
first_row_cells = []
|
||||
for pos, width in zip(first_row_strings, self.widths):
|
||||
first_row_cells.append(pos.rjust(width))
|
||||
|
||||
#table_width = sum(self.widths) + len(self.widths * 2) - 2
|
||||
lines = []
|
||||
#lines.append('=' * table_width)
|
||||
lines.append(bold(' '.join(header_cells)))
|
||||
lines.append(' '.join(underline_cells))
|
||||
lines.append(' '.join(first_row_cells))
|
||||
print '\n'.join(lines)
|
||||
|
||||
def callWithScanPoint(self, position_dict):
|
||||
if not self.first_point_printed:
|
||||
self.print_first_point(position_dict)
|
||||
self.first_point_printed = True
|
||||
else:
|
||||
row_strings = []
|
||||
for scn in self.scannables:
|
||||
pos = position_dict[scn]
|
||||
row_strings.extend(scn.formatPositionFields(pos))
|
||||
|
||||
row_cells = []
|
||||
for pos, width in zip(row_strings, self.widths):
|
||||
row_cells.append(pos.rjust(width))
|
||||
|
||||
print ' '.join(row_cells)
|
||||
|
||||
def callAtScanEnd(self):
|
||||
#table_width = sum(self.widths) + len(self.widths * 2) - 2
|
||||
#print '=' * table_width
|
||||
pass
|
||||
|
||||
|
||||
class Scan(object):
|
||||
class Group:
|
||||
def __init__(self, scannable):
|
||||
self.scannable = scannable
|
||||
self.args = []
|
||||
|
||||
def __cmp__(self, other):
|
||||
return(self.scannable.getLevel() - other.scannable.getLevel())
|
||||
|
||||
def __repr__(self):
|
||||
return "Group(%s, %s)" % (self.scannable.getName(), str(self.args))
|
||||
|
||||
def shouldTriggerLoop(self):
|
||||
return len(self.args) == 3
|
||||
|
||||
def __init__(self, scanDataHandlers):
|
||||
# scanDataHandlers should be list
|
||||
if type(scanDataHandlers) not in (tuple, list):
|
||||
scanDataHandlers = (scanDataHandlers,)
|
||||
self.dataHandlers = scanDataHandlers
|
||||
|
||||
def __call__(self, *scanargs):
|
||||
groups = self._parseScanArgsIntoScannableArgGroups(scanargs)
|
||||
groups = self._reorderInnerGroupsAccordingToLevel(groups)
|
||||
# Configure data handlers for a new scan
|
||||
for handler in self.dataHandlers: handler.callAtScanStart(
|
||||
[grp.scannable for grp in groups])
|
||||
# Perform the scan
|
||||
self._performScan(groups, currentRecursionLevel=0)
|
||||
# Inform data handlers of scan completion
|
||||
for handler in self.dataHandlers: handler.callAtScanEnd()
|
||||
|
||||
def _parseScanArgsIntoScannableArgGroups(self, scanargs):
|
||||
"""
|
||||
-> [ Group(scnA, (a1, a2, a2)), Group((scnB), (b1)), ...
|
||||
... Group((scnC),()), Group((scnD),(d1))]
|
||||
"""
|
||||
result = []
|
||||
if not isinstance(scanargs[0], Scannable):
|
||||
raise TypeError("First scan argument must be a scannable")
|
||||
|
||||
# Parse out scannables followed by non-scannable args
|
||||
for arg in scanargs:
|
||||
if isinstance(arg, Scannable):
|
||||
result.append(Scan.Group(arg))
|
||||
else:
|
||||
result[-1].args.append(arg)
|
||||
return result
|
||||
|
||||
def _reorderInnerGroupsAccordingToLevel(self, groups):
|
||||
# Find the first group not to trigger a loop
|
||||
for idx, group in enumerate(groups):
|
||||
if not group.shouldTriggerLoop():
|
||||
break
|
||||
latter = groups[idx:]; latter.sort() # Horrible hack not needed in python 3!
|
||||
return groups[:idx] + latter
|
||||
|
||||
def _performScan(self, groups, currentRecursionLevel):
|
||||
# groups[currentRecursionLevel:] will start with either:
|
||||
# a) A loop triggering group
|
||||
# b) A number (possibly 0) of non-loop triggering groups
|
||||
unprocessedGroups = groups[currentRecursionLevel:]
|
||||
|
||||
# 1) If first remaining group should trigger a loop, perform this loop,
|
||||
# recursively calling this method on the remaining groups
|
||||
if len(unprocessedGroups) > 0:
|
||||
first = unprocessedGroups[0]
|
||||
# If groups starts with a request to loop:
|
||||
if first.shouldTriggerLoop():
|
||||
posList = self._frange(first.args[0], first.args[1], first.args[2])
|
||||
for pos in posList:
|
||||
first.scannable.asynchronousMoveTo(pos)
|
||||
# TODO: Should wait. minigda assumes all moves complete immediately
|
||||
self._performScan(groups, currentRecursionLevel + 1)
|
||||
return
|
||||
|
||||
# 2) Move all non-loop triggering groups (may be zero)
|
||||
self._moveNonLoopTriggeringGroups(unprocessedGroups)
|
||||
|
||||
# 3) Sample position of all scannables
|
||||
posDict = self._samplePositionsOfAllScannables(groups)
|
||||
|
||||
# 4) Inform the data handlers that this point has been recorded
|
||||
for handler in self.dataHandlers: handler.callWithScanPoint(posDict)
|
||||
|
||||
def _moveNonLoopTriggeringGroups(self, groups):
|
||||
# TODO: Should wait. minigda assumes all moves complete immediately. groups could be zero lengthed.
|
||||
for grp in groups:
|
||||
if len(grp.args) == 0:
|
||||
pass
|
||||
elif len(grp.args) == 1:
|
||||
grp.scannable.asynchronousMoveTo(grp.args[0])
|
||||
elif len(grp.args) == 2:
|
||||
raise Exception("Scannables followed by two args not supported by minigda's scan command ")
|
||||
else:
|
||||
raise Exception("Scannable: %s args%s" % (grp.scannable, str(grp.args)))
|
||||
|
||||
def _samplePositionsOfAllScannables(self, groups):
|
||||
posDict = {}
|
||||
for grp in groups:
|
||||
posDict[grp.scannable] = grp.scannable.getPosition()
|
||||
return posDict
|
||||
|
||||
def _frange(self, limit1, limit2, increment):
|
||||
"""Range function that accepts floats (and integers).
|
||||
"""
|
||||
# limit1 = float(limit1)
|
||||
# limit2 = float(limit2)
|
||||
try:
|
||||
increment = float(increment)
|
||||
except TypeError:
|
||||
raise TypeError(
|
||||
"Only scaler values are supported, not GDA format vectors.")
|
||||
count = int(math.ceil(((limit2 - limit1) + increment / 100.) / increment))
|
||||
result = []
|
||||
for n in range(count):
|
||||
result.append(limit1 + n * increment)
|
||||
return result
|
||||
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError()
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
@@ -0,0 +1,511 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableBase
|
||||
except ImportError:
|
||||
class Scannable(object):
|
||||
pass
|
||||
|
||||
class ScannableBase(Scannable):
|
||||
"""Implemtation of a subset of OpenGDA's Scannable interface
|
||||
"""
|
||||
|
||||
level = 5
|
||||
inputNames = []
|
||||
extraNames = []
|
||||
outputFormat = []
|
||||
|
||||
def isBusy(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def rawGetPosition(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def rawAsynchronousMoveTo(self, newpos):
|
||||
raise NotImplementedError()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
while self.isBusy():
|
||||
time.sleep(.1)
|
||||
|
||||
def getPosition(self):
|
||||
return self.rawGetPosition()
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
self.rawAsynchronousMoveTo(newpos)
|
||||
|
||||
def atScanStart(self):
|
||||
pass
|
||||
|
||||
def atScanEnd(self):
|
||||
pass
|
||||
|
||||
def atCommandFailure(self):
|
||||
pass
|
||||
|
||||
###
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formattedValues = self.formatPositionFields(pos)
|
||||
if len(tuple(self.getInputNames()) + tuple(self.getExtraNames())) > 1:
|
||||
result = self.getName() + ': '
|
||||
else:
|
||||
result = ''
|
||||
|
||||
names = tuple(self.getInputNames()) + tuple(self.getExtraNames())
|
||||
for name, val in zip(names, formattedValues):
|
||||
result += ' ' + name + ': ' + val
|
||||
return result
|
||||
###
|
||||
|
||||
def formatPositionFields(self, pos):
|
||||
"""Returns position as array of formatted strings"""
|
||||
# Make sure pos is a tuple or list
|
||||
if type(pos) not in (tuple, list):
|
||||
pos = tuple([pos])
|
||||
|
||||
# Sanity check
|
||||
if len(pos) != len(self.getOutputFormat()):
|
||||
raise Exception(
|
||||
"In scannable '%s':number of position fields differs from "
|
||||
"number format strings specified" % self.getName())
|
||||
|
||||
result = []
|
||||
for field, format in zip(pos, self.getOutputFormat()):
|
||||
if field is None:
|
||||
result.append('???')
|
||||
else:
|
||||
s = (format % field)
|
||||
## if width!=None:
|
||||
## s = s.ljust(width)
|
||||
result.append(s)
|
||||
|
||||
return result
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def setName(self, value):
|
||||
self.name = value
|
||||
|
||||
def getLevel(self):
|
||||
return self.level
|
||||
|
||||
def setLevel(self, value):
|
||||
self.level = value
|
||||
|
||||
def getInputNames(self):
|
||||
return self.inputNames
|
||||
|
||||
def setInputNames(self, value):
|
||||
self.inputNames = value
|
||||
|
||||
def getExtraNames(self):
|
||||
return self.extraNames
|
||||
|
||||
def setExtraNames(self, value):
|
||||
self.extraNames = value
|
||||
|
||||
def getOutputFormat(self):
|
||||
return self.outputFormat
|
||||
|
||||
def setOutputFormat(self, value):
|
||||
if type(value) not in (tuple, list):
|
||||
raise TypeError(
|
||||
"%s.setOutputFormat() expects tuple or list; not %s" %
|
||||
(self.getName(), str(type(value))))
|
||||
self.outputFormat = value
|
||||
|
||||
def __call__(self, newpos=None):
|
||||
if newpos is None:
|
||||
return self.getPosition()
|
||||
self.asynchronousMoveTo(newpos)
|
||||
|
||||
class ScannableAdapter(Scannable):
|
||||
'''Wrap up a Scannable and give it a new name and optionally an offset
|
||||
(added to the delegate when reading up and subtracting when setting down
|
||||
'''
|
||||
|
||||
def __init__(self, delegate_scn, name, offset=0):
|
||||
assert len(delegate_scn.getInputNames()) == 1
|
||||
assert len(delegate_scn.getExtraNames()) == 0
|
||||
self.delegate_scn = delegate_scn
|
||||
self.name = name
|
||||
self.offset = offset
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.delegate_scn, name)
|
||||
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getInputNames(self):
|
||||
return [self.name]
|
||||
|
||||
def getPosition(self):
|
||||
return self.delegate_scn.getPosition() + self.offset
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
self.delegate_scn.asynchronousMoveTo(newpos - self.offset)
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formatted_values = self.delegate_scn.formatPositionFields(pos)
|
||||
return self.name + ': ' + formatted_values[0] + ' ' + self.get_hint()
|
||||
|
||||
def get_hint(self):
|
||||
if self.offset:
|
||||
offset_hint = ' + ' if self.offset >= 0 else ' - '
|
||||
offset_hint += str(self.offset)
|
||||
else:
|
||||
offset_hint = ''
|
||||
return '(%s%s)' % (self.delegate_scn.name, offset_hint)
|
||||
|
||||
def __call__(self, newpos=None):
|
||||
if newpos is None:
|
||||
return self.getPosition()
|
||||
self.asynchronousMoveTo(newpos)
|
||||
|
||||
class SingleFieldDummyScannable(ScannableBase):
|
||||
|
||||
def __init__(self, name, initial_position=0.):
|
||||
self.name = name
|
||||
self.inputNames = [name]
|
||||
self.outputFormat = ['% 6.4f']
|
||||
self.level = 3
|
||||
self._current_position = float(initial_position)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
self._current_position = float(new_position)
|
||||
|
||||
def getPosition(self):
|
||||
return self._current_position
|
||||
|
||||
|
||||
class DummyPD(SingleFieldDummyScannable):
|
||||
"""For compatability with the gda's dummy_pd module"""
|
||||
pass
|
||||
|
||||
|
||||
class MultiInputExtraFieldsDummyScannable(ScannableBase):
|
||||
'''Multi input Dummy PD Class supporting input and extra fields'''
|
||||
def __init__(self, name, inputNames, extraNames):
|
||||
self.setName(name)
|
||||
self.setInputNames(inputNames)
|
||||
self.setExtraNames(extraNames)
|
||||
self.setOutputFormat(['%6.4f'] * (len(inputNames) + len(extraNames)))
|
||||
self.setLevel(3)
|
||||
self.currentposition = [0.0] * len(inputNames)
|
||||
|
||||
def isBusy(self):
|
||||
return 0
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
if type(new_position) == type(1) or type(new_position) == type(1.0):
|
||||
new_position = [new_position]
|
||||
msg = "Wrong new_position size"
|
||||
assert len(new_position) == len(self.currentposition), msg
|
||||
for i in range(len(new_position)):
|
||||
if new_position[i] != None:
|
||||
self.currentposition[i] = float(new_position[i])
|
||||
|
||||
def getPosition(self):
|
||||
extraValues = range(100, 100 + (len(self.getExtraNames())))
|
||||
return self.currentposition + map(float, extraValues)
|
||||
|
||||
|
||||
class ZeroInputExtraFieldsDummyScannable(ScannableBase):
|
||||
'''Zero input/extra field dummy pd
|
||||
'''
|
||||
def __init__(self, name):
|
||||
self.setName(name)
|
||||
self.setInputNames([])
|
||||
self.setOutputFormat([])
|
||||
|
||||
def isBusy(self):
|
||||
return 0
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
pass
|
||||
|
||||
def getPosition(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScannableGroup(ScannableBase):
|
||||
"""wraps up motors. Simulates motors if non given."""
|
||||
|
||||
def __init__(self, name, motorList):
|
||||
|
||||
self.setName(name)
|
||||
# Set input format
|
||||
motorNames = []
|
||||
for scn in motorList:
|
||||
motorNames.append(scn.getName())
|
||||
self.setInputNames(motorNames)
|
||||
# Set output format
|
||||
format = []
|
||||
for motor in motorList:
|
||||
format.append(motor.getOutputFormat()[0])
|
||||
self.setOutputFormat(format)
|
||||
self.__motors = motorList
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
# if input has any Nones, then replace these with the current positions
|
||||
if None in position:
|
||||
position = list(position)
|
||||
current = self.getPosition()
|
||||
for idx, val in enumerate(position):
|
||||
if val is None:
|
||||
position[idx] = current[idx]
|
||||
|
||||
for scn, pos in zip(self.__motors, position):
|
||||
scn.asynchronousMoveTo(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return [scn.getPosition() for scn in self.__motors]
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.__motors:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
|
||||
def configure(self):
|
||||
pass
|
||||
|
||||
|
||||
class ScannableMotionWithScannableFieldsBase(ScannableBase):
|
||||
'''
|
||||
This extended version of ScannableMotionBase contains a
|
||||
completeInstantiation() method which adds a dictionary of
|
||||
MotionScannableParts to an instance. Each part allows one of the
|
||||
instances fields to be interacted with like it itself is a scannable.
|
||||
Fields are dynamically added to the instance linking to these parts
|
||||
allowing dotted access from Jython. They may also be accessed using
|
||||
Jython container access methods (via the __getitem__() method). To acess
|
||||
them from Jave use the getComponent(name) method.
|
||||
|
||||
When moving a part (via either a pos or scan command), the part calls
|
||||
the parent to perform the actual task. The parts asynchronousMoveto
|
||||
command will call the parent with a list of None values except for the
|
||||
field it represents which will be passed the desired position value.
|
||||
|
||||
The asynchronousMoveTo method in class that inherats from this base
|
||||
class then must handle these Nones. In some cases the method may
|
||||
actually be able to move the underlying system assoiciated with one
|
||||
field individually from others. If this is not possible the best
|
||||
behaviour may be to simply not support this beahviour and exception or
|
||||
alternatively to substitute the None values with actual current position
|
||||
of parent's scannables associated fields.
|
||||
|
||||
ScannableMotionBaseWithMemory() inherats from this calss and provides a
|
||||
solution useful for some scenarious: it keeps track of the last position
|
||||
moved to, and replaces the Nones in an asynchronousMoveTo request with
|
||||
these values. There are a number of dangers associated with this which
|
||||
are addressed in that class's documentation, but it provides a way to
|
||||
move one axis within a group of non-orthogonal axis while keeping the
|
||||
others still.
|
||||
'''
|
||||
childrenDict = {}
|
||||
numInputFields = None
|
||||
numExtraFields = None
|
||||
|
||||
def completeInstantiation(self):
|
||||
'''This method should be called at the end of all user defined
|
||||
consructors'''
|
||||
# self.validate()
|
||||
self.numInputFields = len(self.getInputNames())
|
||||
self.numExtraFields = len(self.getExtraNames())
|
||||
self.addScannableParts()
|
||||
self.autoCompletePartialMoveToTargets = False
|
||||
self.positionAtScanStart = None
|
||||
|
||||
def setAutoCompletePartialMoveToTargets(self, b):
|
||||
self.autoCompletePartialMoveToTargets = b
|
||||
|
||||
def atScanStart(self):
|
||||
self.positionAtScanStart = self.getPosition()
|
||||
|
||||
def atCommandFailure(self):
|
||||
self.positionAtScanStart = None
|
||||
|
||||
def atScanEnd(self):
|
||||
self.positionAtScanStart = None
|
||||
|
||||
###
|
||||
|
||||
def __repr__(self):
|
||||
pos = self.getPosition()
|
||||
formattedValues = self.formatPositionFields(pos)
|
||||
if len(tuple(self.getInputNames()) + tuple(self.getExtraNames())) > 1:
|
||||
result = self.getName() + ': '
|
||||
else:
|
||||
result = ''
|
||||
|
||||
names = tuple(self.getInputNames()) + tuple(self.getExtraNames())
|
||||
for name, val in zip(names, formattedValues):
|
||||
result += ' ' + name + ': ' + val
|
||||
return result
|
||||
###
|
||||
|
||||
def formatPositionFields(self, pos):
|
||||
"""Returns position as array of formatted strings"""
|
||||
# Make sure pos is a tuple or list
|
||||
if type(pos) not in (tuple, list):
|
||||
pos = tuple([pos])
|
||||
|
||||
# Sanity check
|
||||
if len(pos) != len(self.getOutputFormat()):
|
||||
raise Exception(
|
||||
"In scannable '%s':number of position fields differs from "
|
||||
"number format strings specified" % self.getName())
|
||||
|
||||
result = []
|
||||
for field, format in zip(pos, self.getOutputFormat()):
|
||||
if field is None:
|
||||
result.append('???')
|
||||
else:
|
||||
s = (format % field)
|
||||
## if width!=None:
|
||||
## s = s.ljust(width)
|
||||
result.append(s)
|
||||
|
||||
return result
|
||||
|
||||
###
|
||||
|
||||
def addScannableParts(self):
|
||||
'''
|
||||
Creates an array of MotionScannableParts each of which allows access to
|
||||
the scannable's fields. See this class's documentation for more info.
|
||||
'''
|
||||
self.childrenDict = {}
|
||||
# Add parts to access the input fields
|
||||
for index in range(len(self.getInputNames())):
|
||||
scannableName = self.getInputNames()[index]
|
||||
self.childrenDict[scannableName] = self.MotionScannablePart(
|
||||
scannableName, index, self, isInputField=1)
|
||||
|
||||
# Add parts to access the extra fields
|
||||
for index in range(len(self.getExtraNames())):
|
||||
scannableName = self.getExtraNames()[index]
|
||||
self.childrenDict[scannableName] = self.MotionScannablePart(
|
||||
scannableName, index + len(self.getInputNames()),
|
||||
self, isInputField=0)
|
||||
|
||||
def asynchronousMoveTo(self, newpos):
|
||||
if self.autoCompletePartialMoveToTargets:
|
||||
newpos = self.completePosition(newpos)
|
||||
ScannableBase.asynchronousMoveTo(self, newpos)
|
||||
|
||||
def completePosition(self, position):
|
||||
'''
|
||||
If position contains any null or None values, these are replaced with
|
||||
the corresponding fields from the scannables current position and then
|
||||
returned.'''
|
||||
# Just return position if it does not need padding
|
||||
if None not in position:
|
||||
return position
|
||||
if self.positionAtScanStart is not None:
|
||||
basePosition = self.positionAtScanStart
|
||||
else:
|
||||
basePosition = self.getPosition()[:self.numInputFields]
|
||||
for i in range(self.numInputFields):
|
||||
if position[i] is None:
|
||||
position[i] = basePosition[i]
|
||||
return position
|
||||
|
||||
def __getattr__(self, name):
|
||||
try:
|
||||
return self.childrenDict[name]
|
||||
except:
|
||||
raise AttributeError("No child named:" + name)
|
||||
|
||||
def __getitem__(self, key):
|
||||
'''Provides container like access from Jython'''
|
||||
return self.childrenDict[key]
|
||||
|
||||
def getPart(self, name):
|
||||
'''Returns the a compnent scannable'''
|
||||
return self.childrenDict[name]
|
||||
|
||||
class MotionScannablePart(ScannableBase):
|
||||
'''
|
||||
A scannable to be placed in the parent's childrenDict that allows
|
||||
access to the parent's individual fields.'''
|
||||
|
||||
def __init__(self, scannableName, index, parentScannable,
|
||||
isInputField):
|
||||
self.setName(scannableName)
|
||||
if isInputField:
|
||||
self.setInputNames([scannableName])
|
||||
else:
|
||||
self.setExtraNames([scannableName])
|
||||
self.index = index
|
||||
self.parentScannable = parentScannable
|
||||
self.setOutputFormat(
|
||||
[self.parentScannable.getOutputFormat()[index]])
|
||||
|
||||
def isBusy(self):
|
||||
return self.parentScannable.isBusy()
|
||||
|
||||
def asynchronousMoveTo(self, new_position):
|
||||
if self.parentScannable.isBusy():
|
||||
raise Exception(
|
||||
self.parentScannable.getName() + "." + self.getName() +
|
||||
" cannot be moved because " +
|
||||
self.parentScannable.getName() + " is already moving")
|
||||
|
||||
toMoveTo = [None] * len(self.parentScannable.getInputNames())
|
||||
toMoveTo[self.index] = new_position
|
||||
self.parentScannable.asynchronousMoveTo(toMoveTo)
|
||||
|
||||
def moveTo(self, new_position):
|
||||
self.asynchronousMoveTo(new_position)
|
||||
self.waitWhileBusy()
|
||||
|
||||
def getPosition(self):
|
||||
return self.parentScannable.getPosition()[self.index]
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
# Get the name of this field
|
||||
# (assume its an input field first and correct if wrong)
|
||||
name = self.getInputNames()[0]
|
||||
|
||||
if name == 'value':
|
||||
name = self.getExtraNames()[0]
|
||||
parentName = self.parentScannable.getName()
|
||||
return parentName + "." + name + " : " + str(self.getPosition())
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import PseudoDevice
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as PseudoDevice
|
||||
|
||||
|
||||
class ScannableGroup(PseudoDevice):
|
||||
|
||||
def __init__(self, name, motorList):
|
||||
|
||||
self.setName(name)
|
||||
# Set input format
|
||||
motorNames = []
|
||||
for scn in motorList:
|
||||
motorNames.append(scn.getName())
|
||||
self.setInputNames(motorNames)
|
||||
# Set output format
|
||||
format = []
|
||||
for motor in motorList:
|
||||
format.append(motor.getOutputFormat()[0])
|
||||
self.setOutputFormat(format)
|
||||
self.__motors = motorList
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
# if input has any Nones, then replace these with the current positions
|
||||
if None in position:
|
||||
position = list(position)
|
||||
current = self.getPosition()
|
||||
for idx, val in enumerate(position):
|
||||
if val is None:
|
||||
position[idx] = current[idx]
|
||||
|
||||
for scn, pos in zip(self.__motors, position):
|
||||
scn.asynchronousMoveTo(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return [scn.getPosition() for scn in self.__motors]
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.__motors:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,126 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
from diffcalc.util import getMessageFromException
|
||||
|
||||
# TODO: Split into a base class when making other scannables
|
||||
|
||||
|
||||
class DiffractometerScannableGroup(ScannableMotionBase):
|
||||
""""
|
||||
Wraps up a scannableGroup of axis to tweak the way the resulting
|
||||
object is displayed and to add a simulate move to method.
|
||||
|
||||
The scannable group should have the same geometry as that expected
|
||||
by the diffractometer hardware geometry used in the diffraction
|
||||
calculator.
|
||||
|
||||
The optional parameter slaveDriver can be used to provide a
|
||||
slave_driver. This is useful for triggering a move of an incidental
|
||||
axis whose position depends on that of the diffractometer, but whose
|
||||
position need not be included in the DiffractometerScannableGroup
|
||||
itself. This parameter is exposed as a field and can be set or
|
||||
cleared to null at will without effecting the core calculation code.
|
||||
"""
|
||||
|
||||
def __init__(self, name, diffcalc_module, scannableGroup,
|
||||
slave_driver=None, hint_generator=None):
|
||||
# if motorList is None, will create a dummy __group
|
||||
self.diffcalc_module = diffcalc_module
|
||||
self.__group = scannableGroup
|
||||
self.slave_driver = slave_driver
|
||||
self.setName(name)
|
||||
self.hint_generator = hint_generator
|
||||
|
||||
def getInputNames(self):
|
||||
return self.__group.getInputNames()
|
||||
|
||||
def getExtraNames(self):
|
||||
if self.slave_driver is None:
|
||||
return []
|
||||
else:
|
||||
return self.slave_driver.getScannableNames()
|
||||
|
||||
def getOutputFormat(self):
|
||||
if self.slave_driver is None:
|
||||
slave_formats = []
|
||||
else:
|
||||
slave_formats = self.slave_driver.getScannableNames()
|
||||
return list(self.__group.getOutputFormat()) + slave_formats
|
||||
|
||||
def asynchronousMoveTo(self, position):
|
||||
self.__group.asynchronousMoveTo(position)
|
||||
if self.slave_driver is not None:
|
||||
self.slave_driver.triggerAsynchronousMove(position)
|
||||
|
||||
def getPosition(self):
|
||||
if self.slave_driver is None:
|
||||
slave_positions = []
|
||||
else:
|
||||
slave_positions = self.slave_driver.getPositions()
|
||||
return list(self.__group.getPosition()) + list(slave_positions)
|
||||
|
||||
def isBusy(self):
|
||||
if self.slave_driver is None:
|
||||
return self.__group.isBusy()
|
||||
else:
|
||||
return self.__group.isBusy() or self.slave_driver.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
self.__group.waitWhileBusy()
|
||||
if self.slave_driver is not None:
|
||||
self.slave_driver.waitWhileBusy()
|
||||
|
||||
def simulateMoveTo(self, pos):
|
||||
if len(pos) != len(self.getInputNames()):
|
||||
raise ValueError('Wrong number of inputs')
|
||||
try:
|
||||
(hkl, params) = self.diffcalc_module.angles_to_hkl(pos)
|
||||
except Exception, e:
|
||||
return "Error: %s" % getMessageFromException(e)
|
||||
width = max(len(k) for k in params)
|
||||
|
||||
lines = ([' ' + 'hkl'.rjust(width) + ' : % 9.4f %.4f %.4f' %
|
||||
(hkl[0], hkl[1], hkl[2])])
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __repr__(self):
|
||||
position = self.getPosition()
|
||||
names = list(self.getInputNames()) + list(self.getExtraNames())
|
||||
if self.hint_generator is None:
|
||||
hint_list = [''] * len(self.getInputNames())
|
||||
else:
|
||||
hint_list = self.hint_generator()
|
||||
|
||||
lines = [self.name + ':']
|
||||
width = max(len(k) for k in names)
|
||||
fmt = ' %' + str(width) + 's : % 9.4f %s'
|
||||
for name, pos, hint in zip(names, position, hint_list):
|
||||
lines.append(fmt % (name, pos, hint))
|
||||
lines[len(self.getInputNames())] += '\n'
|
||||
return '\n'.join(lines)
|
||||
135
script/__Lib/diffcalc_old/diffcalc/gdasupport/scannable/hkl.py
Normal file
135
script/__Lib/diffcalc_old/diffcalc/gdasupport/scannable/hkl.py
Normal file
@@ -0,0 +1,135 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
import platform
|
||||
|
||||
DEBUG = False
|
||||
|
||||
try:
|
||||
from gda.device.scannable.scannablegroup import \
|
||||
ScannableMotionWithScannableFieldsBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableMotionWithScannableFieldsBase
|
||||
|
||||
from diffcalc.util import getMessageFromException, DiffcalcException
|
||||
|
||||
|
||||
class _DynamicDocstringMetaclass(type):
|
||||
|
||||
def _get_doc(self):
|
||||
return Hkl.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
|
||||
class Hkl(ScannableMotionWithScannableFieldsBase):
|
||||
|
||||
if platform.system() != 'Java':
|
||||
__metaclass__ = _DynamicDocstringMetaclass # TODO: Removed to fix Jython
|
||||
|
||||
dynamic_docstring = 'Hkl Scannable'
|
||||
|
||||
def _get_doc(self):
|
||||
return Hkl.dynamic_docstring
|
||||
|
||||
__doc__ = property(_get_doc) # @ReservedAssignment
|
||||
|
||||
def __init__(self, name, diffractometerObject, diffcalcObject,
|
||||
virtualAnglesToReport=None):
|
||||
self.diffhw = diffractometerObject
|
||||
self._diffcalc = diffcalcObject
|
||||
if type(virtualAnglesToReport) is str:
|
||||
virtualAnglesToReport = (virtualAnglesToReport,)
|
||||
self.vAngleNames = virtualAnglesToReport
|
||||
|
||||
self.setName(name)
|
||||
self.setInputNames(['h', 'k', 'l'])
|
||||
self.setOutputFormat(['%7.5f'] * 3)
|
||||
if self.vAngleNames:
|
||||
self.setExtraNames(self.vAngleNames)
|
||||
self.setOutputFormat(['%7.5f'] * (3 + len(self.vAngleNames)))
|
||||
|
||||
self.completeInstantiation()
|
||||
self.setAutoCompletePartialMoveToTargets(True)
|
||||
self.dynamic_class_doc = 'Hkl Scannable xyz'
|
||||
|
||||
def rawAsynchronousMoveTo(self, hkl):
|
||||
if len(hkl) != 3: raise ValueError('Hkl device expects three inputs')
|
||||
try:
|
||||
(pos, _) = self._diffcalc.hkl_to_angles(hkl[0], hkl[1], hkl[2])
|
||||
except DiffcalcException, e:
|
||||
if DEBUG:
|
||||
raise
|
||||
else:
|
||||
raise DiffcalcException(e.message)
|
||||
self.diffhw.asynchronousMoveTo(pos)
|
||||
|
||||
def rawGetPosition(self):
|
||||
pos = self.diffhw.getPosition() # a tuple
|
||||
(hkl , params) = self._diffcalc.angles_to_hkl(pos)
|
||||
result = list(hkl)
|
||||
if self.vAngleNames:
|
||||
for vAngleName in self.vAngleNames:
|
||||
result.append(params[vAngleName])
|
||||
return result
|
||||
|
||||
def getFieldPosition(self, i):
|
||||
return self.getPosition()[i]
|
||||
|
||||
def isBusy(self):
|
||||
return self.diffhw.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return self.diffhw.waitWhileBusy()
|
||||
|
||||
def simulateMoveTo(self, hkl):
|
||||
if type(hkl) not in (list, tuple):
|
||||
raise ValueError('Hkl device expects three inputs')
|
||||
if len(hkl) != 3:
|
||||
raise ValueError('Hkl device expects three inputs')
|
||||
(pos, params) = self._diffcalc.hkl_to_angles(hkl[0], hkl[1], hkl[2])
|
||||
|
||||
width = max(len(k) for k in (params.keys() + list(self.diffhw.getInputNames())))
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
|
||||
lines = [self.diffhw.getName() + ' would move to:']
|
||||
for idx, name in enumerate(self.diffhw.getInputNames()):
|
||||
lines.append(fmt % (name, pos[idx]))
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
lines = ['hkl:']
|
||||
pos = self.diffhw.getPosition()
|
||||
try:
|
||||
(hkl, params) = self._diffcalc.angles_to_hkl(pos)
|
||||
except Exception, e:
|
||||
return "<hkl: %s>" % getMessageFromException(e)
|
||||
|
||||
width = max(len(k) for k in params)
|
||||
lines.append(' ' + 'hkl'.rjust(width) + ' : %9.4f %.4f %.4f' % (hkl[0], hkl[1], hkl[2]))
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
fmt = ' %' + str(width) + 's : % 9.4f'
|
||||
for k in sorted(params):
|
||||
lines.append(fmt % (k, params[k]))
|
||||
return '\n'.join(lines)
|
||||
@@ -0,0 +1,47 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
|
||||
class MockMotor(ScannableMotionBase):
|
||||
|
||||
def __init__(self, name='mock'):
|
||||
self.pos = 0.0
|
||||
self._busy = False
|
||||
self.name = name
|
||||
|
||||
def asynchronousMoveTo(self, pos):
|
||||
self._busy = True
|
||||
self.pos = float(pos)
|
||||
|
||||
def getPosition(self):
|
||||
return self.pos
|
||||
|
||||
def isBusy(self):
|
||||
return self._busy
|
||||
|
||||
def makeNotBusy(self):
|
||||
self._busy = False
|
||||
|
||||
def getOutputFormat(self):
|
||||
return ['%f']
|
||||
@@ -0,0 +1,45 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gda.device.scannable import ScannableMotionBase
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as ScannableMotionBase
|
||||
|
||||
|
||||
class DiffractionCalculatorParameter(ScannableMotionBase):
|
||||
|
||||
def __init__(self, name, parameterName, parameter_manager):
|
||||
|
||||
self.parameter_manager = parameter_manager
|
||||
self.parameterName = parameterName
|
||||
|
||||
self.setName(name)
|
||||
self.setInputNames([parameterName])
|
||||
self.setOutputFormat(['%5.5f'])
|
||||
self.setLevel(3)
|
||||
|
||||
def asynchronousMoveTo(self, value):
|
||||
self.parameter_manager.set_constraint(self.parameterName, value)
|
||||
|
||||
def getPosition(self):
|
||||
return self.parameter_manager.get_constraint(self.parameterName)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
@@ -0,0 +1,21 @@
|
||||
'''
|
||||
Created on 7 May 2016
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
from diffcalc.util import allnum
|
||||
|
||||
def sim(scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The first argument does not support simulated moves")
|
||||
@@ -0,0 +1,139 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
from math import sqrt, pi, exp
|
||||
|
||||
try:
|
||||
from gda.device.scannable import PseudoDevice
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import \
|
||||
ScannableBase as PseudoDevice
|
||||
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.hkl.you.calc import youAnglesToHkl
|
||||
from diffcalc.hkl.vlieg.calc import vliegAnglesToHkl
|
||||
from diffcalc.hkl.you.geometry import calcCHI, calcPHI
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class Equation(object):
|
||||
|
||||
def __call__(self, dh, dk, dl):
|
||||
raise Exception('Abstract')
|
||||
|
||||
def __str__(self):
|
||||
"Abstract equation"
|
||||
|
||||
|
||||
class Gaussian(Equation):
|
||||
|
||||
def __init__(self, variance):
|
||||
self.variance = float(variance)
|
||||
|
||||
def __call__(self, dh, dk, dl):
|
||||
dr_squared = dh * dh + dk * dk + dl * dl
|
||||
return (1 / sqrt(2 * pi * self.variance) *
|
||||
exp(-dr_squared / (2 * self.variance)))
|
||||
|
||||
|
||||
class SimulatedCrystalCounter(PseudoDevice):
|
||||
|
||||
def __init__(self, name, diffractometerScannable, geometryPlugin,
|
||||
wavelengthScannable, equation=Gaussian(.01), engine='you'):
|
||||
self.setName(name)
|
||||
self.setInputNames([name + '_count'])
|
||||
self.setOutputFormat(['%7.5f'])
|
||||
self.exposureTime = 1
|
||||
self.pause = True
|
||||
self.diffractometerScannable = diffractometerScannable
|
||||
self.geometry = geometryPlugin
|
||||
self.wavelengthScannable = wavelengthScannable
|
||||
self.equation = equation
|
||||
self.engine = engine
|
||||
|
||||
self.cut = None
|
||||
self.UB = None
|
||||
self.chiMissmount = 0.
|
||||
self.phiMissmount = 0.
|
||||
self.setCrystal('cubic', 1, 1, 1, 90, 90, 90)
|
||||
|
||||
def setCrystal(self, name, a, b, c, alpha, beta, gamma):
|
||||
self.cut = CrystalUnderTest(name, a, b, c, alpha, beta, gamma)
|
||||
self.calcUB()
|
||||
|
||||
def setChiMissmount(self, chi):
|
||||
self.chiMissmount = chi
|
||||
self.calcUB()
|
||||
|
||||
def setPhiMissmount(self, phi):
|
||||
self.phiMissmount = phi
|
||||
self.calcUB()
|
||||
|
||||
def calcUB(self):
|
||||
CHI = calcCHI(self.chiMissmount * TORAD)
|
||||
PHI = calcPHI(self.phiMissmount * TORAD)
|
||||
self.UB = CHI * PHI * self.cut.B
|
||||
|
||||
def asynchronousMoveTo(self, exposureTime):
|
||||
self.exposureTime = exposureTime
|
||||
if self.pause:
|
||||
time.sleep(exposureTime) # Should not technically block!
|
||||
|
||||
def getPosition(self):
|
||||
h, k, l = self.getHkl()
|
||||
dh, dk, dl = h - round(h), k - round(k), l - round(l)
|
||||
count = self.equation(dh, dk, dl)
|
||||
#return self.exposureTime, count*self.exposureTime
|
||||
return count * self.exposureTime
|
||||
|
||||
def getHkl(self):
|
||||
pos = self.geometry.physical_angles_to_internal_position(
|
||||
self.diffractometerScannable.getPosition())
|
||||
pos.changeToRadians()
|
||||
wavelength = self.wavelengthScannable.getPosition()
|
||||
if self.engine.lower() == 'vlieg':
|
||||
return vliegAnglesToHkl(pos, wavelength, self.UB)
|
||||
elif self.engine.lower() == 'you':
|
||||
return youAnglesToHkl(pos, wavelength, self.UB)
|
||||
else:
|
||||
raise ValueError(self.engine)
|
||||
|
||||
def isBusy(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def __repr__(self):
|
||||
s = 'simulated crystal detector: %s\n' % self.getName()
|
||||
h, k, l = self.getHkl()
|
||||
s += ' h : %f\n' % h
|
||||
s += ' k : %f\n' % k
|
||||
s += ' l : %f\n' % l
|
||||
s += self.cut.__str__() + '\n'
|
||||
s += "chi orientation: %s\n" % self.chiMissmount
|
||||
s += "phi orientation: %s\n" % self.phiMissmount
|
||||
ub = self.UB.tolist()
|
||||
s += "UB:\n"
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[0][0], ub[0][1], ub[0][2])
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[1][0], ub[1][1], ub[1][2])
|
||||
s += " % 18.13f% 18.13f% 18.12f\n" % (ub[2][0], ub[2][1], ub[2][2])
|
||||
return s
|
||||
@@ -0,0 +1,109 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, tan, sin, atan, cos, atan2
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class SlaveScannableDriver(object):
|
||||
|
||||
def __init__(self, scannables):
|
||||
self.scannables = scannables
|
||||
|
||||
def isBusy(self):
|
||||
for scn in self.scannables:
|
||||
if scn.isBusy():
|
||||
return True
|
||||
return False
|
||||
|
||||
def waitWhileBusy(self):
|
||||
for scn in self.scannables:
|
||||
scn.waitWhileBusy()
|
||||
|
||||
def triggerAsynchronousMove(self, triggerPos):
|
||||
nu = self.slaveFromTriggerPos(triggerPos)
|
||||
for scn in self.scannables:
|
||||
scn.asynchronousMoveTo(nu)
|
||||
|
||||
def getPosition(self):
|
||||
return self.scannables[0].getPosition()
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
raise Exception("Abstract")
|
||||
|
||||
def getScannableNames(self):
|
||||
return [scn.name for scn in self.scannables]
|
||||
|
||||
def getOutputFormat(self):
|
||||
return [list(scn.outputFormat)[0] for scn in self.scannables]
|
||||
|
||||
def getPositions(self):
|
||||
return [float(scn.getPosition()) for scn in self.scannables]
|
||||
|
||||
|
||||
"""
|
||||
Based on: Elias Vlieg, "A (2+3)-Type Surface Diffractometer: Mergence of the
|
||||
z-axis and (2+2)-Type Geometries", J. Appl. Cryst. (1998). 31. 198-203
|
||||
"""
|
||||
|
||||
|
||||
class NuDriverForSixCirclePlugin(SlaveScannableDriver):
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
|
||||
alpha, delta, gamma, _, _, _ = triggerPos
|
||||
alpha = alpha * TORAD
|
||||
delta = delta * TORAD
|
||||
gamma = gamma * TORAD
|
||||
|
||||
### Equation16 RHS ###
|
||||
rhs = -1 * tan(gamma - alpha) * sin(delta)
|
||||
nu = atan(rhs) # -pi/2 <= nu <= pi/2
|
||||
return nu * TODEG
|
||||
|
||||
|
||||
class NuDriverForWillmottHorizontalGeometry(SlaveScannableDriver):
|
||||
|
||||
"""
|
||||
Based on: Phillip Willmott, "Angle calculations for a (2+3)-type
|
||||
diffractometer: focus on area detectors", J. Appl. Cryst. (2011). 44.
|
||||
73-83
|
||||
"""
|
||||
|
||||
def __init__(self, scannables, area_detector=False):
|
||||
SlaveScannableDriver.__init__(self, scannables)
|
||||
self.area_detector = area_detector
|
||||
|
||||
def slaveFromTriggerPos(self, triggerPos):
|
||||
|
||||
delta, gamma, omegah, _ = triggerPos
|
||||
delta *= TORAD
|
||||
gamma *= TORAD
|
||||
omegah *= TORAD
|
||||
if self.area_detector:
|
||||
nu = atan2(sin(delta - omegah), tan(gamma)) # (66)
|
||||
else:
|
||||
top = -sin(gamma) * sin(omegah)
|
||||
bot = (sin(omegah) * cos(gamma) * sin(delta) +
|
||||
cos(omegah) * cos(delta))
|
||||
nu = atan2(top, bot) # (61)
|
||||
|
||||
print 'nu:', nu * TODEG
|
||||
return nu * TODEG
|
||||
@@ -0,0 +1,184 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
import time
|
||||
import threading
|
||||
import socket
|
||||
PORT = 4567
|
||||
|
||||
from gda.device.scannable import ScannableMotionWithScannableFieldsBaseTest
|
||||
|
||||
#import scannable.vrmlModelDriver
|
||||
#reload(scannable.vrmlModelDriver);from scannable.vrmlModelDriver import \
|
||||
# VrmlModelDriver, LinearProfile, MoveThread
|
||||
#fc=VrmlModelDriver(
|
||||
# 'fc',['alpha','delta','omega', 'chi','phi'], speed=30, host='diamrl5104')
|
||||
#alpha = fc.alpha
|
||||
#delta = fc.delta
|
||||
#omega = fc.omega
|
||||
#chi = fc.chi
|
||||
#phi = fc.phi
|
||||
|
||||
|
||||
def connect_to_socket(host, port):
|
||||
print "Connecting to %s on port %d" % (host, port)
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sock.connect((host, port))
|
||||
print "Connected"
|
||||
socketfile = sock.makefile('rw', 0)
|
||||
return socketfile
|
||||
|
||||
|
||||
class LinearProfile(object):
|
||||
|
||||
def __init__(self, v, t_accel, startList, endList):
|
||||
assert len(startList) == len(endList)
|
||||
self.v = float(v)
|
||||
self.start = startList
|
||||
self.end = endList
|
||||
self.t_accel = t_accel
|
||||
|
||||
distances = [e - s for e, s in zip(self.end, self.start)]
|
||||
max_distance = max([abs(d) for d in distances])
|
||||
if max_distance == 0:
|
||||
self.delta_time = 0
|
||||
else:
|
||||
self.delta_time = abs(max_distance / self.v)
|
||||
self.speeds = [d / self.delta_time for d in distances]
|
||||
self.start_time = time.time()
|
||||
|
||||
def getPosition(self):
|
||||
if self.start_time is None:
|
||||
return self.start
|
||||
if not self.isMoving():
|
||||
return self.end
|
||||
t = abs(float(time.time() - self.start_time))
|
||||
if t > self.delta_time:
|
||||
# we are in the deceleration phase (i.e paused for now)
|
||||
return self.end
|
||||
return [s + v * t for s, v in zip(self.start, self.speeds)]
|
||||
|
||||
def isMoving(self):
|
||||
return time.time() < self.start_time + self.delta_time + self.t_accel
|
||||
|
||||
|
||||
class MoveThread(threading.Thread):
|
||||
|
||||
def __init__(self, profile, socketfile, axisNames):
|
||||
threading.Thread.__init__(self)
|
||||
self.profile = profile
|
||||
self.socketfile = socketfile
|
||||
self.axisNames = axisNames
|
||||
|
||||
def run(self):
|
||||
while self.profile.isMoving():
|
||||
self.update()
|
||||
time.sleep(.1)
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
pos = self.profile.getPosition()
|
||||
d = dict(zip(map(str, self.axisNames), pos))
|
||||
if self.socketfile:
|
||||
self.socketfile.write(repr(d) + '\n')
|
||||
|
||||
|
||||
class VrmlModelDriver(ScannableMotionWithScannableFieldsBaseTest):
|
||||
|
||||
def __init__(self, name, axes_names, host=None, speed=60, t_accel=.1,
|
||||
format='%.3f'):
|
||||
self.name = name
|
||||
self.inputNames = list(axes_names)
|
||||
self.extraNames = []
|
||||
self.outputFormat = [format] * len(self.inputNames)
|
||||
self.completeInstantiation()
|
||||
self.__last_target = [0.] * len(self.inputNames)
|
||||
self.verbose = False
|
||||
self.move_thread = None
|
||||
self.speed = speed
|
||||
self.host = host
|
||||
self.t_accel = t_accel
|
||||
self.socketfile = None
|
||||
if self.host:
|
||||
try:
|
||||
self.connect()
|
||||
except socket.error:
|
||||
print "Failed to connect to %s:%r" % (self.host, PORT)
|
||||
print "Connect with: %s.connect()" % self.name
|
||||
|
||||
def connect(self):
|
||||
self.socketfile = connect_to_socket(self.host, PORT)
|
||||
self.rawAsynchronousMoveTo(self.__last_target)
|
||||
|
||||
def isBusy(self):
|
||||
if self.move_thread is None:
|
||||
return False
|
||||
return self.move_thread.profile.isMoving()
|
||||
|
||||
def rawGetPosition(self):
|
||||
if self.move_thread is None:
|
||||
return self.__last_target
|
||||
else:
|
||||
return self.move_thread.profile.getPosition()
|
||||
|
||||
def rawAsynchronousMoveTo(self, targetList):
|
||||
if self.isBusy():
|
||||
raise Exception(self.name + ' is already moving')
|
||||
if self.verbose:
|
||||
print self.name + ".rawAsynchronousMoveTo(%r)" % targetList
|
||||
|
||||
for i, target in enumerate(targetList):
|
||||
if target is None:
|
||||
targetList[i] = self.__last_target[i]
|
||||
profile = LinearProfile(
|
||||
self.speed, self.t_accel, self.__last_target, targetList)
|
||||
self.move_thread = MoveThread(
|
||||
profile, self.socketfile, self.inputNames)
|
||||
self.move_thread.start()
|
||||
self.__last_target = targetList
|
||||
|
||||
def getFieldPosition(self, index):
|
||||
return self.getPosition()[index]
|
||||
|
||||
def __del__(self):
|
||||
self.socketfile.close()
|
||||
|
||||
#class TrapezoidProfile(object):
|
||||
#
|
||||
# def __init__(self, t_accel, v_max, delta_x):
|
||||
# self.t_a = t_accel
|
||||
# self.v_m = v_max
|
||||
# self.delta_x = delta_x
|
||||
#
|
||||
# self.t_c = (self.X - self.v_m*self.t_a) / self.v_m
|
||||
#
|
||||
# def x(self, t):
|
||||
# if self.t_c <=0:
|
||||
# return self.__xshort(t)
|
||||
# else:
|
||||
# return self.__xlong(t)
|
||||
#
|
||||
# def __xshort(self, t):
|
||||
# delta_t = 2 * sqrt(self.delta_x*self.t_a/self.v_m)
|
||||
# if t <= .5*delta_t:
|
||||
# return (.5*self.v_m/self.t_a) * t**2
|
||||
# else:
|
||||
# v_peak = (self.v_m/self.t_a) * .5*delta_t
|
||||
# return (t-.5*delta_t)*v_peak - (t-.5*delta_t)**2 ####HERE, bugged
|
||||
# self.delta_x/2
|
||||
@@ -0,0 +1,50 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
try:
|
||||
from gdascripts.pd.dummy_pds import DummyPD
|
||||
except ImportError:
|
||||
from diffcalc.gdasupport.minigda.scannable import DummyPD
|
||||
|
||||
|
||||
class Wavelength(DummyPD):
|
||||
|
||||
def __init__(self, name, energyScannable,
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
self.energyScannable = energyScannable
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
|
||||
DummyPD.__init__(self, name)
|
||||
|
||||
def asynchronousMoveTo(self, pos):
|
||||
self.energyScannable.asynchronousMoveTo(
|
||||
(12.39842 / pos) / self.energyScannableMultiplierToGetKeV)
|
||||
|
||||
def getPosition(self):
|
||||
energy = self.energyScannable.getPosition()
|
||||
if energy == 0:
|
||||
raise Exception(
|
||||
"The energy is 0, so no wavelength could be calculated.run_All()")
|
||||
return 12.39842 / (energy * self.energyScannableMultiplierToGetKeV)
|
||||
|
||||
def isBusy(self):
|
||||
return self.energyScannable.isBusy()
|
||||
|
||||
def waitWhileBusy(self):
|
||||
return self.energyScannable.waitWhileBusy()
|
||||
116
script/__Lib/diffcalc_old/diffcalc/gdasupport/you.py
Normal file
116
script/__Lib/diffcalc_old/diffcalc/gdasupport/you.py
Normal file
@@ -0,0 +1,116 @@
|
||||
from diffcalc.gdasupport.scannable.diffractometer import DiffractometerScannableGroup
|
||||
from diffcalc.gdasupport.scannable.hkl import Hkl
|
||||
from diffcalc.gdasupport.scannable.simulation import SimulatedCrystalCounter
|
||||
from diffcalc.gdasupport.scannable.wavelength import Wavelength
|
||||
from diffcalc.gdasupport.scannable.parameter import DiffractionCalculatorParameter
|
||||
|
||||
|
||||
from diffcalc.dc import dcyou as _dc
|
||||
from diffcalc.dc.help import format_command_help
|
||||
reload(_dc)
|
||||
from diffcalc.dc.dcyou import * # @UnusedWildImport
|
||||
from diffcalc import settings
|
||||
|
||||
try:
|
||||
import gda # @UnusedImport @UnresolvedImport
|
||||
GDA = True
|
||||
except:
|
||||
GDA = False
|
||||
|
||||
if not GDA:
|
||||
from diffcalc.gdasupport.minigda import command
|
||||
_pos = command.Pos()
|
||||
_scan = command.Scan(command.ScanDataPrinter())
|
||||
|
||||
def pos(*args):
|
||||
"""
|
||||
pos show position of all Scannables
|
||||
pos scn show position of scn
|
||||
pos scn targetmove scn to target (a number)
|
||||
"""
|
||||
return _pos(*args)
|
||||
|
||||
def scan(*args):
|
||||
"""
|
||||
scan scn start stop step {scn {target}} {det t}
|
||||
"""
|
||||
return _scan(*args)
|
||||
|
||||
|
||||
from diffcalc.gdasupport.scannable.sim import sim # @UnusedImport
|
||||
|
||||
_scn_group = settings.axes_scannable_group
|
||||
_diff_scn_name = settings.geometry.name # @UndefinedVariable
|
||||
_energy_scannable = settings.energy_scannable
|
||||
|
||||
|
||||
# Create diffractometer scannable
|
||||
_diff_scn = DiffractometerScannableGroup(_diff_scn_name, _dc, _scn_group)
|
||||
globals()[_diff_scn_name] = _diff_scn
|
||||
|
||||
# Create hkl scannables
|
||||
hkl = Hkl('hkl', _scn_group, _dc)
|
||||
h = hkl.h
|
||||
k = hkl.k
|
||||
l = hkl.l
|
||||
|
||||
Hkl.dynamic_docstring = format_command_help(hkl_commands_for_help) # must be on the class
|
||||
ub.__doc__ = format_command_help(ub_commands_for_help)
|
||||
|
||||
_virtual_angles = ('theta', 'qaz', 'alpha', 'naz', 'tau', 'psi', 'beta')
|
||||
hklverbose = Hkl('hklverbose', _scn_group, _dc, _virtual_angles)
|
||||
|
||||
|
||||
# Create wavelength scannable
|
||||
wl = Wavelength(
|
||||
'wl', _energy_scannable, settings.energy_scannable_multiplier_to_get_KeV)
|
||||
|
||||
###GOBBO
|
||||
#if not GDA:
|
||||
# wl.asynchronousMoveTo(1) # Angstrom
|
||||
|
||||
_energy_scannable.level = 3
|
||||
wl.level = 3
|
||||
|
||||
|
||||
# Create simulated counter timer
|
||||
ct = SimulatedCrystalCounter('ct', _scn_group, settings.geometry, wl)
|
||||
ct.level = 10
|
||||
|
||||
|
||||
# Create constraint scannables
|
||||
def _create_constraint_scannable(con_name, scn_name=None):
|
||||
if not scn_name:
|
||||
scn_name = con_name
|
||||
return DiffractionCalculatorParameter(
|
||||
scn_name, con_name, _dc.constraint_manager)
|
||||
|
||||
# Detector constraints
|
||||
def isconstrainable(name):
|
||||
return not constraint_manager.is_constraint_fixed(name)
|
||||
|
||||
if isconstrainable('delta'): delta_con = _create_constraint_scannable('delta', 'delta_con')
|
||||
if isconstrainable('gam'): gam_con = _create_constraint_scannable('gam', 'gam_con')
|
||||
if isconstrainable('qaz'): qaz = _create_constraint_scannable('qaz')
|
||||
if isconstrainable('naz'): naz = _create_constraint_scannable('naz')
|
||||
|
||||
# Reference constraints
|
||||
alpha = _create_constraint_scannable('alpha')
|
||||
beta = _create_constraint_scannable('beta')
|
||||
psi = _create_constraint_scannable('psi')
|
||||
a_eq_b = 'a_eq_b'
|
||||
|
||||
# Sample constraints
|
||||
if isconstrainable('mu'): mu_con = _create_constraint_scannable('mu', 'mu_con')
|
||||
if isconstrainable('eta'): eta_con = _create_constraint_scannable('eta', 'eta_con')
|
||||
if isconstrainable('chi'): chi_con = _create_constraint_scannable('chi', 'chi_con')
|
||||
if isconstrainable('phi'): phi_con = _create_constraint_scannable('phi', 'phi_con')
|
||||
if isconstrainable('mu') and isconstrainable('gam'): mu_is_gam = 'mu_is_gam'
|
||||
|
||||
|
||||
# Cleanup to allow "from gdasupport.you import *"
|
||||
del DiffractometerScannableGroup, Hkl, SimulatedCrystalCounter
|
||||
del Wavelength, DiffractionCalculatorParameter
|
||||
|
||||
# Cleanup other cruft
|
||||
del format_command_help
|
||||
382
script/__Lib/diffcalc_old/diffcalc/hardware.py
Normal file
382
script/__Lib/diffcalc_old/diffcalc/hardware.py
Normal file
@@ -0,0 +1,382 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
from diffcalc import settings
|
||||
|
||||
SMALL = 1e-8
|
||||
|
||||
from diffcalc.util import command
|
||||
|
||||
__all__ = ['hardware', 'setcut', 'setmin', 'setmax']
|
||||
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
|
||||
|
||||
|
||||
@command
|
||||
def hardware():
|
||||
"""hardware -- show diffcalc limits and cuts"""
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setcut(scannable_or_string=None, val=None):
|
||||
"""setcut {name {val}} -- sets cut angle
|
||||
"""
|
||||
if scannable_or_string is None and val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(scannable_or_string)
|
||||
if val is None:
|
||||
print '%s: %f' % (name, settings.hardware.get_cuts()[name]) # @UndefinedVariable
|
||||
else:
|
||||
oldcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
settings.hardware.set_cut(name, float(val)) # @UndefinedVariable
|
||||
newcut = settings.hardware.get_cuts()[name] # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmin(name=None, val=None):
|
||||
"""setmin {axis {val}} -- set lower limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setmax(name=None, val=None):
|
||||
"""setmax {name {val}} -- sets upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, val, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
@command
|
||||
def setrange(name=None, lower=None, upper=None):
|
||||
"""setrange {axis {min} {max}} -- set lower and upper limits used by auto sector code (None to clear)""" #@IgnorePep8
|
||||
_setMinOrMax(name, lower, settings.hardware.set_lower_limit) # @UndefinedVariable
|
||||
_setMinOrMax(name, upper, settings.hardware.set_upper_limit) # @UndefinedVariable
|
||||
|
||||
def _setMinOrMax(name, val, setMethod):
|
||||
if name is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts() # @UndefinedVariable
|
||||
else:
|
||||
name = getNameFromScannableOrString(name)
|
||||
if val is None:
|
||||
print settings.hardware.repr_sector_limits_and_cuts(name) # @UndefinedVariable
|
||||
else:
|
||||
setMethod(name, float(val))
|
||||
|
||||
|
||||
commands_for_help = ['Hardware',
|
||||
hardware,
|
||||
setcut,
|
||||
setmin,
|
||||
setmax]
|
||||
|
||||
|
||||
class HardwareAdapter(object):
|
||||
|
||||
def __init__(self, diffractometerAngleNames, defaultCuts={},
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
|
||||
self._diffractometerAngleNames = diffractometerAngleNames
|
||||
self._upperLimitDict = {}
|
||||
self._lowerLimitDict = {}
|
||||
self._cut_angles = {}
|
||||
self._configure_cuts(defaultCuts)
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = 'base'
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def get_axes_names(self):
|
||||
return tuple(self._diffractometerAngleNames)
|
||||
|
||||
def get_position(self):
|
||||
"""pos = get_position() -- returns the current physical diffractometer
|
||||
position as a diffcalc.util object in degrees
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms
|
||||
"""
|
||||
return 12.39842 / self.get_energy()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
raise NotImplementedError()
|
||||
|
||||
def __str__(self):
|
||||
s = self.name + ":\n"
|
||||
s += " energy : " + str(self.get_energy()) + " keV\n"
|
||||
s += " wavelength : " + str(self.get_wavelength()) + " Angstrom\n"
|
||||
names = self._diffractometerAngleNames
|
||||
for name, pos in zip(names, self.get_position()):
|
||||
s += " %s : %r deg\n" % (name, pos)
|
||||
return s
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def get_position_by_name(self, angleName):
|
||||
names = list(self._diffractometerAngleNames)
|
||||
return self.get_position()[names.index(angleName)]
|
||||
|
||||
### Limits ###
|
||||
|
||||
def get_lower_limit(self, name):
|
||||
'''returns lower limits by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
(name, self._diffractometerAngleNames))
|
||||
return self._lowerLimitDict.get(name)
|
||||
|
||||
def get_upper_limit(self, name):
|
||||
'''returns upper limit by axis name. Limit may be None if not set
|
||||
'''
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError("No angle called %s. Try one of: %s" %
|
||||
name, self._diffractometerAngleNames)
|
||||
return self._upperLimitDict.get(name)
|
||||
|
||||
def set_lower_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set lower Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._lowerLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no lower Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._lowerLimitDict[name] = value
|
||||
|
||||
def set_upper_limit(self, name, value):
|
||||
"""value may be None to remove limit"""
|
||||
if name not in self._diffractometerAngleNames:
|
||||
raise ValueError(
|
||||
"Cannot set upper Diffcalc limit: No angle called %s. Try one "
|
||||
"of: %s" % (name, self._diffractometerAngleNames))
|
||||
if value is None:
|
||||
try:
|
||||
del self._upperLimitDict[name]
|
||||
except KeyError:
|
||||
print ("WARNING: There was no upper Diffcalc limit %s set to "
|
||||
"clear" % name)
|
||||
else:
|
||||
self._upperLimitDict[name] = value
|
||||
|
||||
def is_position_within_limits(self, positionArray):
|
||||
"""
|
||||
where position array is in degrees and cut to be between -180 and 180
|
||||
"""
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
if not self.is_axis_value_within_limits(axis_name, value):
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_axis_value_within_limits(self, axis_name, value):
|
||||
if axis_name in self._upperLimitDict:
|
||||
if value > self._upperLimitDict[axis_name]:
|
||||
return False
|
||||
if axis_name in self._lowerLimitDict:
|
||||
if value < self._lowerLimitDict[axis_name]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def repr_sector_limits_and_cuts(self, name=None):
|
||||
if name is None:
|
||||
s = ''
|
||||
for name in self.get_axes_names():
|
||||
s += self.repr_sector_limits_and_cuts(name) + '\n'
|
||||
s += "Note: When auto sector/transforms are used,\n "
|
||||
s += " cuts are applied before checking limits."
|
||||
return s
|
||||
# limits:
|
||||
low = self.get_lower_limit(name)
|
||||
high = self.get_upper_limit(name)
|
||||
s = ' '
|
||||
if low is not None:
|
||||
s += "% 6.1f <= " % low
|
||||
else:
|
||||
s += ' ' * 10
|
||||
s += '%5s' % name
|
||||
if high is not None:
|
||||
s += " <= % 6.1f" % high
|
||||
else:
|
||||
s += ' ' * 10
|
||||
# cuts:
|
||||
try:
|
||||
if self.get_cuts()[name] is not None:
|
||||
s += " (cut: % 6.1f)" % self.get_cuts()[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return s
|
||||
|
||||
### Cutting Stuff ###
|
||||
|
||||
def _configure_cuts(self, defaultCutsDict):
|
||||
# 1. Set default cut angles
|
||||
self._cut_angles = dict.fromkeys(self._diffractometerAngleNames, -180.)
|
||||
if 'phi' in self._cut_angles:
|
||||
self._cut_angles['phi'] = 0.
|
||||
# 2. Overide with user-specified cuts
|
||||
for name, val in defaultCutsDict.iteritems():
|
||||
self.set_cut(name, val)
|
||||
|
||||
def set_cut(self, name, value):
|
||||
if name in self._cut_angles:
|
||||
self._cut_angles[name] = value
|
||||
else:
|
||||
raise KeyError("Diffractometer has no angle %s. Try: %s." %
|
||||
(name, self._diffractometerAngleNames))
|
||||
|
||||
def get_cuts(self):
|
||||
return self._cut_angles
|
||||
|
||||
def cut_angles(self, positionArray):
|
||||
'''Assumes each angle in positionArray is between -360 and 360
|
||||
'''
|
||||
cutArray = []
|
||||
names = self._diffractometerAngleNames
|
||||
for axis_name, value in zip(names, positionArray):
|
||||
cutArray.append(self.cut_angle(axis_name, value))
|
||||
return tuple(cutArray)
|
||||
|
||||
def cut_angle(self, axis_name, value):
|
||||
cut_angle = self._cut_angles[axis_name]
|
||||
if cut_angle is None:
|
||||
return value
|
||||
return cut_angle_at(cut_angle, value)
|
||||
|
||||
|
||||
def cut_angle_at(cut_angle, value):
|
||||
if (cut_angle == 0 and (abs(value - 360) < SMALL) or
|
||||
(abs(value + 360) < SMALL) or
|
||||
(abs(value) < SMALL)):
|
||||
value = 0.
|
||||
if value < (cut_angle - SMALL):
|
||||
return value + 360.
|
||||
elif value >= cut_angle + 360. + SMALL:
|
||||
return value - 360.
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class DummyHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerAngleNames):
|
||||
super(self.__class__, self).__init__(diffractometerAngleNames)
|
||||
# HardwareAdapter.__init__(self, diffractometerAngleNames)
|
||||
|
||||
self._position = [0.] * len(diffractometerAngleNames)
|
||||
self._wavelength = 1.
|
||||
self.energyScannableMultiplierToGetKeV = 1
|
||||
self._name = "Dummy"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self._position
|
||||
|
||||
def _set_position(self, pos):
|
||||
assert len(pos) == len(self.get_axes_names()), \
|
||||
"Wrong length of input list"
|
||||
self._position = pos
|
||||
|
||||
position = property(get_position, _set_position)
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv """
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return (12.39842 /
|
||||
(self._wavelength * self.energyScannableMultiplierToGetKeV))
|
||||
|
||||
def _set_energy(self, energy):
|
||||
self._wavelength = 12.39842 / energy
|
||||
|
||||
energy = property(get_energy, _set_energy)
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
if self._wavelength is None:
|
||||
raise DiffcalcException(
|
||||
"Energy or wavelength have not been set")
|
||||
return self._wavelength
|
||||
|
||||
def _set_wavelength(self, wavelength):
|
||||
self._wavelength = wavelength
|
||||
|
||||
wavelength = property(get_wavelength, _set_wavelength)
|
||||
|
||||
|
||||
class ScannableHardwareAdapter(HardwareAdapter):
|
||||
|
||||
def __init__(self, diffractometerScannable, energyScannable,
|
||||
energyScannableMultiplierToGetKeV=1):
|
||||
input_names = diffractometerScannable.getInputNames()
|
||||
super(self.__class__, self).__init__(input_names)
|
||||
# HardwareAdapter.__init__(self, input_names)
|
||||
self.diffhw = diffractometerScannable
|
||||
self.energyhw = energyScannable
|
||||
self.energyScannableMultiplierToGetKeV = \
|
||||
energyScannableMultiplierToGetKeV
|
||||
self._name = "ScannableHarwdareMonitor"
|
||||
|
||||
# Required methods
|
||||
|
||||
def get_position(self):
|
||||
"""
|
||||
pos = getDiffractometerPosition() -- returns the current physical
|
||||
diffractometer position as a list in degrees
|
||||
"""
|
||||
return self.diffhw.getPosition()
|
||||
|
||||
def get_energy(self):
|
||||
"""energy = get_energy() -- returns energy in kEv (NOT eV!) """
|
||||
multiplier = self.energyScannableMultiplierToGetKeV
|
||||
energy = self.energyhw.getPosition() * multiplier
|
||||
if energy is None:
|
||||
raise DiffcalcException("Energy has not been set")
|
||||
return energy
|
||||
|
||||
def get_wavelength(self):
|
||||
"""wavelength = get_wavelength() -- returns wavelength in Angstroms"""
|
||||
energy = self.get_energy()
|
||||
return 12.39842 / energy
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.diffhw.getName()
|
||||
0
script/__Lib/diffcalc_old/diffcalc/hkl/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/hkl/__init__.py
Normal file
155
script/__Lib/diffcalc_old/diffcalc/hkl/calcbase.py
Normal file
155
script/__Lib/diffcalc_old/diffcalc/hkl/calcbase.py
Normal file
@@ -0,0 +1,155 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
from diffcalc.util import DiffcalcException, differ
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class HklCalculatorBase(object):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=False):
|
||||
|
||||
self._ubcalc = ubcalc # to get the UBMatrix, tau and sigma
|
||||
self._geometry = geometry # to access information about the
|
||||
# diffractometer geometry and mode_selector
|
||||
self._hardware = hardware # Used for tracking parameters only
|
||||
self.raiseExceptionsIfAnglesDoNotMapBackToHkl = \
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl
|
||||
|
||||
def anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Return hkl tuple and dictionary of all virtual angles in degrees from
|
||||
Position in degrees and wavelength in Angstroms.
|
||||
"""
|
||||
|
||||
h, k, l = self._anglesToHkl(pos.inRadians(), wavelength)
|
||||
paramDict = self.anglesToVirtualAngles(pos, wavelength)
|
||||
return ((h, k, l), paramDict)
|
||||
|
||||
def anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Return dictionary of all virtual angles in degrees from Position object
|
||||
in degrees and wavelength in Angstroms.
|
||||
"""
|
||||
anglesDict = self._anglesToVirtualAngles(pos.inRadians(), wavelength)
|
||||
for name in anglesDict:
|
||||
anglesDict[name] = anglesDict[name] * TODEG
|
||||
return anglesDict
|
||||
|
||||
def hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return verified Position and all virtual angles in degrees from
|
||||
h, k & l and wavelength in Angstroms.
|
||||
|
||||
The calculated Position is verified by checking that it maps back using
|
||||
anglesToHkl() to the requested hkl value.
|
||||
|
||||
Those virtual angles fixed or generated while calculating the position
|
||||
are verified by by checking that they map back using
|
||||
anglesToVirtualAngles to the virtual angles for the given position.
|
||||
|
||||
Throws a DiffcalcException if either check fails and
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl is True, otherwise displays a
|
||||
warning.
|
||||
"""
|
||||
|
||||
# Update tracked parameters. During this calculation parameter values
|
||||
# will be read directly from self._parameters instead of via
|
||||
# self.getParameter which would trigger another potentially time-costly
|
||||
# position update.
|
||||
self.parameter_manager.update_tracked()
|
||||
|
||||
pos, virtualAngles = self._hklToAngles(h, k, l, wavelength) # in rad
|
||||
|
||||
# to degrees:
|
||||
pos.changeToDegrees()
|
||||
|
||||
for key, val in virtualAngles.items():
|
||||
if val is not None:
|
||||
virtualAngles[key] = val * TODEG
|
||||
|
||||
self._verify_pos_map_to_hkl(h, k, l, wavelength, pos)
|
||||
|
||||
virtualAnglesReadback = self._verify_virtual_angles(h, k, l, wavelength, pos, virtualAngles)
|
||||
|
||||
return pos, virtualAnglesReadback
|
||||
|
||||
def _verify_pos_map_to_hkl(self, h, k, l, wavelength, pos):
|
||||
hkl, _ = self.anglesToHkl(pos, wavelength)
|
||||
e = 0.001
|
||||
if ((abs(hkl[0] - h) > e) or (abs(hkl[1] - k) > e) or
|
||||
(abs(hkl[2] - l) > e)):
|
||||
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) were %s.\n" % (h, k, l, str(pos))
|
||||
s += "Converting these angles back to hkl resulted in hkl="\
|
||||
"(%f,%f,%f)" % (hkl[0], hkl[1], hkl[2])
|
||||
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
|
||||
raise DiffcalcException(s)
|
||||
else:
|
||||
print s
|
||||
|
||||
def _verify_virtual_angles(self, h, k, l, wavelength, pos, virtualAngles):
|
||||
# Check that the virtual angles calculated/fixed during the hklToAngles
|
||||
# those read back from pos using anglesToVirtualAngles
|
||||
virtualAnglesReadback = self.anglesToVirtualAngles(pos, wavelength)
|
||||
for key, val in virtualAngles.items():
|
||||
if val != None: # Some values calculated in some mode_selector
|
||||
r = virtualAnglesReadback[key]
|
||||
if ((differ(val, r, .00001) and differ(val, r + 360, .00001) and differ(val, r - 360, .00001))):
|
||||
s = "ERROR: The angles calculated for hkl=(%f,%f,%f) with"\
|
||||
" mode=%s were %s.\n" % (h, k, l, self.repr_mode(), str(pos))
|
||||
s += "During verification the virtual angle %s resulting "\
|
||||
"from (or set for) this calculation of %f" % (key, val)
|
||||
s += "did not match that calculated by "\
|
||||
"anglesToVirtualAngles of %f" % virtualAnglesReadback[key]
|
||||
if self.raiseExceptionsIfAnglesDoNotMapBackToHkl:
|
||||
raise DiffcalcException(s)
|
||||
else:
|
||||
print s
|
||||
|
||||
return virtualAnglesReadback
|
||||
|
||||
def repr_mode(self):
|
||||
pass
|
||||
|
||||
### Collect all math access to context here
|
||||
|
||||
def _getUBMatrix(self):
|
||||
return self._ubcalc.UB
|
||||
|
||||
def _getMode(self):
|
||||
return self.mode_selector.getMode()
|
||||
|
||||
def _getSigma(self):
|
||||
return self._ubcalc.sigma
|
||||
|
||||
def _getTau(self):
|
||||
return self._ubcalc.tau
|
||||
|
||||
def _getParameter(self, name):
|
||||
# Does not use context.getParameter as this will trigger a costly
|
||||
# parameter collection
|
||||
pm = self.parameter_manager
|
||||
return pm.getParameterWithoutUpdatingTrackedParemeters(name)
|
||||
|
||||
def _getGammaParameterName(self):
|
||||
return self._gammaParameterName
|
||||
55
script/__Lib/diffcalc_old/diffcalc/hkl/common.py
Normal file
55
script/__Lib/diffcalc_old/diffcalc/hkl/common.py
Normal file
@@ -0,0 +1,55 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
from diffcalc.util import allnum
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
raise TypeError()
|
||||
|
||||
|
||||
class DummyParameterManager(object):
|
||||
|
||||
def getParameterDict(self):
|
||||
return {}
|
||||
|
||||
def _setParameter(self, name, value):
|
||||
raise KeyError(name)
|
||||
|
||||
def _getParameter(self, name):
|
||||
raise KeyError(name)
|
||||
|
||||
def update_tracked(self):
|
||||
pass
|
||||
|
||||
|
||||
def sim(self, scn, hkl):
|
||||
"""sim hkl scn -- simulates moving scannable (not all)
|
||||
"""
|
||||
if not isinstance(hkl, (tuple, list)):
|
||||
raise TypeError
|
||||
|
||||
if not allnum(hkl):
|
||||
raise TypeError()
|
||||
|
||||
try:
|
||||
print scn.simulateMoveTo(hkl)
|
||||
except AttributeError:
|
||||
raise TypeError("The first argument does not support simulated moves")
|
||||
846
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/calc.py
Normal file
846
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/calc.py
Normal file
@@ -0,0 +1,846 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, asin, acos, sin, cos, sqrt, atan2, fabs, atan
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
from numjy.linalg import norm
|
||||
|
||||
from diffcalc.hkl.calcbase import HklCalculatorBase
|
||||
from diffcalc.hkl.vlieg.transform import TransformCInRadians
|
||||
from diffcalc.util import dot3, cross3, bound, differ
|
||||
from diffcalc.hkl.vlieg.geometry import createVliegMatrices, \
|
||||
createVliegsPsiTransformationMatrix, \
|
||||
createVliegsSurfaceTransformationMatrices, calcPHI
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
from diffcalc.hkl.vlieg.constraints import VliegParameterManager
|
||||
from diffcalc.hkl.vlieg.constraints import ModeSelector
|
||||
from diffcalc.ub.calc import PaperSpecificUbCalcStrategy
|
||||
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
transformC = TransformCInRadians()
|
||||
|
||||
|
||||
PREFER_POSITIVE_CHI_SOLUTIONS = True
|
||||
|
||||
I = matrix('1 0 0; 0 1 0; 0 0 1')
|
||||
y = matrix('0; 1; 0')
|
||||
|
||||
|
||||
def check(condition, ErrorOrStringOrCallable, *args):
|
||||
"""
|
||||
fail = check(condition, ErrorOrString) -- if condition is false raises the
|
||||
Exception passed in, or creates one from a string. If a callable function
|
||||
is passed in this is called with any args specified and the thing returns
|
||||
false.
|
||||
"""
|
||||
# TODO: Remove (really nasty) check function
|
||||
if condition == False:
|
||||
if callable(ErrorOrStringOrCallable):
|
||||
ErrorOrStringOrCallable(*args)
|
||||
return False
|
||||
elif isinstance(ErrorOrStringOrCallable, str):
|
||||
raise Exception(ErrorOrStringOrCallable)
|
||||
else: # assume input is an exception
|
||||
raise ErrorOrStringOrCallable
|
||||
return True
|
||||
|
||||
|
||||
def sign(x):
|
||||
if x < 0:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
|
||||
def vliegAnglesToHkl(pos, wavelength, UBMatrix):
|
||||
"""
|
||||
Returns hkl indices from pos object in radians.
|
||||
"""
|
||||
wavevector = 2 * pi / wavelength
|
||||
|
||||
# Create transformation matrices
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
# Create the plane normal vector in the alpha axis coordinate frame
|
||||
qa = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [wavevector], [0]])
|
||||
|
||||
# Transform the plane normal vector from the alpha frame to reciprical
|
||||
# lattice frame.
|
||||
hkl = UBMatrix.I * PHI.I * CHI.I * OMEGA.I * qa
|
||||
|
||||
return hkl[0, 0], hkl[1, 0], hkl[2, 0]
|
||||
|
||||
|
||||
class VliegUbCalcStrategy(PaperSpecificUbCalcStrategy):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
u1a = (DELTA * GAMMA - ALPHA.I) * y
|
||||
u1p = PHI.I * CHI.I * OMEGA.I * u1a
|
||||
return u1p
|
||||
|
||||
|
||||
class VliegHklCalculator(HklCalculatorBase):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=True):
|
||||
r = raiseExceptionsIfAnglesDoNotMapBackToHkl
|
||||
HklCalculatorBase.__init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=r)
|
||||
self._gammaParameterName = ({'arm': 'gamma', 'base': 'oopgamma'}
|
||||
[self._geometry.gamma_location])
|
||||
self.mode_selector = ModeSelector(self._geometry, None,
|
||||
self._gammaParameterName)
|
||||
self.parameter_manager = VliegParameterManager(
|
||||
self._geometry, self._hardware, self.mode_selector,
|
||||
self._gammaParameterName)
|
||||
self.mode_selector.setParameterManager(self.parameter_manager)
|
||||
|
||||
def __str__(self):
|
||||
# should list paramemeters and indicate which are used in selected mode
|
||||
result = "Available mode_selector:\n"
|
||||
result += self.mode_selector.reportAvailableModes()
|
||||
result += '\nCurrent mode:\n'
|
||||
result += self.mode_selector.reportCurrentMode()
|
||||
result += '\n\nParameters:\n'
|
||||
result += self.parameter_manager.reportAllParameters()
|
||||
return result
|
||||
|
||||
def _anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Return hkl tuple from VliegPosition in radians and wavelength in
|
||||
Angstroms.
|
||||
"""
|
||||
return vliegAnglesToHkl(pos, wavelength, self._getUBMatrix())
|
||||
|
||||
def _anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Return dictionary of all virtual angles in radians from VliegPosition
|
||||
object win radians and wavelength in Angstroms. The virtual angles are:
|
||||
Bin, Bout, azimuth and 2theta.
|
||||
"""
|
||||
|
||||
# Create transformation matrices
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
|
||||
S = TAU * SIGMA
|
||||
y_vector = matrix([[0], [1], [0]])
|
||||
|
||||
# Calculate Bin from equation 15:
|
||||
surfacenormal_alpha = OMEGA * CHI * PHI * S * matrix([[0], [0], [1]])
|
||||
incoming_alpha = ALPHA.I * y_vector
|
||||
minusSinBetaIn = dot3(surfacenormal_alpha, incoming_alpha)
|
||||
Bin = asin(bound(-minusSinBetaIn))
|
||||
|
||||
# Calculate Bout from equation 16:
|
||||
# surfacenormal_alpha has just ben calculated
|
||||
outgoing_alpha = DELTA * GAMMA * y_vector
|
||||
sinBetaOut = dot3(surfacenormal_alpha, outgoing_alpha)
|
||||
Bout = asin(bound(sinBetaOut))
|
||||
|
||||
# Calculate 2theta from equation 25:
|
||||
|
||||
cosTwoTheta = dot3(ALPHA * DELTA * GAMMA * y_vector, y_vector)
|
||||
twotheta = acos(bound(cosTwoTheta))
|
||||
psi = self._anglesToPsi(pos, wavelength)
|
||||
|
||||
return {'Bin': Bin, 'Bout': Bout, 'azimuth': psi, '2theta': twotheta}
|
||||
|
||||
def _hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstroms. The virtual angles are those fixed or
|
||||
generated while calculating the position: Bin, Bout and 2theta; and
|
||||
azimuth in four and five circle modes.
|
||||
"""
|
||||
|
||||
if self._getMode().group in ("fourc", "fivecFixedGamma",
|
||||
"fivecFixedAlpha"):
|
||||
return self._hklToAnglesFourAndFiveCirclesModes(h, k, l,
|
||||
wavelength)
|
||||
elif self._getMode().group == "zaxis":
|
||||
return self._hklToAnglesZaxisModes(h, k, l, wavelength)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'The current mode (%s) has an unrecognised group: %s.'
|
||||
% (self._getMode().name, self._getMode().group))
|
||||
|
||||
def _hklToAnglesFourAndFiveCirclesModes(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstrom for four and five circle modes. The virtual
|
||||
angles are those fixed or generated while calculating the position:
|
||||
Bin, Bout, 2theta and azimuth.
|
||||
"""
|
||||
|
||||
# Results in radians during calculations, returned in degreess
|
||||
pos = VliegPosition(None, None, None, None, None, None)
|
||||
|
||||
# Normalise hkl
|
||||
wavevector = 2 * pi / wavelength
|
||||
hklNorm = matrix([[h], [k], [l]]) / wavevector
|
||||
|
||||
# Compute hkl in phi axis coordinate frame
|
||||
hklPhiNorm = self._getUBMatrix() * hklNorm
|
||||
|
||||
# Determine Bin and Bout
|
||||
if self._getMode().name == '4cPhi':
|
||||
Bin = Bout = None
|
||||
else:
|
||||
Bin, Bout = self._determineBinAndBoutInFourAndFiveCirclesModes(
|
||||
hklNorm)
|
||||
|
||||
# Determine alpha and gamma
|
||||
if self._getMode().group == 'fourc':
|
||||
pos.alpha, pos.gamma = \
|
||||
self._determineAlphaAndGammaForFourCircleModes(hklPhiNorm)
|
||||
else:
|
||||
pos.alpha, pos.gamma = \
|
||||
self._determineAlphaAndGammaForFiveCircleModes(Bin, hklPhiNorm)
|
||||
if pos.alpha < -pi:
|
||||
pos.alpha += 2 * pi
|
||||
if pos.alpha > pi:
|
||||
pos.alpha -= 2 * pi
|
||||
|
||||
# Determine delta
|
||||
(pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha,
|
||||
pos.gamma)
|
||||
|
||||
# Determine omega, chi & phi
|
||||
pos.omega, pos.chi, pos.phi, psi = \
|
||||
self._determineSampleAnglesInFourAndFiveCircleModes(
|
||||
hklPhiNorm, pos.alpha, pos.delta, pos.gamma, Bin)
|
||||
# (psi will be None in fixed phi mode)
|
||||
|
||||
# Ensure that by default omega is between -90 and 90, by possibly
|
||||
# transforming the sample angles
|
||||
if self._getMode().name != '4cPhi': # not in fixed-phi mode
|
||||
if pos.omega < -pi / 2 or pos.omega > pi / 2:
|
||||
pos = transformC.transform(pos)
|
||||
|
||||
# Gather up the virtual angles calculated along the way...
|
||||
# -pi<psi<=pi
|
||||
if psi is not None:
|
||||
if psi > pi:
|
||||
psi -= 2 * pi
|
||||
if psi < (-1 * pi):
|
||||
psi += 2 * pi
|
||||
|
||||
v = {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout, 'azimuth': psi}
|
||||
return pos, v
|
||||
|
||||
def _hklToAnglesZaxisModes(self, h, k, l, wavelength):
|
||||
"""
|
||||
Return VliegPosition and virtual angles in radians from h, k & l and
|
||||
wavelength in Angstroms for z-axis modes. The virtual angles are those
|
||||
fixed or generated while calculating the position: Bin, Bout, and
|
||||
2theta.
|
||||
"""
|
||||
# Section 6:
|
||||
|
||||
# Results in radians during calculations, returned in degreess
|
||||
pos = VliegPosition(None, None, None, None, None, None)
|
||||
|
||||
# Normalise hkl
|
||||
wavevector = 2 * pi / wavelength
|
||||
hkl = matrix([[h], [k], [l]])
|
||||
hklNorm = hkl * (1.0 / wavevector)
|
||||
|
||||
# Compute hkl in phi axis coordinate frame
|
||||
hklPhi = self._getUBMatrix() * hkl
|
||||
hklPhiNorm = self._getUBMatrix() * hklNorm
|
||||
|
||||
# Determine Chi and Phi (Equation 29):
|
||||
pos.phi = -self._getTau() * TORAD
|
||||
pos.chi = -self._getSigma() * TORAD
|
||||
|
||||
# Equation 30:
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
None, None, None, None, pos.chi, pos.phi)
|
||||
del ALPHA, DELTA, GAMMA, OMEGA
|
||||
Hw = CHI * PHI * hklPhi
|
||||
|
||||
# Determine Bin and Bout:
|
||||
(Bin, Bout) = self._determineBinAndBoutInZaxisModes(
|
||||
Hw[2, 0] / wavevector)
|
||||
|
||||
# Determine Alpha and Gamma (Equation 32):
|
||||
pos.alpha = Bin
|
||||
pos.gamma = Bout
|
||||
|
||||
# Determine Delta:
|
||||
(pos.delta, twotheta) = self._determineDelta(hklPhiNorm, pos.alpha,
|
||||
pos.gamma)
|
||||
|
||||
# Determine Omega:
|
||||
delta = pos.delta
|
||||
gamma = pos.gamma
|
||||
d1 = (Hw[1, 0] * sin(delta) * cos(gamma) - Hw[0, 0] *
|
||||
(cos(delta) * cos(gamma) - cos(pos.alpha)))
|
||||
d2 = (Hw[0, 0] * sin(delta) * cos(gamma) + Hw[1, 0] *
|
||||
(cos(delta) * cos(gamma) - cos(pos.alpha)))
|
||||
|
||||
if fabs(d2) < 1e-30:
|
||||
pos.omega = sign(d1) * sign(d2) * pi / 2.0
|
||||
else:
|
||||
pos.omega = atan2(d1, d2)
|
||||
|
||||
# Gather up the virtual angles calculated along the way
|
||||
return pos, {'2theta': twotheta, 'Bin': Bin, 'Bout': Bout}
|
||||
|
||||
###
|
||||
|
||||
def _determineBinAndBoutInFourAndFiveCirclesModes(self, hklNorm):
|
||||
"""(Bin, Bout) = _determineBinAndBoutInFourAndFiveCirclesModes()"""
|
||||
BinModes = ('4cBin', '5cgBin', '5caBin')
|
||||
BoutModes = ('4cBout', '5cgBout', '5caBout')
|
||||
BeqModes = ('4cBeq', '5cgBeq', '5caBeq')
|
||||
azimuthModes = ('4cAzimuth')
|
||||
fixedBusingAndLeviWmodes = ('4cFixedw')
|
||||
|
||||
# Calculate RHS of equation 20
|
||||
# RHS (1/K)(S^-1*U*B*H)_3 where H/K = hklNorm
|
||||
UB = self._getUBMatrix()
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
#S = SIGMA * TAU
|
||||
S = TAU * SIGMA
|
||||
RHS = (S.I * UB * hklNorm)[2, 0]
|
||||
|
||||
if self._getMode().name in BinModes:
|
||||
Bin = self._getParameter('betain')
|
||||
check(Bin != None, "The parameter betain must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bin = Bin * TORAD
|
||||
sinBout = RHS - sin(Bin)
|
||||
check(fabs(sinBout) <= 1, "Could not compute Bout")
|
||||
Bout = asin(sinBout)
|
||||
|
||||
elif self._getMode().name in BoutModes:
|
||||
Bout = self._getParameter('betaout')
|
||||
check(Bout != None, "The parameter Bout must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bout = Bout * TORAD
|
||||
sinBin = RHS - sin(Bout)
|
||||
check(fabs(sinBin) <= 1, "Could not compute Bin")
|
||||
Bin = asin(sinBin)
|
||||
|
||||
elif self._getMode().name in BeqModes:
|
||||
sinBeq = RHS / 2
|
||||
check(fabs(sinBeq) <= 1, "Could not compute Bin=Bout")
|
||||
Bin = Bout = asin(sinBeq)
|
||||
|
||||
elif self._getMode().name in azimuthModes:
|
||||
azimuth = self._getParameter('azimuth')
|
||||
check(azimuth != None, "The parameter azimuth must be set for "
|
||||
"mode %s" % self._getMode().name)
|
||||
del azimuth
|
||||
# TODO: codeit
|
||||
raise NotImplementedError()
|
||||
|
||||
elif self._getMode().name in fixedBusingAndLeviWmodes:
|
||||
bandlomega = self._getParameter('blw')
|
||||
check(bandlomega != None, "The parameter abandlomega must be set "
|
||||
"for mode %s" % self._getMode().name)
|
||||
del bandlomega
|
||||
# TODO: codeit
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
raise RuntimeError("AngleCalculator does not know how to handle "
|
||||
"mode %s" % self._getMode().name)
|
||||
|
||||
return (Bin, Bout)
|
||||
|
||||
def _determineBinAndBoutInZaxisModes(self, Hw3OverK):
|
||||
"""(Bin, Bout) = _determineBinAndBoutInZaxisModes(HwOverK)"""
|
||||
BinModes = ('6czBin')
|
||||
BoutModes = ('6czBout')
|
||||
BeqModes = ('6czBeq')
|
||||
|
||||
if self._getMode().name in BinModes:
|
||||
Bin = self._getParameter('betain')
|
||||
check(Bin != None, "The parameter betain must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bin = Bin * TORAD
|
||||
# Equation 32a:
|
||||
Bout = asin(Hw3OverK - sin(Bin))
|
||||
|
||||
elif self._getMode().name in BoutModes:
|
||||
Bout = self._getParameter('betaout')
|
||||
check(Bout != None, "The parameter Bout must be set for mode %s" %
|
||||
self._getMode().name)
|
||||
Bout = Bout * TORAD
|
||||
# Equation 32b:
|
||||
Bin = asin(Hw3OverK - sin(Bout))
|
||||
|
||||
elif self._getMode().name in BeqModes:
|
||||
# Equation 32c:
|
||||
Bin = Bout = asin(Hw3OverK / 2)
|
||||
|
||||
return (Bin, Bout)
|
||||
|
||||
###
|
||||
|
||||
def _determineAlphaAndGammaForFourCircleModes(self, hklPhiNorm):
|
||||
|
||||
if self._getMode().group == 'fourc':
|
||||
alpha = self._getParameter('alpha') * TORAD
|
||||
gamma = self._getParameter(self._getGammaParameterName()) * TORAD
|
||||
check(alpha != None, "alpha parameter must be set in fourc modes")
|
||||
check(gamma != None, "gamma parameter must be set in fourc modes")
|
||||
return alpha, gamma
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"determineAlphaAndGammaForFourCirclesModes() "
|
||||
"is not appropriate for %s modes" % self._getMode().group)
|
||||
|
||||
def _determineAlphaAndGammaForFiveCircleModes(self, Bin, hklPhiNorm):
|
||||
|
||||
## Solve equation 34 for one possible Y, Yo
|
||||
# Calculate surface normal in phi frame
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
S = TAU * SIGMA
|
||||
surfaceNormalPhi = S * matrix([[0], [0], [1]])
|
||||
# Compute beta in vector
|
||||
BetaVector = matrix([[0], [-sin(Bin)], [cos(Bin)]])
|
||||
# Find Yo
|
||||
Yo = self._findMatrixToTransformAIntoB(surfaceNormalPhi, BetaVector)
|
||||
|
||||
## Calculate Hv from equation 39
|
||||
Z = matrix([[1, 0, 0],
|
||||
[0, cos(Bin), sin(Bin)],
|
||||
[0, -sin(Bin), cos(Bin)]])
|
||||
Hv = Z * Yo * hklPhiNorm
|
||||
# Fixed gamma:
|
||||
if self._getMode().group == 'fivecFixedGamma':
|
||||
gamma = self._getParameter(self._getGammaParameterName())
|
||||
check(gamma != None,
|
||||
"gamma parameter must be set in fivecFixedGamma modes")
|
||||
gamma = gamma * TORAD
|
||||
H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
|
||||
hklPhiNorm[2, 0] ** 2)
|
||||
a = -(0.5 * H2 * sin(Bin) - Hv[2, 0])
|
||||
b = -(1.0 - 0.5 * H2) * cos(Bin)
|
||||
c = cos(Bin) * sin(gamma)
|
||||
check((b * b + a * a - c * c) >= 0, 'Could not solve for alpha')
|
||||
alpha = 2 * atan2(-(b + sqrt(b * b + a * a - c * c)), -(a + c))
|
||||
|
||||
# Fixed Alpha:
|
||||
elif self._getMode().group == 'fivecFixedAlpha':
|
||||
alpha = self._getParameter('alpha')
|
||||
check(alpha != None,
|
||||
"alpha parameter must be set in fivecFixedAlpha modes")
|
||||
alpha = alpha * TORAD
|
||||
H2 = (hklPhiNorm[0, 0] ** 2 + hklPhiNorm[1, 0] ** 2 +
|
||||
hklPhiNorm[2, 0] ** 2)
|
||||
t0 = ((2 * cos(alpha) * Hv[2, 0] - sin(Bin) * cos(alpha) * H2 +
|
||||
cos(Bin) * sin(alpha) * H2 - 2 * cos(Bin) * sin(alpha)) /
|
||||
(cos(Bin) * 2.0))
|
||||
check(abs(t0) <= 1, "Cannot compute gamma: sin(gamma)>1")
|
||||
gamma = asin(t0)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"determineAlphaAndGammaInFiveCirclesModes() is not "
|
||||
"appropriate for %s modes" % self._getMode().group)
|
||||
|
||||
return (alpha, gamma)
|
||||
|
||||
###
|
||||
|
||||
def _determineDelta(self, hklPhiNorm, alpha, gamma):
|
||||
"""
|
||||
(delta, twotheta) = _determineDelta(hklPhiNorm, alpha, gamma) --
|
||||
computes delta for all modes. Also returns twotheta for sanity
|
||||
checking. hklPhiNorm is a 3X1 matrix.
|
||||
|
||||
alpha, gamma & delta - in radians.
|
||||
h k & l normalised to wavevector and in phi axis coordinates
|
||||
"""
|
||||
h = hklPhiNorm[0, 0]
|
||||
k = hklPhiNorm[1, 0]
|
||||
l = hklPhiNorm[2, 0]
|
||||
# See Vlieg section 5 (with K=1)
|
||||
cosdelta = ((1 + sin(gamma) * sin(alpha) - (h * h + k * k + l * l) / 2)
|
||||
/ (cos(gamma) * cos(alpha)))
|
||||
costwotheta = (cos(alpha) * cos(gamma) * bound(cosdelta) -
|
||||
sin(alpha) * sin(gamma))
|
||||
return (acos(bound(cosdelta)), acos(bound(costwotheta)))
|
||||
|
||||
def _determineSampleAnglesInFourAndFiveCircleModes(self, hklPhiNorm, alpha,
|
||||
delta, gamma, Bin):
|
||||
"""
|
||||
(omega, chi, phi, psi)=determineNonZAxisSampleAngles(hklPhiNorm, alpha,
|
||||
delta, gamma, sigma, tau) where hkl has been normalised by the
|
||||
wavevector and is in the phi Axis coordinate frame. All angles in
|
||||
radians. hklPhiNorm is a 3X1 matrix
|
||||
"""
|
||||
|
||||
def equation49through59(psi):
|
||||
# equation 49 R = (D^-1)*PI*D*Ro
|
||||
PSI = createVliegsPsiTransformationMatrix(psi)
|
||||
R = D.I * PSI * D * Ro
|
||||
|
||||
# eq 57: extract omega from R
|
||||
if abs(R[0, 2]) < 1e-20:
|
||||
omega = -sign(R[1, 2]) * sign(R[0, 2]) * pi / 2
|
||||
else:
|
||||
omega = -atan2(R[1, 2], R[0, 2])
|
||||
|
||||
# eq 58: extract chi from R
|
||||
sinchi = sqrt(pow(R[0, 2], 2) + pow(R[1, 2], 2))
|
||||
sinchi = bound(sinchi)
|
||||
check(abs(sinchi) <= 1, 'could not compute chi')
|
||||
# (there are two roots to this equation, but only the first is also
|
||||
# a solution to R33=cos(chi))
|
||||
chi = asin(sinchi)
|
||||
|
||||
# eq 59: extract phi from R
|
||||
if abs(R[2, 0]) < 1e-20:
|
||||
phi = sign(R[2, 1]) * sign(R[2, 1]) * pi / 2
|
||||
else:
|
||||
phi = atan2(-R[2, 1], -R[2, 0])
|
||||
return omega, chi, phi
|
||||
|
||||
def checkSolution(omega, chi, phi):
|
||||
_, _, _, OMEGA, CHI, PHI = createVliegMatrices(
|
||||
None, None, None, omega, chi, phi)
|
||||
R = OMEGA * CHI * PHI
|
||||
RtimesH_phi = R * H_phi
|
||||
print ("R*H_phi=%s, Q_alpha=%s" %
|
||||
(R * H_phi.tolist(), Q_alpha.tolist()))
|
||||
return not differ(RtimesH_phi, Q_alpha, .0001)
|
||||
|
||||
# Using Vlieg section 7.2
|
||||
|
||||
# Needed througout:
|
||||
[ALPHA, DELTA, GAMMA, _, _, _] = createVliegMatrices(
|
||||
alpha, delta, gamma, None, None, None)
|
||||
|
||||
## Find Ro, one possible solution to equation 46: R*H_phi=Q_alpha
|
||||
|
||||
# Normalise hklPhiNorm (As it is currently normalised only to the
|
||||
# wavevector)
|
||||
normh = norm(hklPhiNorm)
|
||||
check(normh >= 1e-10, "reciprical lattice vector too close to zero")
|
||||
H_phi = hklPhiNorm * (1 / normh)
|
||||
|
||||
# Create Q_alpha from equation 47, (it comes normalised)
|
||||
Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
|
||||
Q_alpha = Q_alpha * (1 / norm(Q_alpha))
|
||||
|
||||
if self._getMode().name == '4cPhi':
|
||||
### Use the fixed value of phi as the final constraint ###
|
||||
phi = self._getParameter('phi') * TORAD
|
||||
PHI = calcPHI(phi)
|
||||
H_chi = PHI * H_phi
|
||||
omega, chi = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
|
||||
return (omega, chi, phi, None) # psi = None as not calculated
|
||||
else:
|
||||
### Use Bin as the final constraint ###
|
||||
|
||||
# Find a solution Ro to Ro*H_phi=Q_alpha
|
||||
Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)
|
||||
|
||||
## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
|
||||
D = self._findMatrixToTransformAIntoB(
|
||||
Q_alpha, matrix([[1], [0], [0]]))
|
||||
|
||||
## Find psi and create PSI
|
||||
|
||||
# eq 54: compute u=D*Ro*S*[[0],[0],[1]], the surface normal in
|
||||
# psi frame
|
||||
[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(
|
||||
self._getSigma() * TORAD, self._getTau() * TORAD)
|
||||
S = TAU * SIGMA
|
||||
[u1], [u2], [u3] = (D * Ro * S * matrix([[0], [0], [1]])).tolist()
|
||||
# TODO: If u points along 100, then any psi is a solution. Choose 0
|
||||
if not differ([u1, u2, u3], [1, 0, 0], 1e-9):
|
||||
psi = 0
|
||||
omega, chi, phi = equation49through59(psi)
|
||||
else:
|
||||
# equation 53: V=A*(D^-1)
|
||||
V = ALPHA * D.I
|
||||
v21 = V[1, 0]
|
||||
v22 = V[1, 1]
|
||||
v23 = V[1, 2]
|
||||
# equation 55
|
||||
a = v22 * u2 + v23 * u3
|
||||
b = v22 * u3 - v23 * u2
|
||||
c = -sin(Bin) - v21 * u1 # TODO: changed sign from paper
|
||||
|
||||
# equation 44
|
||||
# Try first root:
|
||||
def myatan2(y, x):
|
||||
if abs(x) < 1e-20 and abs(y) < 1e-20:
|
||||
return pi / 2
|
||||
else:
|
||||
return atan2(y, x)
|
||||
psi = 2 * myatan2(-(b - sqrt(b * b + a * a - c * c)), -(a + c))
|
||||
#psi = -acos(c/sqrt(a*a+b*b))+atan2(b,a)# -2*pi
|
||||
omega, chi, phi = equation49through59(psi)
|
||||
|
||||
# if u points along z axis, the psi could have been either 0 or 180
|
||||
if (not differ([u1, u2, u3], [0, 0, 1], 1e-9) and
|
||||
abs(psi - pi) < 1e-10):
|
||||
# Choose 0 to match that read up by angles-to-virtual-angles
|
||||
psi = 0.
|
||||
# if u points a long
|
||||
return (omega, chi, phi, psi)
|
||||
|
||||
def _anglesToPsi(self, pos, wavelength):
|
||||
"""
|
||||
pos assumed in radians. -180<= psi <= 180
|
||||
"""
|
||||
# Using Vlieg section 7.2
|
||||
|
||||
# Needed througout:
|
||||
[ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI] = createVliegMatrices(
|
||||
pos.alpha, pos.delta, pos.gamma, pos.omega, pos.chi, pos.phi)
|
||||
|
||||
# Solve equation 49 for psi, the rotation of the a reference solution
|
||||
# about Qalpha or H_phi##
|
||||
|
||||
# Find Ro, the reference solution to equation 46: R*H_phi=Q_alpha
|
||||
|
||||
# Create Q_alpha from equation 47, (it comes normalised)
|
||||
Q_alpha = ((DELTA * GAMMA) - ALPHA.I) * matrix([[0], [1], [0]])
|
||||
Q_alpha = Q_alpha * (1 / norm(Q_alpha))
|
||||
|
||||
# Finh H_phi
|
||||
h, k, l = self._anglesToHkl(pos, wavelength)
|
||||
H_phi = self._getUBMatrix() * matrix([[h], [k], [l]])
|
||||
normh = norm(H_phi)
|
||||
check(normh >= 1e-10, "reciprical lattice vector too close to zero")
|
||||
H_phi = H_phi * (1 / normh)
|
||||
|
||||
# Find a solution Ro to Ro*H_phi=Q_alpha
|
||||
# This the reference solution with zero azimuth (psi)
|
||||
Ro = self._findMatrixToTransformAIntoB(H_phi, Q_alpha)
|
||||
|
||||
# equation 48:
|
||||
R = OMEGA * CHI * PHI
|
||||
|
||||
## equation 50: Find a solution D to D*Q=norm(Q)*[[1],[0],[0]])
|
||||
D = self._findMatrixToTransformAIntoB(Q_alpha, matrix([[1], [0], [0]]))
|
||||
|
||||
# solve equation 49 for psi
|
||||
# D*R = PSI*D*Ro
|
||||
# D*R*(D*Ro)^-1 = PSI
|
||||
PSI = D * R * ((D * Ro).I)
|
||||
|
||||
# Find psi within PSI as defined in equation 51
|
||||
PSI_23 = PSI[1, 2]
|
||||
PSI_33 = PSI[2, 2]
|
||||
psi = atan2(PSI_23, PSI_33)
|
||||
|
||||
#print "PSI: ", PSI.tolist()
|
||||
return psi
|
||||
|
||||
def _findMatrixToTransformAIntoB(self, a, b):
|
||||
"""
|
||||
Finds a particular matrix Mo that transforms the unit vector a into the
|
||||
unit vector b. Thats is it finds Mo Mo*a=b. a and b 3x1 matrixes and Mo
|
||||
is a 3x3 matrix.
|
||||
|
||||
Throws an exception if this is not possible.
|
||||
"""
|
||||
# Maths from the appendix of "Angle caluculations
|
||||
# for a 5-circle diffractometer used for surface X-ray diffraction",
|
||||
# E. Vlieg, J.F. van der Veen, J.E. Macdonald and M. Miller, J. of
|
||||
# Applied Cryst. 20 (1987) 330.
|
||||
# - courtesy of Elias Vlieg again
|
||||
|
||||
# equation A2: compute angle xi between vectors a and b
|
||||
cosxi = dot3(a, b)
|
||||
try:
|
||||
cosxi = bound(cosxi)
|
||||
except ValueError:
|
||||
raise Exception("Could not compute cos(xi), vectors a=%f and b=%f "
|
||||
"must be of unit length" % (norm(a), norm(b)))
|
||||
xi = acos(cosxi)
|
||||
|
||||
# Mo is identity matrix if xi zero (math below would blow up)
|
||||
if abs(xi) < 1e-10:
|
||||
return I
|
||||
|
||||
# equation A3: c=cross(a,b)/sin(xi)
|
||||
c = cross3(a, b) * (1 / sin(xi))
|
||||
|
||||
# equation A4: find D matrix that transforms a into the frame
|
||||
# x = a; y = c x a; z = c. */
|
||||
a1 = a[0, 0]
|
||||
a2 = a[1, 0]
|
||||
a3 = a[2, 0]
|
||||
c1 = c[0, 0]
|
||||
c2 = c[1, 0]
|
||||
c3 = c[2, 0]
|
||||
D = matrix([[a1, a2, a3],
|
||||
[c2 * a3 - c3 * a2, c3 * a1 - c1 * a3, c1 * a2 - c2 * a1],
|
||||
[c1, c2, c3]])
|
||||
|
||||
# equation A5: create Xi to rotate by xi about z-axis
|
||||
XI = matrix([[cos(xi), -sin(xi), 0],
|
||||
[sin(xi), cos(xi), 0],
|
||||
[0, 0, 1]])
|
||||
|
||||
# eq A6: compute Mo
|
||||
return D.I * XI * D
|
||||
|
||||
|
||||
def _findOmegaAndChiToRotateHchiIntoQalpha(h_chi, q_alpha):
|
||||
"""
|
||||
(omega, chi) = _findOmegaAndChiToRotateHchiIntoQalpha(H_chi, Q_alpha)
|
||||
|
||||
Solves for omega and chi in OMEGA*CHI*h_chi = q_alpha where h_chi and
|
||||
q_alpha are 3x1 matrices with unit length. Omega and chi are returned in
|
||||
radians.
|
||||
|
||||
Throws an exception if this is not possible.
|
||||
"""
|
||||
|
||||
def solve(a, b, c):
|
||||
"""
|
||||
x1,x2 = solve(a , b, c)
|
||||
solves for the two solutions to x in equations of the form
|
||||
a*sin(x) + b*cos(x) = c
|
||||
by using the trigonometric identity
|
||||
a*sin(x) + b*cos(x) = a*sin(x)+b*cos(x)=sqrt(a**2+b**2)-sin(x+p)
|
||||
where
|
||||
p = atan(b/a) + {0 if a>=0
|
||||
{pi if a<0
|
||||
"""
|
||||
if a == 0:
|
||||
p = pi / 2 if b >= 0 else - pi / 2
|
||||
else:
|
||||
p = atan(b / a)
|
||||
if a < 0:
|
||||
p = p + pi
|
||||
guts = c / sqrt(a ** 2 + b ** 2)
|
||||
if guts < -1:
|
||||
guts = -1
|
||||
elif guts > 1:
|
||||
guts = 1
|
||||
left1 = asin(guts)
|
||||
left2 = pi - left1
|
||||
return (left1 - p, left2 - p)
|
||||
|
||||
def ne(a, b):
|
||||
"""
|
||||
shifts a and b in between -pi and pi and tests for near equality
|
||||
"""
|
||||
def shift(a):
|
||||
if a > pi:
|
||||
return a - 2 * pi
|
||||
elif a <= -pi:
|
||||
return a + 2 * pi
|
||||
else:
|
||||
return a
|
||||
return abs(shift(a) - shift(b)) < .0000001
|
||||
|
||||
# 1. Compute some solutions
|
||||
h_chi1 = h_chi[0, 0]
|
||||
h_chi2 = h_chi[1, 0]
|
||||
h_chi3 = h_chi[2, 0]
|
||||
q_alpha1 = q_alpha[0, 0]
|
||||
q_alpha2 = q_alpha[1, 0]
|
||||
q_alpha3 = q_alpha[2, 0]
|
||||
|
||||
try:
|
||||
# a) Solve for chi using Equation 3
|
||||
chi1, chi2 = solve(-h_chi1, h_chi3, q_alpha3)
|
||||
|
||||
# b) Solve for omega Equation 1 and each chi
|
||||
B = h_chi1 * cos(chi1) + h_chi3 * sin(chi1)
|
||||
eq1omega11, eq1omega12 = solve(h_chi2, B, q_alpha1)
|
||||
B = h_chi1 * cos(chi2) + h_chi3 * sin(chi2)
|
||||
eq1omega21, eq1omega22 = solve(h_chi2, B, q_alpha1)
|
||||
|
||||
# c) Solve for omega Equation 2 and each chi
|
||||
A = -h_chi1 * cos(chi1) - h_chi3 * sin(chi1)
|
||||
eq2omega11, eq2omega12 = solve(A, h_chi2, q_alpha2)
|
||||
A = -h_chi1 * cos(chi2) - h_chi3 * sin(chi2)
|
||||
eq2omega21, eq2omega22 = solve(A, h_chi2, q_alpha2)
|
||||
|
||||
except ValueError, e:
|
||||
raise ValueError(
|
||||
str(e) + ":\nProblem in fixed-phi calculation for:\nh_chi: " +
|
||||
str(h_chi.tolist()) + " q_alpha: " + str(q_alpha.tolist()))
|
||||
|
||||
# 2. Choose values of chi and omega that are solutions to equations 1 and 2
|
||||
solutions = []
|
||||
# a) Check the chi1 solutions
|
||||
print "_findOmegaAndChiToRotateHchiIntoQalpha:"
|
||||
if ne(eq1omega11, eq2omega11) or ne(eq1omega11, eq2omega12):
|
||||
# print "1: eq1omega11, chi1 = ", eq1omega11, chi1
|
||||
solutions.append((eq1omega11, chi1))
|
||||
if ne(eq1omega12, eq2omega11) or ne(eq1omega12, eq2omega12):
|
||||
# print "2: eq1omega12, chi1 = ", eq1omega12, chi1
|
||||
solutions.append((eq1omega12, chi1))
|
||||
# b) Check the chi2 solutions
|
||||
if ne(eq1omega21, eq2omega21) or ne(eq1omega21, eq2omega22):
|
||||
# print "3: eq1omega21, chi2 = ", eq1omega21, chi2
|
||||
solutions.append((eq1omega21, chi2))
|
||||
if ne(eq1omega22, eq2omega21) or ne(eq1omega22, eq2omega22):
|
||||
# print "4: eq1omega22, chi2 = ", eq1omega22, chi2
|
||||
solutions.append((eq1omega22, chi2))
|
||||
# print solutions
|
||||
# print "*"
|
||||
|
||||
if len(solutions) == 0:
|
||||
e = "h_chi: " + str(h_chi.tolist())
|
||||
e += " q_alpha: " + str(q_alpha.tolist())
|
||||
e += ("\nchi1:%4f eq1omega11:%4f eq1omega12:%4f eq2omega11:%4f "
|
||||
"eq2omega12:%4f" % (chi1 * TODEG, eq1omega11 * TODEG,
|
||||
eq1omega12 * TODEG, eq2omega11 * TODEG, eq2omega12 * TODEG))
|
||||
e += ("\nchi2:%4f eq1omega21:%4f eq1omega22:%4f eq2omega21:%4f "
|
||||
"eq2omega22:%4f" % (chi2 * TODEG, eq1omega21 * TODEG,
|
||||
eq1omega22 * TODEG, eq2omega21 * TODEG, eq2omega22 * TODEG))
|
||||
raise Exception("Could not find simultaneous solution for this fixed "
|
||||
"phi mode problem\n" + e)
|
||||
|
||||
if not PREFER_POSITIVE_CHI_SOLUTIONS:
|
||||
return solutions[0]
|
||||
|
||||
positive_chi_solutions = [sol for sol in solutions if sol[1] > 0]
|
||||
|
||||
if len(positive_chi_solutions) == 0:
|
||||
print "WARNING: A +ve chi solution was requested, but none were found."
|
||||
print " Returning a -ve one. Try the mapper"
|
||||
return solutions[0]
|
||||
|
||||
if len(positive_chi_solutions) > 1:
|
||||
print ("INFO: Multiple +ve chi solutions were found [(omega, chi) ...]"
|
||||
" = " + str(positive_chi_solutions))
|
||||
print " Returning the first"
|
||||
|
||||
return positive_chi_solutions[0]
|
||||
336
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/constraints.py
Normal file
336
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/constraints.py
Normal file
@@ -0,0 +1,336 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from copy import copy
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
|
||||
|
||||
class Mode(object):
|
||||
|
||||
def __init__(self, index, name, group, description, parameterNames,
|
||||
implemented=True):
|
||||
self.index = index
|
||||
self.group = group
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.parameterNames = parameterNames
|
||||
self.implemented = implemented
|
||||
|
||||
def __repr__(self):
|
||||
return "%i) %s" % (self.index, self.description)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def usesParameter(self, name):
|
||||
return name in self.parameterNames
|
||||
|
||||
|
||||
class ModeSelector(object):
|
||||
|
||||
def __init__(self, geometry, parameterManager=None,
|
||||
gammaParameterName='gamma'):
|
||||
self.parameter_manager = parameterManager
|
||||
self._geometry = geometry
|
||||
self._gammaParameterName = gammaParameterName
|
||||
self._modelist = {} # indexed by non-contiguous mode number
|
||||
self._configureAvailableModes()
|
||||
self._selectedIndex = 1
|
||||
|
||||
def setParameterManager(self, manager):
|
||||
"""
|
||||
Required as a ParameterManager and ModelSelector are mutually tied
|
||||
together in practice
|
||||
"""
|
||||
self.parameter_manager = manager
|
||||
|
||||
def _configureAvailableModes(self):
|
||||
|
||||
gammaName = self._gammaParameterName
|
||||
|
||||
ml = self._modelist
|
||||
|
||||
ml[0] = Mode(0, '4cFixedw', 'fourc', 'fourc fixed-bandlw',
|
||||
['alpha', gammaName, 'blw'], False)
|
||||
|
||||
ml[1] = Mode(1, '4cBeq', 'fourc', 'fourc bisecting',
|
||||
['alpha', gammaName])
|
||||
|
||||
ml[2] = Mode(2, '4cBin', 'fourc', 'fourc incoming',
|
||||
['alpha', gammaName, 'betain'])
|
||||
|
||||
ml[3] = Mode(3, '4cBout', 'fourc', 'fourc outgoing',
|
||||
['alpha', gammaName, 'betaout'])
|
||||
|
||||
ml[4] = Mode(4, '4cAzimuth', 'fourc', 'fourc azimuth',
|
||||
['alpha', gammaName, 'azimuth'], False)
|
||||
|
||||
ml[5] = Mode(5, '4cPhi', 'fourc', 'fourc fixed-phi',
|
||||
['alpha', gammaName, 'phi'])
|
||||
|
||||
ml[10] = Mode(10, '5cgBeq', 'fivecFixedGamma', 'fivec bisecting',
|
||||
[gammaName])
|
||||
|
||||
ml[11] = Mode(11, '5cgBin', 'fivecFixedGamma', 'fivec incoming',
|
||||
[gammaName, 'betain'])
|
||||
|
||||
ml[12] = Mode(12, '5cgBout', 'fivecFixedGamma', 'fivec outgoing',
|
||||
[gammaName, 'betaout'])
|
||||
|
||||
ml[13] = Mode(13, '5caBeq', 'fivecFixedAlpha', 'fivec bisecting',
|
||||
['alpha'])
|
||||
|
||||
ml[14] = Mode(14, '5caBin', 'fivecFixedAlpha', 'fivec incoming',
|
||||
['alpha', 'betain'])
|
||||
|
||||
ml[15] = Mode(15, '5caBout', 'fivecFixedAlpha', 'fivec outgoing',
|
||||
['alpha', 'betaout'])
|
||||
|
||||
ml[20] = Mode(20, '6czBeq', 'zaxis', 'zaxis bisecting',
|
||||
[])
|
||||
|
||||
ml[21] = Mode(21, '6czBin', 'zaxis', 'zaxis incoming',
|
||||
['betain'])
|
||||
|
||||
ml[22] = Mode(22, '6czBout', 'zaxis', 'zaxiz outgoing',
|
||||
['betaout'])
|
||||
|
||||
def setModeByIndex(self, index):
|
||||
if index in self._modelist:
|
||||
self._selectedIndex = index
|
||||
else:
|
||||
raise DiffcalcException("mode %r is not defined" % index)
|
||||
|
||||
def setModeByName(self, name):
|
||||
def findModeWithName(name):
|
||||
for index, mode in self._modelist.items():
|
||||
if mode.name == name:
|
||||
return index, mode
|
||||
raise ValueError
|
||||
|
||||
try:
|
||||
index, mode = findModeWithName(name)
|
||||
except ValueError:
|
||||
raise DiffcalcException(
|
||||
'Unknown mode. The diffraction calculator supports these '
|
||||
'modeSelector: %s' % self._supportedModes.keys())
|
||||
if self._geometry.supports_mode_group(mode.group):
|
||||
self._selectedIndex = index
|
||||
else:
|
||||
raise DiffcalcException(
|
||||
"Mode %s not supported for this diffractometer (%s)." %
|
||||
(name, self._geometry.name))
|
||||
|
||||
def getMode(self):
|
||||
return self._modelist[self._selectedIndex]
|
||||
|
||||
def reportCurrentMode(self):
|
||||
return self.getMode().__str__()
|
||||
|
||||
def reportAvailableModes(self):
|
||||
result = ''
|
||||
indecis = self._modelist.keys()
|
||||
indecis.sort()
|
||||
for index in indecis:
|
||||
mode = self._modelist[index]
|
||||
if self._geometry.supports_mode_group(mode.group):
|
||||
paramString = ''
|
||||
flags = ''
|
||||
pm = self.parameter_manager
|
||||
for paramName in pm.getUserChangableParametersForMode(mode):
|
||||
paramString += paramName + ", "
|
||||
if paramString:
|
||||
paramString = paramString[:-2] # remove trailing commas
|
||||
if not mode.implemented:
|
||||
flags += "(Not impl.)"
|
||||
result += ('%2i) %-15s (%s) %s\n' % (mode.index,
|
||||
mode.description, paramString, flags))
|
||||
return result
|
||||
|
||||
|
||||
class VliegParameterManager(object):
|
||||
|
||||
def __init__(self, geometry, hardware, modeSelector,
|
||||
gammaParameterName='gamma'):
|
||||
self._geometry = geometry
|
||||
self._hardware = hardware
|
||||
self._modeSelector = modeSelector
|
||||
self._gammaParameterName = gammaParameterName
|
||||
self._parameters = {}
|
||||
self._defineParameters()
|
||||
|
||||
def _defineParameters(self):
|
||||
# Set default fixed values (In degrees if angles)
|
||||
self._parameters = {}
|
||||
self._parameters['alpha'] = 0
|
||||
self._parameters[self._gammaParameterName] = 0
|
||||
self._parameters['blw'] = None # Busing and Levi omega!
|
||||
self._parameters['betain'] = None
|
||||
self._parameters['betaout'] = None
|
||||
self._parameters['azimuth'] = None
|
||||
self._parameters['phi'] = None
|
||||
|
||||
self._parameterDisplayOrder = (
|
||||
'alpha', self._gammaParameterName, 'betain', 'betaout', 'azimuth',
|
||||
'phi', 'blw')
|
||||
self._trackableParameters = ('alpha', self._gammaParameterName, 'phi')
|
||||
self._trackedParameters = []
|
||||
|
||||
# Overide parameters that are unchangable for this diffractometer
|
||||
for (name, value) in self._geometry.fixed_parameters.items():
|
||||
if name not in self._parameters:
|
||||
raise RuntimeError(
|
||||
"The %s diffractometer geometry specifies a fixed "
|
||||
"parameter %s that is not used by the diffractometer "
|
||||
"calculator" % (self._geometry.getName, name))
|
||||
self._parameters[name] = value
|
||||
|
||||
def reportAllParameters(self):
|
||||
self.update_tracked()
|
||||
result = ''
|
||||
for name in self._parameterDisplayOrder:
|
||||
flags = ""
|
||||
if not self._modeSelector.getMode().usesParameter(name):
|
||||
flags += '(not relevant in this mode)'
|
||||
if self._geometry.parameter_fixed(name):
|
||||
flags += ' (fixed by this diffractometer)'
|
||||
if self.isParameterTracked(name):
|
||||
flags += ' (tracking hardware)'
|
||||
value = self._parameters[name]
|
||||
if value is None:
|
||||
value = '---'
|
||||
else:
|
||||
value = float(value)
|
||||
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
|
||||
return result
|
||||
|
||||
def reportParametersUsedInCurrentMode(self):
|
||||
self.update_tracked()
|
||||
result = ''
|
||||
for name in self.getUserChangableParametersForMode(
|
||||
self._modeSelector.getMode()):
|
||||
flags = ""
|
||||
value = self._parameters[name]
|
||||
if value is None:
|
||||
value = '---'
|
||||
else:
|
||||
value = float(value)
|
||||
if self.isParameterTracked(name):
|
||||
flags += ' (tracking hardware)'
|
||||
result += '%s: %s %s\n' % (name.rjust(8), value, flags)
|
||||
return result
|
||||
|
||||
def getUserChangableParametersForMode(self, mode=None):
|
||||
"""
|
||||
(p1,p2...p3) = getUserChangableParametersForMode(mode) returns a list
|
||||
of parameters names used in this mode for this diffractometer geometry.
|
||||
Checks current mode if no mode specified.
|
||||
"""
|
||||
if mode is None:
|
||||
mode = self._mode
|
||||
result = []
|
||||
for name in self._parameterDisplayOrder:
|
||||
if self._isParameterChangeable(name, mode):
|
||||
result += [name]
|
||||
return result
|
||||
|
||||
### Fixed parameters stuff ###
|
||||
|
||||
def set_constraint(self, name, value):
|
||||
if not name in self._parameters:
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
if self._geometry.parameter_fixed(name):
|
||||
raise DiffcalcException(
|
||||
"The parameter %s cannot be changed: It has been fixed by the "
|
||||
"%s diffractometer geometry"
|
||||
% (name, self._geometry.name))
|
||||
if self.isParameterTracked(name):
|
||||
# for safety and to avoid confusion:
|
||||
raise DiffcalcException(
|
||||
"Cannot change parameter %s as it is set to track an axis.\n"
|
||||
"To turn this off use a command like 'trackalpha 0'." % name)
|
||||
|
||||
if not self.isParameterUsedInSelectedMode(name):
|
||||
print ("WARNING: The parameter %s is not used in mode %i" %
|
||||
(name, self._modeSelector.getMode().index))
|
||||
self._parameters[name] = value
|
||||
|
||||
def isParameterUsedInSelectedMode(self, name):
|
||||
return self._modeSelector.getMode().usesParameter(name)
|
||||
|
||||
def getParameterWithoutUpdatingTrackedParemeters(self, name):
|
||||
try:
|
||||
return self._parameters[name]
|
||||
except KeyError:
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
|
||||
def get_constraint(self, name):
|
||||
self.update_tracked()
|
||||
return self.getParameterWithoutUpdatingTrackedParemeters(name)
|
||||
|
||||
def getParameterDict(self):
|
||||
self.update_tracked()
|
||||
return copy(self._parameters)
|
||||
|
||||
@property
|
||||
def settable_constraint_names(self):
|
||||
"""list of all available constraints that have settable values"""
|
||||
return sorted(self.getParameterDict().keys())
|
||||
|
||||
def setTrackParameter(self, name, switch):
|
||||
if not name in self._parameters.keys():
|
||||
raise DiffcalcException("No fixed parameter %s is used by the "
|
||||
"diffraction calculator" % name)
|
||||
if not name in self._trackableParameters:
|
||||
raise DiffcalcException("Parameter %s is not trackable" % name)
|
||||
if not self._isParameterChangeable(name):
|
||||
print ("WARNING: Parameter %s is not used in mode %i" %
|
||||
(name, self._mode.index))
|
||||
if switch:
|
||||
if name not in self._trackedParameters:
|
||||
self._trackedParameters.append(name)
|
||||
else:
|
||||
if name in self._trackedParameters:
|
||||
self._trackedParameters.remove(name)
|
||||
|
||||
def isParameterTracked(self, name):
|
||||
return (name in self._trackedParameters)
|
||||
|
||||
def update_tracked(self):
|
||||
"""Note that the name of a tracked parameter MUST map into the name of
|
||||
an external diffractometer angle
|
||||
"""
|
||||
if self._trackedParameters:
|
||||
externalAnglePositionArray = self._hardware.get_position()
|
||||
externalAngleNames = list(self._hardware.get_axes_names())
|
||||
for name in self._trackedParameters:
|
||||
self._parameters[name] = \
|
||||
externalAnglePositionArray[externalAngleNames.index(name)]
|
||||
|
||||
def _isParameterChangeable(self, name, mode=None):
|
||||
"""
|
||||
Returns true if parameter is used in a mode (current mode if none
|
||||
specified), AND if it is not locked by the diffractometer geometry
|
||||
"""
|
||||
if mode is None:
|
||||
mode = self._modeSelector.getMode()
|
||||
return (mode.usesParameter(name) and
|
||||
not self._geometry.parameter_fixed(name))
|
||||
523
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/geometry.py
Normal file
523
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/geometry.py
Normal file
@@ -0,0 +1,523 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import tan, cos, sin, asin, atan, pi, fabs
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.util import x_rotation, z_rotation, y_rotation
|
||||
from diffcalc.util import AbstractPosition
|
||||
from diffcalc.util import bound, nearlyEqual
|
||||
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
def calcALPHA(alpha):
|
||||
return x_rotation(alpha)
|
||||
|
||||
|
||||
def calcDELTA(delta):
|
||||
return z_rotation(-delta)
|
||||
|
||||
|
||||
def calcGAMMA(gamma):
|
||||
return x_rotation(gamma)
|
||||
|
||||
|
||||
def calcOMEGA(omega):
|
||||
return z_rotation(-omega)
|
||||
|
||||
|
||||
def calcCHI(chi):
|
||||
return y_rotation(chi)
|
||||
|
||||
|
||||
def calcPHI(phi):
|
||||
return z_rotation(-phi)
|
||||
|
||||
|
||||
def createVliegMatrices(alpha=None, delta=None, gamma=None, omega=None,
|
||||
chi=None, phi=None):
|
||||
|
||||
ALPHA = None if alpha is None else calcALPHA(alpha)
|
||||
DELTA = None if delta is None else calcDELTA(delta)
|
||||
GAMMA = None if gamma is None else calcGAMMA(gamma)
|
||||
OMEGA = None if omega is None else calcOMEGA(omega)
|
||||
CHI = None if chi is None else calcCHI(chi)
|
||||
PHI = None if phi is None else calcPHI(phi)
|
||||
return ALPHA, DELTA, GAMMA, OMEGA, CHI, PHI
|
||||
|
||||
|
||||
def createVliegsSurfaceTransformationMatrices(sigma, tau):
|
||||
"""[SIGMA, TAU] = createVliegsSurfaceTransformationMatrices(sigma, tau)
|
||||
angles in radians
|
||||
"""
|
||||
SIGMA = matrix([[cos(sigma), 0, sin(sigma)],
|
||||
[0, 1, 0], \
|
||||
[-sin(sigma), 0, cos(sigma)]])
|
||||
|
||||
TAU = matrix([[cos(tau), sin(tau), 0],
|
||||
[-sin(tau), cos(tau), 0],
|
||||
[0, 0, 1]])
|
||||
return(SIGMA, TAU)
|
||||
|
||||
|
||||
def createVliegsPsiTransformationMatrix(psi):
|
||||
"""PSI = createPsiTransformationMatrices(psi)
|
||||
angles in radians
|
||||
"""
|
||||
return matrix([[1, 0, 0],
|
||||
[0, cos(psi), sin(psi)],
|
||||
[0, -sin(psi), cos(psi)]])
|
||||
|
||||
|
||||
class VliegPosition(AbstractPosition):
|
||||
"""The position of all six diffractometer axis"""
|
||||
def __init__(self, alpha=None, delta=None, gamma=None, omega=None,
|
||||
chi=None, phi=None):
|
||||
self.alpha = alpha
|
||||
self.delta = delta
|
||||
self.gamma = gamma
|
||||
self.omega = omega
|
||||
self.chi = chi
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return VliegPosition(self.alpha, self.delta, self.gamma, self.omega,
|
||||
self.chi, self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.alpha *= TORAD
|
||||
self.delta *= TORAD
|
||||
self.gamma *= TORAD
|
||||
self.omega *= TORAD
|
||||
self.chi *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.alpha *= TODEG
|
||||
self.delta *= TODEG
|
||||
self.gamma *= TODEG
|
||||
self.omega *= TODEG
|
||||
self.chi *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def inRadians(self):
|
||||
pos = self.clone()
|
||||
pos.changeToRadians()
|
||||
return pos
|
||||
|
||||
def inDegrees(self):
|
||||
pos = self.clone()
|
||||
pos.changeToDegrees()
|
||||
return pos
|
||||
|
||||
def nearlyEquals(self, pos2, maxnorm):
|
||||
for a, b in zip(self.totuple(), pos2.totuple()):
|
||||
if abs(a - b) > maxnorm:
|
||||
return False
|
||||
return True
|
||||
|
||||
def totuple(self):
|
||||
return (self.alpha, self.delta, self.gamma, self.omega,
|
||||
self.chi, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ("VliegPosition(alpha %r delta: %r gamma: %r omega: %r chi: %r"
|
||||
" phi: %r)" % self.totuple())
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, b):
|
||||
return self.nearlyEquals(b, .001)
|
||||
|
||||
|
||||
class VliegGeometry(object):
|
||||
|
||||
# Required methods
|
||||
|
||||
def __init__(self, name, supported_mode_groups, fixed_parameters,
|
||||
gamma_location):
|
||||
"""
|
||||
Set geometry name (String), list of supported mode groups (list of
|
||||
strings), list of axis names (list of strings). Define the parameters
|
||||
e.g. alpha and gamma for a four circle (dictionary). Define wether the
|
||||
gamma angle is on the 'arm' or the 'base'; used only by AngleCalculator
|
||||
to interpret the gamma parameter in fixed gamma mode: for instruments
|
||||
with gamma on the base, rather than on the arm as the code assume
|
||||
internally, the two methods physical_angles_to_internal_position and
|
||||
internal_position_to_physical_angles must still be used.
|
||||
"""
|
||||
if gamma_location not in ('arm', 'base', None):
|
||||
raise RuntimeError(
|
||||
"Gamma must be on either 'arm' or 'base' or None")
|
||||
|
||||
self.name = name
|
||||
self.supported_mode_groups = supported_mode_groups
|
||||
self.fixed_parameters = fixed_parameters
|
||||
self.gamma_location = gamma_location
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
def internal_position_to_physical_angles(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
### Do not overide these these ###
|
||||
|
||||
def supports_mode_group(self, name):
|
||||
return name in self.supported_mode_groups
|
||||
|
||||
def parameter_fixed(self, name): # parameter_fixed
|
||||
return name in self.fixed_parameters.keys()
|
||||
|
||||
|
||||
class SixCircleGammaOnArmGeometry(VliegGeometry):
|
||||
"""
|
||||
This six-circle diffractometer geometry simply passes through the
|
||||
angles from a six circle diffractometer with the same geometry and
|
||||
angle names as those defined in Vliegs's paper defined internally.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='sixc_gamma_on_arm',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma',
|
||||
'fivecFixedAlpha', 'zaxis'),
|
||||
fixed_parameters={},
|
||||
gamma_location='arm')
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 6), "Wrong length of input list"
|
||||
return VliegPosition(*physicalAngles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
return internalPosition.totuple()
|
||||
|
||||
|
||||
class SixCircleGeometry(VliegGeometry):
|
||||
"""
|
||||
This six-circle diffractometer geometry simply passes through the
|
||||
angles from a six circle diffractometer with the same geometry and
|
||||
angle names as those defined in Vliegs's paper defined internally.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='sixc',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma',
|
||||
'fivecFixedAlpha', 'zaxis'),
|
||||
fixed_parameters={},
|
||||
gamma_location='base')
|
||||
self.hardwareMonitor = None
|
||||
#(deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in radians)
|
||||
#(deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in radians)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 6), "Wrong length of input list"
|
||||
alpha, deltaB, gammaB, omega, chi, phi = physicalAngles
|
||||
(deltaA, gammaA) = gammaOnBaseToArm(
|
||||
deltaB * TORAD, gammaB * TORAD, alpha * TORAD)
|
||||
return VliegPosition(
|
||||
alpha, deltaA * TODEG, gammaA * TODEG, omega, chi, phi)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
alpha, deltaA, gammaA, omega, chi, phi = internalPosition.totuple()
|
||||
deltaB, gammaB = gammaOnArmToBase(
|
||||
deltaA * TORAD, gammaA * TORAD, alpha * TORAD)
|
||||
deltaB, gammaB = deltaB * TODEG, gammaB * TODEG
|
||||
|
||||
if self.hardwareMonitor is not None:
|
||||
gammaName = self.hardwareMonitor.get_axes_names()[2]
|
||||
minGamma = self.hardwareMonitor.get_lower_limit(gammaName)
|
||||
maxGamma = self.hardwareMonitor.get_upper_limit(gammaName)
|
||||
|
||||
if maxGamma is not None:
|
||||
if gammaB > maxGamma:
|
||||
gammaB = gammaB - 180
|
||||
deltaB = 180 - deltaB
|
||||
if minGamma is not None:
|
||||
if gammaB < minGamma:
|
||||
gammaB = gammaB + 180
|
||||
deltaB = 180 - deltaB
|
||||
|
||||
return alpha, deltaB, gammaB, omega, chi, phi
|
||||
|
||||
|
||||
class FivecWithGammaOnBase(SixCircleGeometry):
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(
|
||||
self,
|
||||
name='fivec_with_gamma',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma'),
|
||||
fixed_parameters={'alpha': 0.0},
|
||||
gamma_location='base')
|
||||
self.hardwareMonitor = None
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 5), "Wrong length of input list"
|
||||
return SixCircleGeometry.physical_angles_to_internal_position(
|
||||
self, (0,) + tuple(physicalAngles))
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
return SixCircleGeometry.internal_position_to_physical_angles(
|
||||
self, internalPosition)[1:]
|
||||
|
||||
|
||||
class Fivec(VliegGeometry):
|
||||
"""
|
||||
This five-circle diffractometer geometry is for diffractometers with the
|
||||
same geometry and angle names as those defined in Vliegs's paper defined
|
||||
internally, but with no out plane detector arm gamma."""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(self,
|
||||
name='fivec',
|
||||
supported_mode_groups=('fourc', 'fivecFixedGamma'),
|
||||
fixed_parameters={'gamma': 0.0},
|
||||
gamma_location='arm'
|
||||
)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 5), "Wrong length of input list"
|
||||
physicalAngles = tuple(physicalAngles)
|
||||
angles = physicalAngles[0:2] + (0.0,) + physicalAngles[2:]
|
||||
return VliegPosition(*angles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
sixAngles = internalPosition.totuple()
|
||||
return sixAngles[0:2] + sixAngles[3:]
|
||||
|
||||
|
||||
class Fourc(VliegGeometry):
|
||||
"""
|
||||
This five-circle diffractometer geometry is for diffractometers with the
|
||||
same geometry and angle names as those defined in Vliegs's paper defined
|
||||
internally, but with no out plane detector arm gamma."""
|
||||
|
||||
def __init__(self):
|
||||
VliegGeometry.__init__(self,
|
||||
name='fourc',
|
||||
supported_mode_groups=('fourc'),
|
||||
fixed_parameters={'gamma': 0.0, 'alpha': 0.0},
|
||||
gamma_location='arm'
|
||||
)
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
assert (len(physicalAngles) == 4), "Wrong length of input list"
|
||||
physicalAngles = tuple(physicalAngles)
|
||||
angles = (0.0, physicalAngles[0], 0.0) + physicalAngles[1:]
|
||||
return VliegPosition(*angles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
""" (a,d,g,o,c,p) = physicalAnglesToInternal(a,d,g,o,c,p)
|
||||
"""
|
||||
sixAngles = internalPosition.totuple()
|
||||
return sixAngles[1:2] + sixAngles[3:]
|
||||
|
||||
|
||||
def sign(x):
|
||||
if x < 0:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
"""
|
||||
Based on: Elias Vlieg, "A (2+3)-Type Surface Diffractometer: Mergence of
|
||||
the z-axis and (2+2)-Type Geometries", J. Appl. Cryst. (1998). 31.
|
||||
198-203
|
||||
"""
|
||||
|
||||
|
||||
def solvesEq8(alpha, deltaA, gammaA, deltaB, gammaB):
|
||||
tol = 1e-6
|
||||
return (nearlyEqual(sin(deltaA) * cos(gammaA), sin(deltaB), tol) and
|
||||
nearlyEqual(cos(deltaA) * cos(gammaA),
|
||||
cos(gammaB - alpha) * cos(deltaB), tol) and
|
||||
nearlyEqual(sin(gammaA), sin(gammaB - alpha) * cos(deltaB), tol))
|
||||
|
||||
|
||||
GAMMAONBASETOARM_WARNING = '''
|
||||
WARNING: This diffractometer has the gamma circle attached to the
|
||||
base rather than the end of
|
||||
the delta arm as Vlieg's paper defines. A conversion has
|
||||
been made from the physical angles to their internal
|
||||
representation (gamma-on-base-to-arm). This conversion has
|
||||
forced gamma to be positive by applying the mapping:
|
||||
|
||||
delta --> 180+delta
|
||||
gamma --> 180+gamma.
|
||||
|
||||
This should have no adverse effect.
|
||||
'''
|
||||
|
||||
|
||||
def gammaOnBaseToArm(deltaB, gammaB, alpha):
|
||||
"""
|
||||
(deltaA, gammaA) = gammaOnBaseToArm(deltaB, gammaB, alpha) (all in
|
||||
radians)
|
||||
|
||||
Maps delta and gamma for an instrument where the gamma circle rests on
|
||||
the base to the case where it is on the delta arm.
|
||||
|
||||
There are always two possible solutions. To get the second apply the
|
||||
transform:
|
||||
|
||||
delta --> 180+delta (flip to opposite side of circle)
|
||||
gamma --> 180+gamma (flip to opposite side of circle)
|
||||
|
||||
This code will return the solution where gamma is between 0 and 180.
|
||||
"""
|
||||
|
||||
### Equation11 ###
|
||||
if fabs(cos(gammaB - alpha)) < 1e-20:
|
||||
deltaA1 = sign(tan(deltaB)) * sign(cos(gammaB - alpha)) * pi / 2
|
||||
else:
|
||||
deltaA1 = atan(tan(deltaB) / cos(gammaB - alpha))
|
||||
# ...second root
|
||||
if deltaA1 <= 0:
|
||||
deltaA2 = deltaA1 + pi
|
||||
else:
|
||||
deltaA2 = deltaA1 - pi
|
||||
|
||||
### Equation 12 ###
|
||||
gammaA1 = asin(bound(cos(deltaB) * sin(gammaB - alpha)))
|
||||
# ...second root
|
||||
if gammaA1 >= 0:
|
||||
gammaA2 = pi - gammaA1
|
||||
else:
|
||||
gammaA2 = -pi - gammaA1
|
||||
|
||||
# Choose the delta solution that fits equations 8
|
||||
if solvesEq8(alpha, deltaA1, gammaA1, deltaB, gammaB):
|
||||
deltaA, gammaA = deltaA1, gammaA1
|
||||
elif solvesEq8(alpha, deltaA2, gammaA1, deltaB, gammaB):
|
||||
deltaA, gammaA = deltaA2, gammaA1
|
||||
print "gammaOnBaseToArm choosing 2nd delta root (to internal)"
|
||||
elif solvesEq8(alpha, deltaA1, gammaA2, deltaB, gammaB):
|
||||
print "gammaOnBaseToArm choosing 2nd gamma root (to internal)"
|
||||
deltaA, gammaA = deltaA1, gammaA2
|
||||
elif solvesEq8(alpha, deltaA2, gammaA2, deltaB, gammaB):
|
||||
print "gammaOnBaseToArm choosing 2nd delta root and 2nd gamma root"
|
||||
deltaA, gammaA = deltaA2, gammaA2
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"No valid solutions found mapping from gamma-on-base to gamma-on-arm")
|
||||
|
||||
return deltaA, gammaA
|
||||
|
||||
GAMMAONARMTOBASE_WARNING = '''
|
||||
WARNING: This diffractometer has the gamma circle attached to the base
|
||||
rather than the end of the delta arm as Vlieg's paper defines.
|
||||
A conversion has been made from the internal representation of
|
||||
angles to physical angles (gamma-on-arm-to-base). This
|
||||
conversion has forced gamma to be positive by applying the
|
||||
mapping:
|
||||
|
||||
delta --> 180-delta
|
||||
gamma --> 180+gamma.
|
||||
|
||||
This should have no adverse effect.
|
||||
'''
|
||||
|
||||
|
||||
def gammaOnArmToBase(deltaA, gammaA, alpha):
|
||||
"""
|
||||
(deltaB, gammaB) = gammaOnArmToBase(deltaA, gammaA, alpha) (all in
|
||||
radians)
|
||||
|
||||
Maps delta and gamma for an instrument where the gamma circle is on
|
||||
the delta arm to the case where it rests on the base.
|
||||
|
||||
There are always two possible solutions. To get the second apply the
|
||||
transform:
|
||||
|
||||
delta --> 180-delta (reflect and flip to opposite side)
|
||||
gamma --> 180+gamma (flip to opposite side)
|
||||
|
||||
This code will return the solution where gamma is positive, but will
|
||||
warn if a sign change was made.
|
||||
"""
|
||||
|
||||
### Equation 9 ###
|
||||
deltaB1 = asin(bound(sin(deltaA) * cos(gammaA)))
|
||||
# ...second root:
|
||||
if deltaB1 >= 0:
|
||||
deltaB2 = pi - deltaB1
|
||||
else:
|
||||
deltaB2 = -pi - deltaB1
|
||||
|
||||
### Equation 10 ###:
|
||||
if fabs(cos(deltaA)) < 1e-20:
|
||||
gammaB1 = sign(tan(gammaA)) * sign(cos(deltaA)) * pi / 2 + alpha
|
||||
else:
|
||||
gammaB1 = atan(tan(gammaA) / cos(deltaA)) + alpha
|
||||
#... second root:
|
||||
if gammaB1 <= 0:
|
||||
gammaB2 = gammaB1 + pi
|
||||
else:
|
||||
gammaB2 = gammaB1 - pi
|
||||
|
||||
### Choose the solution that fits equation 8 ###
|
||||
if (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB1) and
|
||||
0 <= gammaB1 <= pi):
|
||||
deltaB, gammaB = deltaB1, gammaB1
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB1) and
|
||||
0 <= gammaB1 <= pi):
|
||||
deltaB, gammaB = deltaB2, gammaB1
|
||||
print "gammaOnArmToBase choosing 2nd delta root (to physical)"
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB1, gammaB2) and
|
||||
0 <= gammaB2 <= pi):
|
||||
print "gammaOnArmToBase choosing 2nd gamma root (to physical)"
|
||||
deltaB, gammaB = deltaB1, gammaB2
|
||||
elif (solvesEq8(alpha, deltaA, gammaA, deltaB2, gammaB2)
|
||||
and 0 <= gammaB2 <= pi):
|
||||
print "gammaOnArmToBase choosing 2nd delta root and 2nd gamma root"
|
||||
deltaB, gammaB = deltaB2, gammaB2
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"No valid solutions found mapping gamma-on-arm to gamma-on-base")
|
||||
|
||||
return deltaB, gammaB
|
||||
139
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/hkl.py
Normal file
139
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/hkl.py
Normal file
@@ -0,0 +1,139 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
from diffcalc import settings
|
||||
|
||||
|
||||
from diffcalc.ub import ub
|
||||
from diffcalc.hkl.vlieg.calc import VliegHklCalculator
|
||||
|
||||
|
||||
__all__ = ['hklmode', 'setpar', 'trackalpha', 'trackgamma', 'trackphi',
|
||||
'parameter_manager', 'hklcalc']
|
||||
|
||||
|
||||
hklcalc = VliegHklCalculator(ub.ubcalc, settings.geometry, settings.hardware)
|
||||
|
||||
parameter_manager = hklcalc.parameter_manager
|
||||
|
||||
def __str__(self):
|
||||
return hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def hklmode(num=None):
|
||||
"""hklmode {num} -- changes mode or shows current and available modes and all settings""" #@IgnorePep8
|
||||
|
||||
if num is None:
|
||||
print hklcalc.__str__()
|
||||
else:
|
||||
hklcalc.mode_selector.setModeByIndex(int(num))
|
||||
pm = hklcalc.parameter_manager
|
||||
print (hklcalc.mode_selector.reportCurrentMode() + "\n" +
|
||||
pm.reportParametersUsedInCurrentMode())
|
||||
|
||||
def _setParameter(name, value):
|
||||
hklcalc.parameter_manager.set_constraint(name, value)
|
||||
|
||||
def _getParameter(name):
|
||||
return hklcalc.parameter_manager.get_constraint(name)
|
||||
|
||||
@command
|
||||
def setpar(scannable_or_string=None, val=None):
|
||||
"""setpar {parameter_scannable {{val}} -- sets or shows a parameter'
|
||||
setpar {parameter_name {val}} -- sets or shows a parameter'
|
||||
"""
|
||||
|
||||
if scannable_or_string is None:
|
||||
#show all
|
||||
parameterDict = hklcalc.parameter_manager.getParameterDict()
|
||||
names = parameterDict.keys()
|
||||
names.sort()
|
||||
for name in names:
|
||||
print _representParameter(name)
|
||||
else:
|
||||
name = getNameFromScannableOrString(scannable_or_string)
|
||||
if val is None:
|
||||
_representParameter(name)
|
||||
else:
|
||||
oldval = _getParameter(name)
|
||||
_setParameter(name, float(val))
|
||||
print _representParameter(name, oldval, float(val))
|
||||
|
||||
def _representParameter(name, oldval=None, newval=None):
|
||||
flags = ''
|
||||
if hklcalc.parameter_manager.isParameterTracked(name):
|
||||
flags += '(tracking hardware) '
|
||||
if settings.geometry.parameter_fixed(name): # @UndefinedVariable
|
||||
flags += '(fixed by geometry) '
|
||||
pm = hklcalc.parameter_manager
|
||||
if not pm.isParameterUsedInSelectedMode(name):
|
||||
flags += '(not relevant in this mode) '
|
||||
if oldval is None:
|
||||
val = _getParameter(name)
|
||||
if val is None:
|
||||
val = "---"
|
||||
else:
|
||||
val = str(val)
|
||||
return "%s: %s %s" % (name, val, flags)
|
||||
else:
|
||||
return "%s: %s --> %f %s" % (name, oldval, newval, flags)
|
||||
|
||||
def _checkInputAndSetOrShowParameterTracking(name, b=None):
|
||||
"""
|
||||
for track-parameter commands: If no args displays parameter settings,
|
||||
otherwise sets the tracking switch for the given parameter and displays
|
||||
settings.
|
||||
"""
|
||||
# set if arg given
|
||||
if b is not None:
|
||||
hklcalc.parameter_manager.setTrackParameter(name, b)
|
||||
# Display:
|
||||
lastValue = _getParameter(name)
|
||||
if lastValue is None:
|
||||
lastValue = "---"
|
||||
else:
|
||||
lastValue = str(lastValue)
|
||||
flags = ''
|
||||
if hklcalc.parameter_manager.isParameterTracked(name):
|
||||
flags += '(tracking hardware)'
|
||||
print "%s: %s %s" % (name, lastValue, flags)
|
||||
|
||||
@command
|
||||
def trackalpha(b=None):
|
||||
"""trackalpha {boolean} -- determines wether alpha parameter will track alpha axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('alpha', b)
|
||||
|
||||
@command
|
||||
def trackgamma(b=None):
|
||||
"""trackgamma {boolean} -- determines wether gamma parameter will track alpha axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('gamma', b)
|
||||
|
||||
@command
|
||||
def trackphi(b=None):
|
||||
"""trackphi {boolean} -- determines wether phi parameter will track phi axis""" #@IgnorePep8
|
||||
_checkInputAndSetOrShowParameterTracking('phi', b)
|
||||
|
||||
|
||||
commands_for_help = ['Mode',
|
||||
hklmode,
|
||||
setpar,
|
||||
trackalpha,
|
||||
trackgamma,
|
||||
trackphi]
|
||||
480
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/transform.py
Normal file
480
script/__Lib/diffcalc_old/diffcalc/hkl/vlieg/transform.py
Normal file
@@ -0,0 +1,480 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.util import command
|
||||
|
||||
from copy import copy
|
||||
from math import pi
|
||||
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition as P
|
||||
|
||||
SMALL = 1e-10
|
||||
|
||||
|
||||
class Transform(object):
|
||||
|
||||
def transform(self, pos):
|
||||
raise RuntimeError('Not implemented')
|
||||
|
||||
|
||||
### Transforms, currently for definition and testing the theory only
|
||||
|
||||
class TransformC(Transform):
|
||||
'''Flip omega, invert chi and flip phi
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.omega -= 180
|
||||
pos.chi *= -1
|
||||
pos.phi -= 180
|
||||
return pos
|
||||
|
||||
|
||||
class TransformB(Transform):
|
||||
'''Flip chi, and invert and flip omega
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.chi -= 180
|
||||
pos.omega = 180 - pos.omega
|
||||
return pos
|
||||
|
||||
|
||||
class TransformA(Transform):
|
||||
'''Invert scattering plane: invert delta and omega and flip chi'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
pos.delta *= -1
|
||||
pos.omega *= -1
|
||||
pos.chi -= 180
|
||||
return pos
|
||||
|
||||
|
||||
class TransformCInRadians(Transform):
|
||||
'''
|
||||
Flip omega, invert chi and flip phi. Using radians and keeping
|
||||
-pi<omega<=pi and 0<=phi<=360
|
||||
'''
|
||||
def transform(self, pos):
|
||||
pos = pos.clone()
|
||||
if pos.omega > 0:
|
||||
pos.omega -= pi
|
||||
else:
|
||||
pos.omega += pi
|
||||
pos.chi *= -1
|
||||
pos.phi += pi
|
||||
return pos
|
||||
|
||||
|
||||
###
|
||||
|
||||
transformsFromSector = {
|
||||
0: (),
|
||||
1: ('c',),
|
||||
2: ('a',),
|
||||
3: ('a', 'c'),
|
||||
4: ('b', 'c'),
|
||||
5: ('b',),
|
||||
6: ('a', 'b', 'c'),
|
||||
7: ('a', 'b')
|
||||
}
|
||||
|
||||
sectorFromTransforms = {}
|
||||
for k, v in transformsFromSector.iteritems():
|
||||
sectorFromTransforms[v] = k
|
||||
|
||||
|
||||
class VliegPositionTransformer(object):
|
||||
|
||||
def __init__(self, geometry, hardware, solution_transformer):
|
||||
self._geometry = geometry
|
||||
self._hardware = hardware
|
||||
self._solution_transformer = solution_transformer
|
||||
solution_transformer.limitCheckerFunction = self.is_position_within_limits
|
||||
|
||||
def transform(self, pos):
|
||||
# 1. Choose the correct sector/transforms
|
||||
return self._solution_transformer.transformPosition(pos)
|
||||
|
||||
def is_position_within_limits(self, position):
|
||||
'''where position is Position object in degrees'''
|
||||
angleTuple = self._geometry.internal_position_to_physical_angles(position)
|
||||
angleTuple = self._hardware.cut_angles(angleTuple)
|
||||
return self._hardware.is_position_within_limits(angleTuple)
|
||||
|
||||
|
||||
class VliegTransformSelector(object):
|
||||
'''All returned angles are between -180. and 180. -180.<=angle<180.
|
||||
'''
|
||||
### basic sector selection
|
||||
|
||||
def __init__(self):
|
||||
self.transforms = []
|
||||
self.autotransforms = []
|
||||
self.autosectors = []
|
||||
self.limitCheckerFunction = None # inject
|
||||
self.sector = None
|
||||
self.setSector(0)
|
||||
|
||||
def setSector(self, sector):
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
self.sector = sector
|
||||
self.transforms = list(transformsFromSector[sector])
|
||||
|
||||
def setTransforms(self, transformList):
|
||||
transformList = list(transformList)
|
||||
transformList.sort()
|
||||
self.sector = sectorFromTransforms[tuple(transformList)]
|
||||
self.transforms = transformList
|
||||
|
||||
def addTransorm(self, transformName):
|
||||
if transformName not in ('a', 'b', 'c'):
|
||||
raise ValueError('%s is not a recognised transform. Try a, b or c'
|
||||
% transformName)
|
||||
if transformName in self.transforms:
|
||||
print "WARNING, transform %s is already selected"
|
||||
else:
|
||||
self.setTransforms(self.transforms + [transformName])
|
||||
|
||||
def removeTransorm(self, transformName):
|
||||
if transformName not in ('a', 'b', 'c'):
|
||||
raise ValueError('%s is not a recognised transform. Try a, b or c'
|
||||
% transformName)
|
||||
if transformName in self.transforms:
|
||||
new = copy(self.transforms)
|
||||
new.remove(transformName)
|
||||
self.setTransforms(new)
|
||||
else:
|
||||
print "WARNING, transform %s was not selected" % transformName
|
||||
|
||||
def addAutoTransorm(self, transformOrSector):
|
||||
'''
|
||||
If input is a string (letter), tags one of the transofrms as being a
|
||||
candidate for auto application. If a number, tags a sector as being a
|
||||
candidate for auto application, and removes similar tags for any
|
||||
transforms (as the two are incompatable).
|
||||
'''
|
||||
if type(transformOrSector) == str:
|
||||
transform = transformOrSector
|
||||
if transform not in ('a', 'b', 'c'):
|
||||
raise ValueError(
|
||||
'%s is not a recognised transform. Try a, b or c' %
|
||||
transform)
|
||||
if transform not in self.autotransforms:
|
||||
self.autosectors = []
|
||||
self.autotransforms.append(transform)
|
||||
else:
|
||||
print "WARNING: %s is already set to auto apply" % transform
|
||||
elif type(transformOrSector) == int:
|
||||
sector = transformOrSector
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
if sector not in self.autosectors:
|
||||
self.autotransforms = []
|
||||
self.autosectors.append(sector)
|
||||
else:
|
||||
print "WARNING: %i is already set to auto apply" % sector
|
||||
else:
|
||||
raise ValueError("Input must be 'a', 'b' or 'c', "
|
||||
"or 1,2,3,4,5,6 or 7.")
|
||||
|
||||
def removeAutoTransform(self, transformOrSector):
|
||||
if type(transformOrSector) == str:
|
||||
transform = transformOrSector
|
||||
if transform not in ('a', 'b', 'c'):
|
||||
raise ValueError("%s is not a recognised transform. "
|
||||
"Try a, b or c" % transform)
|
||||
if transform in self.autotransforms:
|
||||
self.autotransforms.remove(transform)
|
||||
else:
|
||||
print "WARNING: %s is not set to auto apply" % transform
|
||||
elif type(transformOrSector) == int:
|
||||
sector = transformOrSector
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
if sector in self.autosectors:
|
||||
self.autosectors.remove(sector)
|
||||
else:
|
||||
print "WARNING: %s is not set to auto apply" % sector
|
||||
else:
|
||||
raise ValueError("Input must be 'a', 'b' or 'c', "
|
||||
"or 1,2,3,4,5,6 or 7.")
|
||||
|
||||
def setAutoSectors(self, sectorList):
|
||||
for sector in sectorList:
|
||||
if not 0 <= sector <= 7:
|
||||
raise ValueError('%i must between 0 and 7.' % sector)
|
||||
self.autosectors = list(sectorList)
|
||||
|
||||
def transformPosition(self, pos):
|
||||
pos = self.transformNWithoutCut(self.sector, pos)
|
||||
cutpos = self.cutPosition(pos)
|
||||
# -180 <= cutpos < 180, NOT the externally applied cuts
|
||||
if len(self.autosectors) > 0:
|
||||
if self.is_position_within_limits(cutpos):
|
||||
return cutpos
|
||||
else:
|
||||
return self.autoTransformPositionBySector(cutpos)
|
||||
if len(self.autotransforms) > 0:
|
||||
if self.is_position_within_limits(cutpos):
|
||||
return cutpos
|
||||
else:
|
||||
return self.autoTransformPositionByTransforms(pos)
|
||||
#else
|
||||
return cutpos
|
||||
|
||||
def transformNWithoutCut(self, n, pos):
|
||||
|
||||
if n == 0:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
pos.omega, pos.chi, pos.phi)
|
||||
if n == 1:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
pos.omega - 180., -pos.chi, pos.phi - 180.)
|
||||
if n == 2:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
-pos.omega, pos.chi - 180., pos.phi)
|
||||
if n == 3:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
180. - pos.omega, 180. - pos.chi, pos.phi - 180.)
|
||||
if n == 4:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
-pos.omega, 180. - pos.chi, pos.phi - 180.)
|
||||
if n == 5:
|
||||
return P(pos.alpha, pos.delta, pos.gamma,
|
||||
180. - pos.omega, pos.chi - 180., pos.phi)
|
||||
if n == 6:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
pos.omega, -pos.chi, pos.phi - 180.)
|
||||
if n == 7:
|
||||
return P(pos.alpha, -pos.delta, pos.gamma,
|
||||
pos.omega - 180., pos.chi, pos.phi)
|
||||
else:
|
||||
raise Exception("sector must be between 0 and 7")
|
||||
|
||||
### autosector
|
||||
|
||||
def hasAutoSectorsOrTransformsToApply(self):
|
||||
return len(self.autosectors) > 0 or len(self.autotransforms) > 0
|
||||
|
||||
def autoTransformPositionBySector(self, pos):
|
||||
okaysectors = []
|
||||
okaypositions = []
|
||||
for sector in self.autosectors:
|
||||
newpos = self.transformNWithoutCut(sector, pos)
|
||||
if self.is_position_within_limits(newpos):
|
||||
okaysectors.append(sector)
|
||||
okaypositions.append(newpos)
|
||||
if len(okaysectors) == 0:
|
||||
raise Exception(
|
||||
"Autosector could not find a sector (from %s) to move %s into "
|
||||
"limits." % (self.autosectors, str(pos)))
|
||||
if len(okaysectors) > 1:
|
||||
print ("WARNING: Autosector found multiple sectors that would "
|
||||
"move %s to move into limits: %s" % (str(pos), okaysectors))
|
||||
|
||||
print ("INFO: Autosector changed sector from %i to %i" %
|
||||
(self.sector, okaysectors[0]))
|
||||
self.sector = okaysectors[0]
|
||||
return okaypositions[0]
|
||||
|
||||
def autoTransformPositionByTransforms(self, pos):
|
||||
possibleTransforms = self.createListOfPossibleTransforms()
|
||||
okaytransforms = []
|
||||
okaypositions = []
|
||||
for transforms in possibleTransforms:
|
||||
sector = sectorFromTransforms[tuple(transforms)]
|
||||
newpos = self.cutPosition(self.transformNWithoutCut(sector, pos))
|
||||
if self.is_position_within_limits(newpos):
|
||||
okaytransforms.append(transforms)
|
||||
okaypositions.append(newpos)
|
||||
if len(okaytransforms) == 0:
|
||||
raise Exception(
|
||||
"Autosector could not find a sector (from %r) to move %r into "
|
||||
"limits." % (self.autosectors, pos))
|
||||
if len(okaytransforms) > 1:
|
||||
print ("WARNING: Autosector found multiple sectors that would "
|
||||
"move %s to move into limits: %s" %
|
||||
(repr(pos), repr(okaytransforms)))
|
||||
|
||||
print ("INFO: Autosector changed selected transforms from %r to %r" %
|
||||
(self.transforms, okaytransforms[0]))
|
||||
self.setTransforms(okaytransforms[0])
|
||||
return okaypositions[0]
|
||||
|
||||
def createListOfPossibleTransforms(self):
|
||||
def vary(possibleTransforms, name):
|
||||
result = []
|
||||
for transforms in possibleTransforms:
|
||||
# add the original.
|
||||
result.append(transforms)
|
||||
# add a modified one
|
||||
toadd = list(copy(transforms))
|
||||
if name in transforms:
|
||||
toadd.remove(name)
|
||||
else:
|
||||
toadd.append(name)
|
||||
toadd.sort()
|
||||
result.append(toadd)
|
||||
return result
|
||||
# start with the currently selected list of transforms
|
||||
if len(self.transforms) == 0:
|
||||
possibleTransforms = [()]
|
||||
else:
|
||||
possibleTransforms = copy(self.transforms)
|
||||
|
||||
for name in self.autotransforms:
|
||||
possibleTransforms = vary(possibleTransforms, name)
|
||||
|
||||
return possibleTransforms
|
||||
|
||||
def is_position_within_limits(self, pos):
|
||||
'''where pos os a poistion object in degrees'''
|
||||
return self.limitCheckerFunction(pos)
|
||||
|
||||
def __repr__(self):
|
||||
def createPrefix(transform):
|
||||
if transform in self.transforms:
|
||||
s = '*on* '
|
||||
else:
|
||||
s = 'off '
|
||||
if len(self.autotransforms) > 0:
|
||||
if transform in self.autotransforms:
|
||||
s += '*auto*'
|
||||
else:
|
||||
s += ' '
|
||||
return s
|
||||
s = 'Transforms/sector:\n'
|
||||
s += (' %s (a transform) Invert scattering plane: invert delta and '
|
||||
'omega and flip chi\n' % createPrefix('a'))
|
||||
s += (' %s (b transform) Flip chi, and invert and flip omega\n' %
|
||||
createPrefix('b'))
|
||||
s += (' %s (c transform) Flip omega, invert chi and flip phi\n' %
|
||||
createPrefix('c'))
|
||||
s += ' Current sector: %i (Spec fourc equivalent)\n' % self.sector
|
||||
if len(self.autosectors) > 0:
|
||||
s += ' Auto sectors: %s\n' % self.autosectors
|
||||
return s
|
||||
|
||||
def cutPosition(self, position):
|
||||
'''Cuts angles at -180.; moves each argument between -180. and 180.
|
||||
'''
|
||||
def cut(a):
|
||||
if a is None:
|
||||
return None
|
||||
else:
|
||||
if a < (-180. - SMALL):
|
||||
return a + 360.
|
||||
if a > (180. + SMALL):
|
||||
return a - 360.
|
||||
return a
|
||||
return P(cut(position.alpha), cut(position.delta), cut(position.gamma),
|
||||
cut(position.omega), cut(position.chi), cut(position.phi))
|
||||
|
||||
|
||||
def getNameFromScannableOrString(o):
|
||||
try: # it may be a scannable
|
||||
return o.getName()
|
||||
except AttributeError:
|
||||
return str(o)
|
||||
|
||||
|
||||
class TransformCommands(object):
|
||||
|
||||
def __init__(self, sector_selector):
|
||||
self._sectorSelector = sector_selector
|
||||
|
||||
@command
|
||||
def transform(self):
|
||||
"""transform -- show transform configuration"""
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def transforma(self, *args):
|
||||
"""transforma {on|off|auto|manual} -- configure transform A application
|
||||
"""
|
||||
self._transform('transforma', 'a', args)
|
||||
|
||||
@command
|
||||
def transformb(self, *args):
|
||||
"""transformb {on|off|auto|manual} -- configure transform B application
|
||||
"""
|
||||
self._transform('transformb', 'b', args)
|
||||
|
||||
@command
|
||||
def transformc(self, *args):
|
||||
"""transformc {on|off|auto|manual} -- configure transform C application
|
||||
"""
|
||||
|
||||
self._transform('transformc', 'c', args)
|
||||
|
||||
def _transform(self, commandName, transformName, args):
|
||||
if len(args) == 0:
|
||||
print self._sectorSelector.__repr__()
|
||||
return
|
||||
# get name
|
||||
if len(args) != 1:
|
||||
raise TypeError()
|
||||
if type(args[0]) is not str:
|
||||
raise TypeError()
|
||||
|
||||
ss = self._sectorSelector
|
||||
if args[0] == 'on':
|
||||
ss.addTransorm(transformName)
|
||||
elif args[0] == 'off':
|
||||
ss.removeTransorm(transformName)
|
||||
elif args[0] == 'auto':
|
||||
ss.addAutoTransorm(transformName)
|
||||
elif args[0] == 'manual':
|
||||
ss.removeAutoTransform(transformName)
|
||||
else:
|
||||
raise TypeError()
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def sector(self, sector=None):
|
||||
"""sector {0-7} -- Select or display sector (a la Spec)
|
||||
"""
|
||||
if sector is None:
|
||||
print self._sectorSelector.__repr__()
|
||||
else:
|
||||
if type(sector) is not int and not (0 <= sector <= 7):
|
||||
raise TypeError()
|
||||
self._sectorSelector.setSector(sector)
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
@command
|
||||
def autosector(self, *args):
|
||||
"""autosector [None] [0-7] [0-7]... -- Set sectors that might be automatically applied""" #@IgnorePep8
|
||||
if len(args) == 0:
|
||||
print self._sectorSelector.__repr__()
|
||||
elif len(args) == 1 and args[0] is None:
|
||||
self._sectorSelector.setAutoSectors([])
|
||||
print self._sectorSelector.__repr__()
|
||||
else:
|
||||
sectorList = []
|
||||
for arg in args:
|
||||
if type(arg) is not int:
|
||||
raise TypeError()
|
||||
sectorList.append(arg)
|
||||
self._sectorSelector.setAutoSectors(sectorList)
|
||||
print self._sectorSelector.__repr__()
|
||||
|
||||
|
||||
|
||||
292
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/calc.py
Normal file
292
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/calc.py
Normal file
@@ -0,0 +1,292 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, asin, acos, atan2, sin, cos, sqrt
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.log import logging
|
||||
from diffcalc.util import bound, AbstractPosition, DiffcalcException,\
|
||||
x_rotation, z_rotation
|
||||
from diffcalc.hkl.vlieg.geometry import VliegGeometry
|
||||
from diffcalc.ub.calc import PaperSpecificUbCalcStrategy
|
||||
from diffcalc.hkl.calcbase import HklCalculatorBase
|
||||
from diffcalc.hkl.common import DummyParameterManager
|
||||
|
||||
logger = logging.getLogger("diffcalc.hkl.willmot.calcwill")
|
||||
|
||||
CHOOSE_POSITIVE_GAMMA = True
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
I = matrix('1 0 0; 0 1 0; 0 0 1')
|
||||
SMALL = 1e-10
|
||||
|
||||
TEMPORARY_CONSTRAINTS_DICT_RAD = {'betain': 2 * TORAD}
|
||||
|
||||
|
||||
def create_matrices(delta, gamma, omegah, phi):
|
||||
return (calc_DELTA(delta), calc_GAMMA(gamma), calc_OMEGAH(omegah),
|
||||
calc_PHI(phi))
|
||||
|
||||
|
||||
def calc_DELTA(delta):
|
||||
return x_rotation(delta) # (39)
|
||||
|
||||
|
||||
def calc_GAMMA(gamma):
|
||||
return z_rotation(gamma) # (40)
|
||||
|
||||
|
||||
def calc_OMEGAH(omegah):
|
||||
return x_rotation(omegah) # (41)
|
||||
|
||||
|
||||
def calc_PHI(phi):
|
||||
return z_rotation(phi) # (42)
|
||||
|
||||
|
||||
def angles_to_hkl_phi(delta, gamma, omegah, phi):
|
||||
"""Calculate hkl matrix in phi frame in units of 2*pi/lambda
|
||||
"""
|
||||
DELTA, GAMMA, OMEGAH, PHI = create_matrices(delta, gamma, omegah, phi)
|
||||
H_lab = (GAMMA * DELTA - I) * matrix([[0], [1], [0]]) # (43)
|
||||
H_phi = PHI.I * OMEGAH.I * H_lab # (44)
|
||||
return H_phi
|
||||
|
||||
|
||||
def angles_to_hkl(delta, gamma, omegah, phi, wavelength, UB):
|
||||
"""Calculate hkl matrix in reprical lattice space in units of 1/Angstrom
|
||||
"""
|
||||
H_phi = angles_to_hkl_phi(delta, gamma, omegah, phi) * 2 * pi / wavelength
|
||||
hkl = UB.I * H_phi # (5)
|
||||
return hkl
|
||||
|
||||
|
||||
class WillmottHorizontalPosition(AbstractPosition):
|
||||
|
||||
def __init__(self, delta=None, gamma=None, omegah=None, phi=None):
|
||||
self.delta = delta
|
||||
self.gamma = gamma
|
||||
self.omegah = omegah
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return WillmottHorizontalPosition(self.delta, self.gamma, self.omegah,
|
||||
self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.delta *= TORAD
|
||||
self.gamma *= TORAD
|
||||
self.omegah *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.delta *= TODEG
|
||||
self.gamma *= TODEG
|
||||
self.omegah *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def totuple(self):
|
||||
return (self.delta, self.gamma, self.omegah, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ('WillmottHorizontalPosition('
|
||||
'delta: %.4f gamma: %.4f omegah: %.4f phi: %.4f)' %
|
||||
(self.delta, self.gamma, self.omegah, self.phi))
|
||||
|
||||
|
||||
class WillmottHorizontalGeometry(object):
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'willmott_horizontal'
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
return WillmottHorizontalPosition(*physicalAngles)
|
||||
|
||||
def internal_position_to_physical_angles(self, internalPosition):
|
||||
return internalPosition.totuple()
|
||||
|
||||
def create_position(self, delta, gamma, omegah, phi):
|
||||
return WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
|
||||
|
||||
class WillmottHorizontalUbCalcStrategy(PaperSpecificUbCalcStrategy):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
H_phi = angles_to_hkl_phi(*pos.totuple())
|
||||
return matrix(H_phi.tolist())
|
||||
|
||||
|
||||
class DummyConstraints(object):
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return TEMPORARY_CONSTRAINTS_DICT_RAD
|
||||
|
||||
|
||||
class ConstraintAdapter(object):
|
||||
|
||||
def __init__(self, constraints):
|
||||
self._constraints = constraints
|
||||
|
||||
def getParameterDict(self):
|
||||
names = self._constraints.available
|
||||
return dict(zip(names, [None] * len(names)))
|
||||
|
||||
def setParameter(self, name, value):
|
||||
self._constraints.set_constraint(name, value)
|
||||
|
||||
def get(self, name):
|
||||
if name in self._constraints.all:
|
||||
val = self._constraints.get_value(name)
|
||||
return 999 if val is None else val
|
||||
else:
|
||||
return 999
|
||||
|
||||
def update_tracked(self):
|
||||
pass
|
||||
|
||||
|
||||
class WillmottHorizontalCalculator(HklCalculatorBase):
|
||||
|
||||
def __init__(self, ubcalc, geometry, hardware, constraints,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl=True):
|
||||
""""
|
||||
Where constraints.reference is a one element dict with the key either
|
||||
('betain', 'betaout' or 'equal') and the value a number or None for
|
||||
'betain_eq_betaout'
|
||||
"""
|
||||
|
||||
HklCalculatorBase.__init__(self, ubcalc, geometry, hardware,
|
||||
raiseExceptionsIfAnglesDoNotMapBackToHkl)
|
||||
|
||||
if constraints is not None:
|
||||
self.constraints = constraints
|
||||
self.parameter_manager = ConstraintAdapter(constraints)
|
||||
else:
|
||||
self.constraints = DummyConstraints()
|
||||
self.parameter_manager = DummyParameterManager()
|
||||
|
||||
@property
|
||||
def _UB(self):
|
||||
return self._ubcalc.UB
|
||||
|
||||
def _anglesToHkl(self, pos, wavelength):
|
||||
"""
|
||||
Calculate miller indices from position in radians.
|
||||
"""
|
||||
hkl_matrix = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
return hkl_matrix[0, 0], hkl_matrix[1, 0], hkl_matrix[2, 0],
|
||||
|
||||
def _anglesToVirtualAngles(self, pos, wavelength):
|
||||
"""
|
||||
Calculate virtual-angles in radians from position in radians.
|
||||
|
||||
Return theta, alpha, and beta in a dictionary.
|
||||
"""
|
||||
|
||||
betain = pos.omegah # (52)
|
||||
|
||||
hkl = angles_to_hkl(pos.delta, pos.gamma, pos.omegah, pos.phi,
|
||||
wavelength, self._UB)
|
||||
H_phi = self._UB * hkl
|
||||
H_phi = H_phi / (2 * pi / wavelength)
|
||||
l_phi = H_phi[2, 0]
|
||||
sin_betaout = l_phi - sin(betain)
|
||||
betaout = asin(bound(sin_betaout)) # (54)
|
||||
|
||||
cos_2theta = cos(pos.delta) * cos(pos.gamma)
|
||||
theta = acos(bound(cos_2theta)) / 2.
|
||||
|
||||
return {'theta': theta, 'betain': betain, 'betaout': betaout}
|
||||
|
||||
def _hklToAngles(self, h, k, l, wavelength):
|
||||
"""
|
||||
Calculate position and virtual angles in radians for a given hkl.
|
||||
"""
|
||||
|
||||
H_phi = self._UB * matrix([[h], [k], [l]]) # units: 1/Angstrom
|
||||
H_phi = H_phi / (2 * pi / wavelength) # units: 2*pi/wavelength
|
||||
h_phi = H_phi[0, 0]
|
||||
k_phi = H_phi[1, 0]
|
||||
l_phi = H_phi[2, 0] # (5)
|
||||
|
||||
### determine betain (omegah) and betaout ###
|
||||
|
||||
if not self.constraints.reference:
|
||||
raise ValueError("No reference constraint has been constrained.")
|
||||
|
||||
ref_name, ref_value = self.constraints.reference.items()[0]
|
||||
if ref_value is not None:
|
||||
ref_value *= TORAD
|
||||
if ref_name == 'betain':
|
||||
betain = ref_value
|
||||
betaout = asin(bound(l_phi - sin(betain))) # (53)
|
||||
elif ref_name == 'betaout':
|
||||
betaout = ref_value
|
||||
betain = asin(bound(l_phi - sin(betaout))) # (54)
|
||||
elif ref_name == 'bin_eq_bout':
|
||||
betain = betaout = asin(bound(l_phi / 2)) # (55)
|
||||
else:
|
||||
raise ValueError("Unexpected constraint name'%s'." % ref_name)
|
||||
|
||||
if abs(betain) < SMALL:
|
||||
raise DiffcalcException('required betain was 0 degrees (requested '
|
||||
'q is perpendicular to surface normal)')
|
||||
if betain < -SMALL:
|
||||
raise DiffcalcException("betain was -ve (%.4f)" % betain)
|
||||
# logger.info('betain = %.4f, betaout = %.4f',
|
||||
# betain * TODEG, betaout * TODEG)
|
||||
omegah = betain # (52)
|
||||
|
||||
### determine H_lab (X, Y and Z) ###
|
||||
|
||||
Y = -(h_phi ** 2 + k_phi ** 2 + l_phi ** 2) / 2 # (45)
|
||||
|
||||
Z = (sin(betaout) + sin(betain) * (Y + 1)) / cos(omegah) # (47)
|
||||
|
||||
X_squared = (h_phi ** 2 + k_phi ** 2 -
|
||||
((cos(betain) * Y + sin(betain) * Z) ** 2)) # (48)
|
||||
if (X_squared < 0) and (abs(X_squared) < SMALL):
|
||||
X_squared = 0
|
||||
Xpositive = sqrt(X_squared)
|
||||
if CHOOSE_POSITIVE_GAMMA:
|
||||
X = -Xpositive
|
||||
else:
|
||||
X = Xpositive
|
||||
# logger.info('H_lab (X,Y,Z) = [%.4f, %.4f, %.4f]', X, Y, Z)
|
||||
### determine diffractometer angles ###
|
||||
|
||||
gamma = atan2(-X, Y + 1) # (49)
|
||||
if (abs(gamma) < SMALL):
|
||||
# degenerate case, only occurs when q || z
|
||||
delta = 2 * omegah
|
||||
else:
|
||||
delta = atan2(Z * sin(gamma), -X) # (50)
|
||||
M = cos(betain) * Y + sin(betain) * Z
|
||||
phi = atan2(h_phi * M - k_phi * X, h_phi * X + k_phi * M) # (51)
|
||||
|
||||
pos = WillmottHorizontalPosition(delta, gamma, omegah, phi)
|
||||
virtual_angles = {'betain': betain, 'betaout': betaout}
|
||||
return pos, virtual_angles
|
||||
58
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/commands.py
Normal file
58
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/commands.py
Normal file
@@ -0,0 +1,58 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
|
||||
|
||||
class WillmottHklCommands(object):
|
||||
|
||||
def __init__(self, hklcalc):
|
||||
self._hklcalc = hklcalc
|
||||
self.commands = [self.con,
|
||||
self.uncon,
|
||||
self.cons]
|
||||
|
||||
def __str__(self):
|
||||
return self._hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def con(self, scn_or_string):
|
||||
"""con <constraint> -- constrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.constrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def uncon(self, scn_or_string):
|
||||
"""uncon <constraint> -- unconstrains constraint
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
self._hklcalc.constraints.unconstrain(name)
|
||||
print self._report_constraints()
|
||||
|
||||
@command
|
||||
def cons(self):
|
||||
"""cons -- list available constraints and values
|
||||
"""
|
||||
print self._report_constraints()
|
||||
|
||||
def _report_constraints(self):
|
||||
return (self._hklcalc.constraints.build_display_table_lines() + '\n\n' +
|
||||
self._hklcalc.constraints._report_constraints())
|
||||
156
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/constraints.py
Normal file
156
script/__Lib/diffcalc_old/diffcalc/hkl/willmott/constraints.py
Normal file
@@ -0,0 +1,156 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.util import DiffcalcException
|
||||
|
||||
|
||||
def filter_dict(d, keys):
|
||||
"""Return a copy of d containing only keys that are in keys"""
|
||||
##return {k: d[k] for k in keys} # requires Python 2.6
|
||||
return dict((k, d[k]) for k in keys if k in d.keys())
|
||||
|
||||
|
||||
ref_constraints = ('betain', 'betaout', 'bin_eq_bout')
|
||||
valueless_constraints = ('bin_eq_bout')
|
||||
all_constraints = ref_constraints
|
||||
|
||||
|
||||
class WillmottConstraintManager(object):
|
||||
"""Constraints in degrees.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._constrained = {'bin_eq_bout': None}
|
||||
|
||||
@property
|
||||
def available_constraint_names(self):
|
||||
"""list of all available constraints"""
|
||||
return all_constraints
|
||||
|
||||
@property
|
||||
def all(self): # @ReservedAssignment
|
||||
"""dictionary of all constrained values"""
|
||||
return self._constrained.copy()
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return filter_dict(self.all, ref_constraints)
|
||||
|
||||
@property
|
||||
def constrained_names(self):
|
||||
"""ordered tuple of constained circles"""
|
||||
names = self.all.keys()
|
||||
names.sort(key=lambda name: list(all_constraints).index(name))
|
||||
return tuple(names)
|
||||
|
||||
def is_constrained(self, name):
|
||||
return name in self._constrained
|
||||
|
||||
def get_value(self, name):
|
||||
return self._constrained[name]
|
||||
|
||||
def _build_display_table(self):
|
||||
constraint_types = (ref_constraints,)
|
||||
num_rows = max([len(col) for col in constraint_types])
|
||||
max_name_width = max(
|
||||
[len(name) for name in sum(constraint_types[:2], ())])
|
||||
# headings
|
||||
lines = [' ' + 'REF'.ljust(max_name_width)]
|
||||
lines.append(' ' + '=' * max_name_width + ' ')
|
||||
|
||||
# constraint rows
|
||||
for n_row in range(num_rows):
|
||||
cells = []
|
||||
for col in constraint_types:
|
||||
name = col[n_row] if n_row < len(col) else ''
|
||||
cells.append(self._label_constraint(name))
|
||||
cells.append(('%-' + str(max_name_width) + 's ') % name)
|
||||
lines.append(''.join(cells))
|
||||
lines.append
|
||||
return '\n'.join(lines)
|
||||
|
||||
def _report_constraints(self):
|
||||
if not self.reference:
|
||||
return "!!! No reference constraint set"
|
||||
name, val = self.reference.items()[0]
|
||||
if name in valueless_constraints:
|
||||
return " %s" % name
|
||||
else:
|
||||
if val is None:
|
||||
return "!!! %s: ---" % name
|
||||
else:
|
||||
return " %s: %.4f" % (name, val)
|
||||
|
||||
def _label_constraint(self, name):
|
||||
if name == '':
|
||||
label = ' '
|
||||
elif (self.is_constrained(name) and (self.get_value(name) is None) and
|
||||
name not in valueless_constraints):
|
||||
label = 'o-> '
|
||||
elif self.is_constrained(name):
|
||||
label = '--> '
|
||||
else:
|
||||
label = ' '
|
||||
return label
|
||||
|
||||
def constrain(self, name):
|
||||
if name in self.all:
|
||||
return "%s is already constrained." % name.capitalize()
|
||||
elif name in ref_constraints:
|
||||
return self._constrain_reference(name)
|
||||
else:
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
|
||||
def _constrain_reference(self, name):
|
||||
if self.reference:
|
||||
constrained_name = self.reference.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def unconstrain(self, name):
|
||||
if name in self._constrained:
|
||||
del self._constrained[name]
|
||||
else:
|
||||
return "%s was not already constrained." % name.capitalize()
|
||||
|
||||
###
|
||||
def _check_constraint_settable(self, name, verb):
|
||||
if name not in all_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not an available '
|
||||
'constraint.' % locals())
|
||||
elif name not in self.all.keys():
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this is not currently '
|
||||
'constrained.' % locals())
|
||||
elif name in valueless_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not %(verb)s %(name)s as this constraint takes no '
|
||||
'value.' % locals())
|
||||
|
||||
def set_constraint(self, name, value): # @ReservedAssignment
|
||||
self._check_constraint_settable(name, 'set')
|
||||
old_value = self.all[name]
|
||||
old = str(old_value) if old_value is not None else '---'
|
||||
self._constrained[name] = float(value)
|
||||
new = str(value)
|
||||
return "%(name)s : %(old)s --> %(new)s" % locals()
|
||||
1155
script/__Lib/diffcalc_old/diffcalc/hkl/you/calc.py
Normal file
1155
script/__Lib/diffcalc_old/diffcalc/hkl/you/calc.py
Normal file
File diff suppressed because it is too large
Load Diff
370
script/__Lib/diffcalc_old/diffcalc/hkl/you/constraints.py
Normal file
370
script/__Lib/diffcalc_old/diffcalc/hkl/you/constraints.py
Normal file
@@ -0,0 +1,370 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
from diffcalc.util import DiffcalcException, bold
|
||||
|
||||
TODEG = 180 / pi
|
||||
TORAD = pi / 180
|
||||
|
||||
NUNAME = 'gam'
|
||||
|
||||
def filter_dict(d, keys):
|
||||
"""Return a copy of d containing only keys that are in keys"""
|
||||
##return {k: d[k] for k in keys} # requires Python 2.6
|
||||
return dict((k, d[k]) for k in keys if k in d.keys())
|
||||
|
||||
|
||||
det_constraints = ('delta', NUNAME, 'qaz', 'naz')
|
||||
ref_constraints = ('a_eq_b', 'alpha', 'beta', 'psi')
|
||||
samp_constraints = ('mu', 'eta', 'chi', 'phi', 'mu_is_' + NUNAME)
|
||||
|
||||
valueless_constraints = ('a_eq_b', 'mu_is_' + NUNAME)
|
||||
all_constraints = det_constraints + ref_constraints + samp_constraints
|
||||
|
||||
|
||||
number_single_sample = (len(det_constraints) * len(ref_constraints) *
|
||||
len(samp_constraints))
|
||||
|
||||
|
||||
class YouConstraintManager(object):
|
||||
|
||||
def __init__(self, hardware, fixed_constraints = {}):
|
||||
self._hardware = hardware
|
||||
self._constrained = {}
|
||||
# self._tracking = []
|
||||
self.n_phi = matrix([[0], [0], [1]])
|
||||
self._hide_detector_constraint = False # default
|
||||
self._fixed_samp_constraints = ()
|
||||
self._fix_constraints(fixed_constraints)
|
||||
|
||||
def __str__(self):
|
||||
lines = []
|
||||
# TODO: Put somewhere with access to UB matrix!
|
||||
# WIDTH = 13
|
||||
# n_phi = self.n_phi
|
||||
# fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
# lines.append(" n_phi:".ljust(WIDTH) +
|
||||
# fmt % (n_phi[0, 0], n_phi[1, 0], n_phi[2, 0]))
|
||||
# if self._getUBMatrix():
|
||||
# n_cryst = self._getUMatrix().I * self.n_phi
|
||||
# lines.append(" n_cryst:".ljust(WIDTH) +
|
||||
# fmt % (n_cryst[0, 0], n_cryst[1, 0], n_cryst[2, 0]))
|
||||
# n_recip = self._getUBMatrix().I * self.n_phi
|
||||
# lines.append(" n_recip:".ljust(WIDTH) +
|
||||
# fmt % (n_recip[0, 0], n_recip[1, 0], n_recip[2, 0]))
|
||||
# else:
|
||||
# lines.append(
|
||||
# " n_cryst:".ljust(WIDTH) + ' "<<< No U matrix >>>"')
|
||||
# lines.append(
|
||||
# " n_recip:".ljust(WIDTH) + ' "<<< No UB matrix >>>"')
|
||||
|
||||
lines.extend(self.build_display_table_lines())
|
||||
lines.append("")
|
||||
lines.extend(self.report_constraints_lines())
|
||||
lines.append("")
|
||||
if (self.is_fully_constrained() and
|
||||
not self.is_current_mode_implemented()):
|
||||
lines.append(
|
||||
" Sorry, this constraint combination is not implemented")
|
||||
lines.append(" Type 'help con' for available combinations")
|
||||
else:
|
||||
lines.append(" Type 'help con' for instructions") # okay
|
||||
return '\n'.join(lines)
|
||||
|
||||
@property
|
||||
def available_constraint_names(self):
|
||||
"""list of all available constraints"""
|
||||
return all_constraints
|
||||
|
||||
@property
|
||||
def settable_constraint_names(self):
|
||||
"""list of all available constraints that have settable values"""
|
||||
all_copy = list(all_constraints)
|
||||
for valueless in valueless_constraints:
|
||||
all_copy.remove(valueless)
|
||||
return all_copy
|
||||
|
||||
@property
|
||||
def all(self): # @ReservedAssignment
|
||||
"""dictionary of all constrained values"""
|
||||
return self._constrained.copy()
|
||||
|
||||
@property
|
||||
def detector(self):
|
||||
"""dictionary of constrained detector circles"""
|
||||
return filter_dict(self.all, det_constraints[:-1])
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
"""dictionary of constrained reference circles"""
|
||||
return filter_dict(self.all, ref_constraints)
|
||||
|
||||
@property
|
||||
def sample(self):
|
||||
"""dictionary of constrained sample circles"""
|
||||
return filter_dict(self.all, samp_constraints)
|
||||
|
||||
@property
|
||||
def naz(self):
|
||||
"""dictionary with naz and value if constrained"""
|
||||
return filter_dict(self.all, ('naz',))
|
||||
|
||||
@property
|
||||
def constrained_names(self):
|
||||
"""ordered tuple of constained circles"""
|
||||
names = self.all.keys()
|
||||
names.sort(key=lambda name: list(all_constraints).index(name))
|
||||
return tuple(names)
|
||||
|
||||
def _fix_constraints(self, fixed_constraints):
|
||||
for name in fixed_constraints:
|
||||
self.constrain(name)
|
||||
self.set_constraint(name, fixed_constraints[name])
|
||||
|
||||
if self.detector or self.naz:
|
||||
self._hide_detector_constraint = True
|
||||
|
||||
fixed_samp_constraints = list(self.sample.keys())
|
||||
if 'mu' in self.sample or NUNAME in self.detector:
|
||||
fixed_samp_constraints.append('mu_is_' + NUNAME)
|
||||
self._fixed_samp_constraints = tuple(fixed_samp_constraints)
|
||||
|
||||
|
||||
def is_constrained(self, name):
|
||||
return name in self._constrained
|
||||
|
||||
def get_value(self, name):
|
||||
return self._constrained[name]
|
||||
|
||||
def build_display_table_lines(self):
|
||||
unfixed_samp_constraints = list(samp_constraints)
|
||||
for name in self._fixed_samp_constraints:
|
||||
unfixed_samp_constraints.remove(name)
|
||||
if self._hide_detector_constraint:
|
||||
constraint_types = (ref_constraints, unfixed_samp_constraints)
|
||||
else:
|
||||
constraint_types = (det_constraints, ref_constraints,
|
||||
unfixed_samp_constraints)
|
||||
num_rows = max([len(col) for col in constraint_types])
|
||||
max_name_width = max(
|
||||
[len(name) for name in sum(constraint_types[:-1], ())])
|
||||
|
||||
cells = []
|
||||
|
||||
header_cells = []
|
||||
if not self._hide_detector_constraint:
|
||||
header_cells.append(bold(' ' + 'DET'.ljust(max_name_width)))
|
||||
header_cells.append(bold(' ' + 'REF'.ljust(max_name_width)))
|
||||
header_cells.append(bold(' ' + 'SAMP'))
|
||||
cells.append(header_cells)
|
||||
|
||||
underline_cells = [' ' + '-' * max_name_width] * len(constraint_types)
|
||||
cells.append(underline_cells)
|
||||
|
||||
for n_row in range(num_rows):
|
||||
row_cells = []
|
||||
for col in constraint_types:
|
||||
name = col[n_row] if n_row < len(col) else ''
|
||||
row_cells.append(self._label_constraint(name))
|
||||
row_cells.append(('%-' + str(max_name_width) + 's') % name)
|
||||
cells.append(row_cells)
|
||||
|
||||
lines = [' '.join(row_cells).rstrip() for row_cells in cells]
|
||||
return lines
|
||||
|
||||
def _report_constraint(self, name):
|
||||
val = self.get_constraint(name)
|
||||
if name in valueless_constraints:
|
||||
return " %s" % name
|
||||
else:
|
||||
if val is None:
|
||||
return "! %-5s: ---" % name
|
||||
else:
|
||||
return " %-5s: %.4f" % (name, val)
|
||||
|
||||
def report_constraints_lines(self):
|
||||
lines = []
|
||||
required = 3 - len(self.all)
|
||||
if required == 0:
|
||||
pass
|
||||
elif required == 1:
|
||||
lines.append('! 1 more constraint required')
|
||||
else:
|
||||
lines.append('! %d more constraints required' % required)
|
||||
constraints = []
|
||||
constraints.extend(self.detector.keys())
|
||||
constraints.extend(self.naz.keys())
|
||||
constraints.extend(self.reference.keys())
|
||||
constraints.extend(sorted(self.sample.keys()))
|
||||
for name in constraints:
|
||||
lines.append(self._report_constraint(name))
|
||||
return lines
|
||||
|
||||
def is_fully_constrained(self):
|
||||
return len(self.all) == 3
|
||||
|
||||
def is_current_mode_implemented(self):
|
||||
if not self.is_fully_constrained():
|
||||
raise ValueError("Three constraints required")
|
||||
|
||||
if len(self.sample) == 3:
|
||||
if set(self.sample.keys()) == set(['chi', 'phi', 'eta']):
|
||||
return True
|
||||
return False
|
||||
|
||||
if len(self.sample) == 1:
|
||||
return True
|
||||
|
||||
if len(self.reference) == 1:
|
||||
return (set(self.sample.keys()) == set(['chi', 'phi']) or
|
||||
set(self.sample.keys()) == set(['mu', 'eta']) or
|
||||
self.sample == {'mu': 0, 'chi': pi / 2})
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def _label_constraint(self, name):
|
||||
if name == '':
|
||||
label = ' '
|
||||
# elif self.is_tracking(name): # implies constrained
|
||||
# label = '~~> '
|
||||
elif (self.is_constrained(name) and (self.get_value(name) is None) and
|
||||
name not in valueless_constraints):
|
||||
label = 'o->'
|
||||
elif self.is_constrained(name):
|
||||
label = '-->'
|
||||
else:
|
||||
label = ' '
|
||||
return label
|
||||
|
||||
def constrain(self, name):
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name' % name)
|
||||
if name in self.all:
|
||||
return "%s is already constrained." % name.capitalize()
|
||||
elif name in det_constraints:
|
||||
return self._constrain_detector(name)
|
||||
elif name in ref_constraints:
|
||||
return self._constrain_reference(name)
|
||||
elif name in samp_constraints:
|
||||
return self._constrain_sample(name)
|
||||
else:
|
||||
raise DiffcalcException("%s is not a valid constraint name. Type 'con' for a table of constraint name" % name)
|
||||
|
||||
def is_constraint_fixed(self, name):
|
||||
return ((name in det_constraints and self._hide_detector_constraint) or
|
||||
(name in samp_constraints and name in self._fixed_samp_constraints))
|
||||
|
||||
def _constrain_detector(self, name):
|
||||
if self.naz:
|
||||
del self._constrained['naz']
|
||||
self._constrained[name] = None
|
||||
return 'Naz constraint replaced.'
|
||||
elif self.detector:
|
||||
constrained_name = self.detector.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return'%s constraint replaced.' % constrained_name.capitalize()
|
||||
elif len(self.all) == 3: # and no detector
|
||||
raise self._could_not_constrain_exception(name)
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def _could_not_constrain_exception(self, name):
|
||||
return DiffcalcException(
|
||||
"%s could not be constrained. First un-constrain one of the\n"
|
||||
"angles %s, %s or %s (with 'uncon')" %
|
||||
((name.capitalize(),) + self.constrained_names))
|
||||
|
||||
def _constrain_reference(self, name):
|
||||
if self.reference:
|
||||
constrained_name = self.reference.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
elif len(self.all) == 3: # and no reference
|
||||
raise self._could_not_constrain_exception(name)
|
||||
else:
|
||||
self._constrained[name] = None
|
||||
|
||||
def _constrain_sample(self, name):
|
||||
if len(self._constrained) < 3:
|
||||
# okay, more to add
|
||||
self._constrained[name] = None
|
||||
# else: three constraints are set
|
||||
elif len(self.sample) == 1:
|
||||
# (detector and reference constraints set)
|
||||
# it is clear which sample constraint to remove
|
||||
constrained_name = self.sample.keys()[0]
|
||||
del self._constrained[constrained_name]
|
||||
self._constrained[name] = None
|
||||
return '%s constraint replaced.' % constrained_name.capitalize()
|
||||
else:
|
||||
raise self._could_not_constrain_exception(name)
|
||||
|
||||
def unconstrain(self, name):
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
if name in self._constrained:
|
||||
del self._constrained[name]
|
||||
else:
|
||||
return "%s was not already constrained." % name.capitalize()
|
||||
|
||||
def _check_constraint_settable(self, name):
|
||||
if name not in all_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This is not an available '
|
||||
'constraint.' % locals())
|
||||
elif name not in self.all.keys():
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This is not currently '
|
||||
'constrained.' % locals())
|
||||
elif name in valueless_constraints:
|
||||
raise DiffcalcException(
|
||||
'Could not set %(name)s. This constraint takes no '
|
||||
'value.' % locals())
|
||||
|
||||
def clear_constraints(self):
|
||||
self._constrained = {}
|
||||
|
||||
def set_constraint(self, name, value): # @ReservedAssignment
|
||||
if self.is_constraint_fixed(name):
|
||||
raise DiffcalcException('%s is not a valid constraint name')
|
||||
self._check_constraint_settable(name)
|
||||
# if name in self._tracking:
|
||||
# raise DiffcalcException(
|
||||
# "Could not set %s as this constraint is configured to track "
|
||||
# "its associated\nphysical angle. First remove this tracking "
|
||||
# "(use 'untrack %s').""" % (name, name))
|
||||
old_value = self.get_constraint(name)
|
||||
old = str(old_value) if old_value is not None else '---'
|
||||
self._constrained[name] = float(value) * TORAD
|
||||
new = str(value)
|
||||
return "%(name)s : %(old)s --> %(new)s" % locals()
|
||||
|
||||
def get_constraint(self, name):
|
||||
value = self.all[name]
|
||||
return None if value is None else value * TODEG
|
||||
|
||||
178
script/__Lib/diffcalc_old/diffcalc/hkl/you/geometry.py
Normal file
178
script/__Lib/diffcalc_old/diffcalc/hkl/you/geometry.py
Normal file
@@ -0,0 +1,178 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi
|
||||
|
||||
from diffcalc.util import AbstractPosition
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
from diffcalc.util import x_rotation, z_rotation, y_rotation
|
||||
|
||||
from diffcalc.hkl.you.constraints import NUNAME
|
||||
|
||||
class YouGeometry(object):
|
||||
|
||||
def __init__(self, name, fixed_constraints ):
|
||||
self.name = name
|
||||
self.fixed_constraints = fixed_constraints
|
||||
|
||||
def physical_angles_to_internal_position(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
def internal_position_to_physical_angles(self, physicalAngles):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_position(self, *args):
|
||||
return YouPosition(*args)
|
||||
|
||||
|
||||
#==============================================================================
|
||||
#==============================================================================
|
||||
# Geometry plugins for use with 'You' hkl calculation engine
|
||||
#==============================================================================
|
||||
#==============================================================================
|
||||
|
||||
|
||||
class SixCircle(YouGeometry):
|
||||
def __init__(self):
|
||||
YouGeometry.__init__(self, 'sixc', {})
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
return YouPosition(*physical_angle_tuple)
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
return internal_position.totuple()
|
||||
|
||||
|
||||
class FourCircle(YouGeometry):
|
||||
"""For a diffractometer with angles:
|
||||
delta, eta, chi, phi
|
||||
"""
|
||||
def __init__(self):
|
||||
YouGeometry.__init__(self, 'fourc', {'mu': 0, NUNAME: 0})
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
delta, eta, chi, phi = physical_angle_tuple
|
||||
return YouPosition(0, delta, 0, eta, chi, phi)
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
_, delta, _, eta, chi, phi = internal_position.totuple()
|
||||
return delta, eta, chi, phi
|
||||
|
||||
|
||||
class FiveCircle(YouGeometry):
|
||||
"""For a diffractometer with angles:
|
||||
delta, nu, eta, chi, phi
|
||||
"""
|
||||
def __init__(self):
|
||||
YouGeometry.__init__(self, 'fivec', {'mu': 0})
|
||||
|
||||
def physical_angles_to_internal_position(self, physical_angle_tuple):
|
||||
# mu, delta, nu, eta, chi, phi
|
||||
delta, nu, eta, chi, phi = physical_angle_tuple
|
||||
return YouPosition(0, delta, nu, eta, chi, phi)
|
||||
|
||||
def internal_position_to_physical_angles(self, internal_position):
|
||||
_, delta, nu, eta, chi, phi = internal_position.totuple()
|
||||
return delta, nu, eta, chi, phi
|
||||
|
||||
|
||||
#==============================================================================
|
||||
|
||||
|
||||
def create_you_matrices(mu=None, delta=None, nu=None, eta=None, chi=None,
|
||||
phi=None):
|
||||
"""
|
||||
Create transformation matrices from H. You's paper.
|
||||
"""
|
||||
MU = None if mu is None else calcMU(mu)
|
||||
DELTA = None if delta is None else calcDELTA(delta)
|
||||
NU = None if nu is None else calcNU(nu)
|
||||
ETA = None if eta is None else calcETA(eta)
|
||||
CHI = None if chi is None else calcCHI(chi)
|
||||
PHI = None if phi is None else calcPHI(phi)
|
||||
return MU, DELTA, NU, ETA, CHI, PHI
|
||||
|
||||
|
||||
def calcNU(nu):
|
||||
return x_rotation(nu)
|
||||
|
||||
|
||||
def calcDELTA(delta):
|
||||
return z_rotation(-delta)
|
||||
|
||||
|
||||
def calcMU(mu_or_alpha):
|
||||
return x_rotation(mu_or_alpha)
|
||||
|
||||
|
||||
def calcETA(eta):
|
||||
return z_rotation(-eta)
|
||||
|
||||
|
||||
def calcCHI(chi):
|
||||
return y_rotation(chi)
|
||||
|
||||
|
||||
def calcPHI(phi):
|
||||
return z_rotation(-phi)
|
||||
|
||||
|
||||
class YouPosition(AbstractPosition):
|
||||
|
||||
def __init__(self, mu=None, delta=None, nu=None, eta=None, chi=None,
|
||||
phi=None):
|
||||
self.mu = mu
|
||||
self.delta = delta
|
||||
self.nu = nu
|
||||
self.eta = eta
|
||||
self.chi = chi
|
||||
self.phi = phi
|
||||
|
||||
def clone(self):
|
||||
return YouPosition(self.mu, self.delta, self.nu, self.eta, self.chi,
|
||||
self.phi)
|
||||
|
||||
def changeToRadians(self):
|
||||
self.mu *= TORAD
|
||||
self.delta *= TORAD
|
||||
self.nu *= TORAD
|
||||
self.eta *= TORAD
|
||||
self.chi *= TORAD
|
||||
self.phi *= TORAD
|
||||
|
||||
def changeToDegrees(self):
|
||||
self.mu *= TODEG
|
||||
self.delta *= TODEG
|
||||
self.nu *= TODEG
|
||||
self.eta *= TODEG
|
||||
self.chi *= TODEG
|
||||
self.phi *= TODEG
|
||||
|
||||
def totuple(self):
|
||||
return (self.mu, self.delta, self.nu, self.eta, self.chi, self.phi)
|
||||
|
||||
def __str__(self):
|
||||
return ("YouPosition(mu %r delta: %r nu: %r eta: %r chi: %r phi: %r)"
|
||||
% self.totuple())
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.totuple() == other.totuple()
|
||||
178
script/__Lib/diffcalc_old/diffcalc/hkl/you/hkl.py
Normal file
178
script/__Lib/diffcalc_old/diffcalc/hkl/you/hkl.py
Normal file
@@ -0,0 +1,178 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from diffcalc.hkl.common import getNameFromScannableOrString
|
||||
from diffcalc.util import command
|
||||
from diffcalc.hkl.you.calc import YouHklCalculator
|
||||
from diffcalc import settings
|
||||
|
||||
|
||||
|
||||
import diffcalc.ub.ub
|
||||
from diffcalc.hkl.you.constraints import YouConstraintManager
|
||||
|
||||
__all__ = ['allhkl', 'con', 'uncon', 'hklcalc', 'constraint_manager']
|
||||
|
||||
|
||||
_fixed_constraints = settings.geometry.fixed_constraints # @UndefinedVariable
|
||||
|
||||
constraint_manager = YouConstraintManager(settings.hardware, _fixed_constraints)
|
||||
|
||||
hklcalc = YouHklCalculator(
|
||||
diffcalc.ub.ub.ubcalc, settings.geometry, settings.hardware, constraint_manager)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return hklcalc.__str__()
|
||||
|
||||
@command
|
||||
def con(*args):
|
||||
"""
|
||||
con -- list available constraints and values
|
||||
con <name> {val} -- constrains and optionally sets one constraint
|
||||
con <name> {val} <name> {val} <name> {val} -- clears and then fully constrains
|
||||
|
||||
Select three constraints using 'con' and 'uncon'. Choose up to one
|
||||
from each of the sample and detector columns and up to three from
|
||||
the sample column.
|
||||
|
||||
Not all constraint combinations are currently available:
|
||||
|
||||
1 x samp: all 80 of 80
|
||||
2 x samp and 1 x ref: chi & phi
|
||||
mu & eta
|
||||
chi=90 & mu=0 (2.5 of 6)
|
||||
2 x samp and 1 x det: 0 of 6
|
||||
3 x samp: eta, chi & phi (1 of 4)
|
||||
|
||||
See also 'uncon'
|
||||
"""
|
||||
args = list(args)
|
||||
msg = _handle_con(args)
|
||||
if (hklcalc.constraints.is_fully_constrained() and
|
||||
not hklcalc.constraints.is_current_mode_implemented()):
|
||||
msg += ("\n\nWARNING:. The selected constraint combination is valid but "
|
||||
"is not implemented.\n\nType 'help con' to see implemented combinations")
|
||||
|
||||
if msg:
|
||||
print msg
|
||||
|
||||
def _handle_con(args):
|
||||
if not args:
|
||||
return hklcalc.constraints.__str__()
|
||||
|
||||
if len(args) > 6:
|
||||
raise TypeError("Unexpected args: " + str(args))
|
||||
|
||||
cons_value_pairs = []
|
||||
while args:
|
||||
scn_or_str = args.pop(0)
|
||||
name = getNameFromScannableOrString(scn_or_str)
|
||||
if args and isinstance(args[0], (int, long, float)):
|
||||
value = args.pop(0)
|
||||
else:
|
||||
value = None
|
||||
cons_value_pairs.append((name, value))
|
||||
|
||||
if len(cons_value_pairs) == 1:
|
||||
pass
|
||||
elif len(cons_value_pairs) == 3:
|
||||
hklcalc.constraints.clear_constraints()
|
||||
else:
|
||||
raise TypeError("Either one or three constraints must be specified")
|
||||
for name, value in cons_value_pairs:
|
||||
hklcalc.constraints.constrain(name)
|
||||
if value is not None:
|
||||
hklcalc.constraints.set_constraint(name, value)
|
||||
return '\n'.join(hklcalc.constraints.report_constraints_lines())
|
||||
|
||||
|
||||
@command
|
||||
def uncon(scn_or_string):
|
||||
"""uncon <name> -- remove constraint
|
||||
|
||||
See also 'con'
|
||||
"""
|
||||
name = getNameFromScannableOrString(scn_or_string)
|
||||
hklcalc.constraints.unconstrain(name)
|
||||
print '\n'.join(hklcalc.constraints.report_constraints_lines())
|
||||
|
||||
@command
|
||||
def allhkl(hkl, wavelength=None):
|
||||
"""allhkl [h k l] -- print all hkl solutions ignoring limits
|
||||
|
||||
"""
|
||||
hardware = hklcalc._hardware
|
||||
geometry = hklcalc._geometry
|
||||
if wavelength is None:
|
||||
wavelength = hardware.get_wavelength()
|
||||
h, k, l = hkl
|
||||
pos_virtual_angles_pairs = hklcalc.hkl_to_all_angles(
|
||||
h, k, l, wavelength)
|
||||
cells = []
|
||||
# virtual_angle_names = list(pos_virtual_angles_pairs[0][1].keys())
|
||||
# virtual_angle_names.sort()
|
||||
virtual_angle_names = ['qaz', 'psi', 'naz', 'tau', 'theta', 'alpha', 'beta']
|
||||
header_cells = list(hardware.get_axes_names()) + [' '] + virtual_angle_names
|
||||
cells.append(['%9s' % s for s in header_cells])
|
||||
cells.append([''] * len(header_cells))
|
||||
|
||||
|
||||
for pos, virtual_angles in pos_virtual_angles_pairs:
|
||||
row_cells = []
|
||||
|
||||
|
||||
angle_tuple = geometry.internal_position_to_physical_angles(pos)
|
||||
angle_tuple = hardware.cut_angles(angle_tuple)
|
||||
for val in angle_tuple:
|
||||
row_cells.append('%9.4f' % val)
|
||||
|
||||
row_cells.append('|')
|
||||
|
||||
for name in virtual_angle_names:
|
||||
row_cells.append('%9.4f' % virtual_angles[name])
|
||||
cells.append(row_cells)
|
||||
|
||||
|
||||
column_widths = []
|
||||
for col in range(len(cells[0])):
|
||||
widths = []
|
||||
for row in range(len(cells)):
|
||||
cell = cells[row][col]
|
||||
width = len(cell.strip())
|
||||
widths.append(width)
|
||||
column_widths.append(max(widths))
|
||||
|
||||
lines = []
|
||||
for row_cells in cells:
|
||||
trimmed_row_cells = []
|
||||
for cell, width in zip(row_cells, column_widths):
|
||||
trimmed_cell = cell.strip().rjust(width)
|
||||
trimmed_row_cells.append(trimmed_cell)
|
||||
lines.append(' '.join(trimmed_row_cells))
|
||||
print '\n'.join(lines)
|
||||
|
||||
|
||||
commands_for_help = ['Constraints',
|
||||
con,
|
||||
uncon,
|
||||
'Hkl',
|
||||
allhkl
|
||||
]
|
||||
27
script/__Lib/diffcalc_old/diffcalc/log.py
Normal file
27
script/__Lib/diffcalc_old/diffcalc/log.py
Normal file
@@ -0,0 +1,27 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import getpass
|
||||
|
||||
logging.basicConfig(format="%(asctime)s %(levelname)s:%(name)s:%(message)s",
|
||||
datefmt='%m/%d/%Y %I:%M:%S',
|
||||
filename='/tmp/diffcalc_%s.log' % getpass.getuser(),
|
||||
level=logging.DEBUG)
|
||||
24
script/__Lib/diffcalc_old/diffcalc/settings.py
Normal file
24
script/__Lib/diffcalc_old/diffcalc/settings.py
Normal file
@@ -0,0 +1,24 @@
|
||||
'''
|
||||
Created on Aug 5, 2013
|
||||
|
||||
@author: walton
|
||||
'''
|
||||
import os
|
||||
|
||||
from diffcalc.ub.persistence import UbCalculationNonPersister
|
||||
|
||||
# These should be by the user *before* importing other modules
|
||||
geometry = None
|
||||
hardware = None
|
||||
ubcalc_persister = UbCalculationNonPersister()
|
||||
|
||||
axes_scannable_group = None
|
||||
energy_scannable = None
|
||||
energy_scannable_multiplier_to_get_KeV=1
|
||||
|
||||
|
||||
# These will be set by dcyou, dcvlieg or dcwillmot
|
||||
ubcalc_strategy = None
|
||||
angles_to_hkl_function = None # Used by checkub to avoid coupling it to an hkl module
|
||||
include_sigtau=False
|
||||
include_reference=False
|
||||
0
script/__Lib/diffcalc_old/diffcalc/ub/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcalc/ub/__init__.py
Normal file
637
script/__Lib/diffcalc_old/diffcalc/ub/calc.py
Normal file
637
script/__Lib/diffcalc_old/diffcalc/ub/calc.py
Normal file
@@ -0,0 +1,637 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc.ub.calcstate import decode_ubcalcstate
|
||||
from diffcalc.ub.calcstate import UBCalcState
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList
|
||||
from diffcalc.ub.persistence import UBCalculationJSONPersister, UBCalculationPersister
|
||||
from diffcalc.util import DiffcalcException, cross3, dot3, bold
|
||||
from math import acos, cos, sin, pi
|
||||
from diffcalc.ub.reference import YouReference
|
||||
|
||||
try:
|
||||
from numpy import matrix, hstack
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix, hstack
|
||||
from numjy.linalg import norm
|
||||
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList
|
||||
from diffcalc.util import DiffcalcException, cross3, dot3
|
||||
|
||||
SMALL = 1e-7
|
||||
TODEG = 180 / pi
|
||||
|
||||
WIDTH = 13
|
||||
|
||||
def z(num):
|
||||
"""Round to zero if small. This is useful to get rid of erroneous
|
||||
minus signs resulting from float representation close to zero.
|
||||
"""
|
||||
if abs(num) < SMALL:
|
||||
num = 0
|
||||
return num
|
||||
|
||||
#The UB matrix is used to find or set the orientation of a set of
|
||||
#planes described by an hkl vector. The U matrix can be used to find
|
||||
#or set the orientation of the crystal lattices' y axis. If there is
|
||||
#crystal miscut the crystal lattices y axis is not parallel to the
|
||||
#crystals optical surface normal. For surface diffraction experiments,
|
||||
#where not only the crystal lattice must be oriented appropriately but
|
||||
#so must the crystal's optical surface, two angles tau and sigma are
|
||||
#used to describe the difference between the two. Sigma is (minus) the
|
||||
#ammount of chi axis rotation and tau (minus) the ammount of phi axis
|
||||
#rotation needed to move the surface normal into the direction of the
|
||||
|
||||
|
||||
class PaperSpecificUbCalcStrategy(object):
|
||||
|
||||
def calculate_q_phi(self, pos):
|
||||
"""Calculate hkl in the phi frame in units of 2 * pi / lambda from
|
||||
pos object in radians"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class UBCalculation:
|
||||
"""A UB matrix calculation for an experiment.
|
||||
|
||||
Contains the parameters for the _crystal under test, a list of measured
|
||||
reflections and, if its been calculated, a UB matrix to be used by the rest
|
||||
of the code.
|
||||
"""
|
||||
|
||||
def __init__(self, hardware, diffractometerPluginObject,
|
||||
persister, strategy, include_sigtau=True, include_reference=True):
|
||||
|
||||
# The diffractometer geometry is required to map the internal angles
|
||||
# into those used by this diffractometer (for display only)
|
||||
|
||||
self._hardware = hardware
|
||||
self._geometry = diffractometerPluginObject
|
||||
self._persister = persister
|
||||
self._strategy = strategy
|
||||
self.include_sigtau = include_sigtau
|
||||
self.include_reference = include_reference
|
||||
self._clear()
|
||||
|
||||
def _get_diffractometer_axes_names(self):
|
||||
return self._hardware.get_axes_names()
|
||||
|
||||
def _clear(self, name=None):
|
||||
# NOTE the Diffraction calculator is expecting this object to exist in
|
||||
# the long run. We can't remove this entire object, and recreate it.
|
||||
# It also contains a required link to the angle calculator.
|
||||
reflist = ReflectionList(self._geometry, self._get_diffractometer_axes_names())
|
||||
reference = YouReference(self._get_UB)
|
||||
self._state = UBCalcState(name=name, reflist=reflist, reference=reference)
|
||||
self._U = None
|
||||
self._UB = None
|
||||
self._state.configure_calc_type()
|
||||
|
||||
### State ###
|
||||
def start_new(self, name):
|
||||
"""start_new(name) --- creates a new blank ub calculation"""
|
||||
# Create storage object if name does not exist (TODO)
|
||||
if name in self._persister.list():
|
||||
print ("No UBCalculation started: There is already a calculation "
|
||||
"called: " + name)
|
||||
print "Saved calculations: " + repr(self._persister.list())
|
||||
return
|
||||
self._clear(name)
|
||||
self.save()
|
||||
|
||||
def load(self, name):
|
||||
state = self._persister.load(name)
|
||||
if isinstance(self._persister, UBCalculationJSONPersister):
|
||||
self._state = decode_ubcalcstate(state, self._geometry, self._get_diffractometer_axes_names())
|
||||
self._state.reference.get_UB = self._get_UB
|
||||
elif isinstance(self._persister, UBCalculationPersister):
|
||||
self._state = state
|
||||
else:
|
||||
raise Exception('Unexpected persister type: ' + str(self._persister))
|
||||
if self._state.manual_U is not None:
|
||||
self.set_U_manually(self._state.manual_U)
|
||||
elif self._state.manual_UB is not None:
|
||||
self.set_UB_manually(self._state.manual_UB)
|
||||
elif self._state.or0 is not None:
|
||||
if self._state.or1 is None:
|
||||
self.calculate_UB_from_primary_only()
|
||||
else:
|
||||
self.calculate_UB()
|
||||
else:
|
||||
pass
|
||||
|
||||
def save(self):
|
||||
self.saveas(self._state.name)
|
||||
|
||||
def saveas(self, name):
|
||||
self._state.name = name
|
||||
self._persister.save(self._state, name)
|
||||
|
||||
def listub(self):
|
||||
return self._persister.list()
|
||||
|
||||
def listub_metadata(self):
|
||||
return self._persister.list_metadata()
|
||||
|
||||
def remove(self, name):
|
||||
self._persister.remove(name)
|
||||
if self._state == name:
|
||||
self._clear(name)
|
||||
|
||||
def getState(self):
|
||||
return self._state.getState()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
if self._state.name is None:
|
||||
return "<<< No UB calculation started >>>"
|
||||
lines = []
|
||||
lines.append(bold("UBCALC"))
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" name:".ljust(WIDTH) + self._state.name.rjust(9))
|
||||
|
||||
if self.include_sigtau:
|
||||
lines.append("")
|
||||
lines.append(
|
||||
" sigma:".ljust(WIDTH) + ("% 9.5f" % self._state.sigma).rjust(9))
|
||||
lines.append(
|
||||
" tau:".ljust(WIDTH) + ("% 9.5f" % self._state.tau).rjust(9))
|
||||
|
||||
if self.include_reference:
|
||||
lines.append("")
|
||||
ub_calculated = self._UB is not None
|
||||
lines.extend(self._state.reference.repr_lines(ub_calculated, WIDTH))
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("CRYSTAL"))
|
||||
lines.append("")
|
||||
|
||||
if self._state.crystal is None:
|
||||
lines.append(" <<< none specified >>>")
|
||||
else:
|
||||
lines.extend(self._state.crystal.str_lines())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("UB MATRIX"))
|
||||
lines.append("")
|
||||
|
||||
if self._UB is None:
|
||||
lines.append(" <<< none calculated >>>")
|
||||
else:
|
||||
lines.extend(self.str_lines_u())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_u_angle_and_axis())
|
||||
lines.append("")
|
||||
lines.extend(self.str_lines_ub())
|
||||
|
||||
lines.append("")
|
||||
lines.append(bold("REFLECTIONS"))
|
||||
lines.append("")
|
||||
|
||||
lines.extend(self._state.reflist.str_lines())
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
def str_lines_u(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
U = self.U
|
||||
lines.append(" U matrix:".ljust(WIDTH) +
|
||||
fmt % (z(U[0, 0]), z(U[0, 1]), z(U[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[1, 0]), z(U[1, 1]), z(U[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(U[2, 0]), z(U[2, 1]), z(U[2, 2])))
|
||||
return lines
|
||||
|
||||
def str_lines_u_angle_and_axis(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
y = matrix('0; 0; 1')
|
||||
rotation_axis = cross3(y, self.U * y)
|
||||
if abs(norm(rotation_axis)) < SMALL:
|
||||
lines.append(" U angle:".ljust(WIDTH) + " 0")
|
||||
else:
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
cos_rotation_angle = dot3(y, self.U * y)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
lines.append(" angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
|
||||
lines.append(" axis:".ljust(WIDTH) + fmt % tuple((rotation_axis.T).tolist()[0]))
|
||||
|
||||
return lines
|
||||
|
||||
def str_lines_ub(self):
|
||||
lines = []
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
UB = self.UB
|
||||
lines.append(" UB matrix:".ljust(WIDTH) +
|
||||
fmt % (z(UB[0, 0]), z(UB[0, 1]), z(UB[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[1, 0]), z(UB[1, 1]), z(UB[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(UB[2, 0]), z(UB[2, 1]), z(UB[2, 2])))
|
||||
return lines
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._state.name
|
||||
### Lattice ###
|
||||
|
||||
def set_lattice(self, name, *shortform):
|
||||
"""
|
||||
Converts a list shortform crystal parameter specification to a six-long
|
||||
tuple returned as . Returns None if wrong number of input args. See
|
||||
set_lattice() for a description of the shortforms supported.
|
||||
|
||||
shortformLattice -- a tuple as follows:
|
||||
[a] - assumes cubic
|
||||
[a,b]) - assumes tetragonal
|
||||
[a,b,c]) - assumes ortho
|
||||
[a,b,c,gam]) - assumes mon/hex gam different from 90.
|
||||
[a,b,c,alp,bet,gam]) - for arbitrary
|
||||
where all measurements in angstroms and angles in degrees
|
||||
"""
|
||||
self._set_lattice_without_saving(name, *shortform)
|
||||
self.save()
|
||||
|
||||
def _set_lattice_without_saving(self, name, *shortform):
|
||||
sf = shortform
|
||||
if len(sf) == 1:
|
||||
fullform = (sf[0], sf[0], sf[0], 90., 90., 90.) # cubic
|
||||
elif len(sf) == 2:
|
||||
fullform = (sf[0], sf[0], sf[1], 90., 90., 90.) # tetragonal
|
||||
elif len(sf) == 3:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., 90.) # ortho
|
||||
elif len(sf) == 4:
|
||||
fullform = (sf[0], sf[1], sf[2], 90., 90., sf[3]) # mon/hex gam
|
||||
# not 90
|
||||
elif len(sf) == 5:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
elif len(sf) == 6:
|
||||
fullform = sf # triclinic/arbitrary
|
||||
else:
|
||||
raise ValueError("wrong length input to set_lattice")
|
||||
self._set_lattice(name, *fullform)
|
||||
|
||||
def _set_lattice(self, name, a, b, c, alpha, beta, gamma):
|
||||
"""set lattice parameters in degrees"""
|
||||
if self._state.name is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot set lattice until a UBCalcaluation has been started "
|
||||
"with newubcalc")
|
||||
self._state.crystal = CrystalUnderTest(name, a, b, c, alpha, beta, gamma)
|
||||
# Clear U and UB if these exist
|
||||
if self._U is not None: # (UB will also exist)
|
||||
print "Warning: the old UB calculation has been cleared."
|
||||
print " Use 'calcub' to recalculate with old reflections."
|
||||
|
||||
### Surface normal stuff ###
|
||||
|
||||
def _gettau(self):
|
||||
"""
|
||||
Returns tau (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some chi axis rotation (minus sigma) brings the
|
||||
optical surface normal parallelto the omega axis.
|
||||
"""
|
||||
return self._state.tau
|
||||
|
||||
def _settau(self, tau):
|
||||
self._state.tau = tau
|
||||
self.save()
|
||||
|
||||
tau = property(_gettau, _settau)
|
||||
|
||||
def _getsigma(self):
|
||||
"""
|
||||
Returns sigma (in degrees): the (minus) ammount of phi axis rotation ,
|
||||
that together with some phi axis rotation (minus tau) brings the
|
||||
optical surface normal parallel to the omega axis.
|
||||
"""
|
||||
return self._state.sigma
|
||||
|
||||
def _setsigma(self, sigma):
|
||||
self.state._sigma = sigma
|
||||
self.save()
|
||||
|
||||
sigma = property(_getsigma, _setsigma)
|
||||
|
||||
|
||||
### Reference vector ###
|
||||
|
||||
def _get_n_phi(self):
|
||||
return self._state.reference.n_phi
|
||||
|
||||
n_phi = property(_get_n_phi)
|
||||
|
||||
def set_n_phi_configured(self, n_phi):
|
||||
self._state.reference.n_phi_configured = n_phi
|
||||
self.save()
|
||||
|
||||
def set_n_hkl_configured(self, n_hkl):
|
||||
self._state.reference.n_hkl_configured = n_hkl
|
||||
self.save()
|
||||
|
||||
def print_reference(self):
|
||||
print '\n'.join(self._state.reference.repr_lines(self.is_ub_calculated()))
|
||||
|
||||
### Reflections ###
|
||||
|
||||
def add_reflection(self, h, k, l, position, energy, tag, time):
|
||||
"""add_reflection(h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.add_reflection(h, k, l, position, energy, tag, time)
|
||||
self.save() # incase autocalculateUbAndReport fails
|
||||
|
||||
# If second reflection has just been added then calculateUB
|
||||
if len(self._state.reflist) == 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def edit_reflection(self, num, h, k, l, position, energy, tag, time):
|
||||
"""
|
||||
edit_reflection(num, h, k, l, position, tag=None) -- adds a reflection
|
||||
|
||||
position is in degrees and in the systems internal representation.
|
||||
"""
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("No UBCalculation loaded")
|
||||
self._state.reflist.edit_reflection(num, h, k, l, position, energy, tag, time)
|
||||
|
||||
# If first or second reflection has been changed and there are at least
|
||||
# two reflections then recalculate UB
|
||||
if (num == 1 or num == 2) and len(self._state.reflist) >= 2:
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def get_reflection(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.getReflection(num)
|
||||
|
||||
def get_reflection_in_external_angles(self, num):
|
||||
"""--> ( [h, k, l], position, energy, tag, time
|
||||
num starts at 1, position in degrees"""
|
||||
return self._state.reflist.get_reflection_in_external_angles(num)
|
||||
|
||||
def get_number_reflections(self):
|
||||
return 0 if self._state.reflist is None else len(self._state.reflist)
|
||||
|
||||
def del_reflection(self, reflectionNumber):
|
||||
self._state.reflist.removeReflection(reflectionNumber)
|
||||
if ((reflectionNumber == 1 or reflectionNumber == 2) and
|
||||
(self._U != None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def swap_reflections(self, num1, num2):
|
||||
self._state.reflist.swap_reflections(num1, num2)
|
||||
if ((num1 == 1 or num1 == 2 or num2 == 1 or num2 == 2) and
|
||||
(self._U != None)):
|
||||
self._autocalculateUbAndReport()
|
||||
self.save()
|
||||
|
||||
def _autocalculateUbAndReport(self):
|
||||
if len(self._state.reflist) < 2:
|
||||
pass
|
||||
elif self._state.crystal is None:
|
||||
print ("Not calculating UB matrix as no lattice parameters have "
|
||||
"been specified.")
|
||||
elif not self._state.is_okay_to_autocalculate_ub:
|
||||
print ("Not calculating UB matrix as it has been manually set. "
|
||||
"Use 'calcub' to explicitly recalculate it.")
|
||||
else: # okay to autocalculate
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
self.calculate_UB()
|
||||
|
||||
# @property
|
||||
# def reflist(self):
|
||||
# return self._state.reflist
|
||||
### Calculations ###
|
||||
|
||||
def set_U_manually(self, m):
|
||||
"""Manually sets U. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix."
|
||||
else:
|
||||
print "Recalculating UB matrix."
|
||||
|
||||
self._state.configure_calc_type(manual_U=m)
|
||||
self._U = m
|
||||
if self._state.crystal is None:
|
||||
raise DiffcalcException(
|
||||
"A crystal must be specified before manually setting U")
|
||||
self._UB = self._U * self._state.crystal.B
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
self.save()
|
||||
|
||||
def set_UB_manually(self, m):
|
||||
"""Manually sets UB. matrix must be 3*3 Jama or python matrix.
|
||||
Turns off aution UB calcualtion."""
|
||||
|
||||
# Check matrix is a 3*3 Jama matrix
|
||||
if m.__class__ != matrix:
|
||||
m = matrix(m) # assume its a python matrix
|
||||
if m.shape[0] != 3 or m.shape[1] != 3:
|
||||
raise ValueError("Expects 3*3 matrix")
|
||||
|
||||
self._state.configure_calc_type(manual_UB=m)
|
||||
self._UB = m
|
||||
self.save()
|
||||
|
||||
@property
|
||||
def U(self):
|
||||
if self._U is None:
|
||||
raise DiffcalcException(
|
||||
"No U matrix has been calculated during this ub calculation")
|
||||
return self._U
|
||||
|
||||
@property
|
||||
def UB(self):
|
||||
return self._get_UB()
|
||||
|
||||
def is_ub_calculated(self):
|
||||
return self._UB is not None
|
||||
|
||||
def _get_UB(self):
|
||||
if not self.is_ub_calculated():
|
||||
raise DiffcalcException(
|
||||
"No UB matrix has been calculated during this ub calculation")
|
||||
else:
|
||||
return self._UB
|
||||
|
||||
def calculate_UB(self):
|
||||
"""
|
||||
Calculate orientation matrix. Uses first two orientation reflections
|
||||
as in Busang and Levy, but for the diffractometer in Lohmeier and
|
||||
Vlieg.
|
||||
"""
|
||||
|
||||
# Major variables:
|
||||
# h1, h2: user input reciprical lattice vectors of the two reflections
|
||||
# h1c, h2c: user input vectors in cartesian crystal plane
|
||||
# pos1, pos2: measured diffractometer positions of the two reflections
|
||||
# u1a, u2a: measured reflection vectors in alpha frame
|
||||
# u1p, u2p: measured reflection vectors in phi frame
|
||||
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException("Cannot calculate a U matrix until a "
|
||||
"UBCalculation has been started with "
|
||||
"'newub'")
|
||||
try:
|
||||
(h1, pos1, _, _, _) = self._state.reflist.getReflection(1)
|
||||
(h2, pos2, _, _, _) = self._state.reflist.getReflection(2)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"Two reflections are required to calculate a u matrix")
|
||||
h1 = matrix([h1]).T # row->column
|
||||
h2 = matrix([h2]).T
|
||||
pos1.changeToRadians()
|
||||
pos2.changeToRadians()
|
||||
|
||||
# Compute the two reflections' reciprical lattice vectors in the
|
||||
# cartesian crystal frame
|
||||
B = self._state.crystal.B
|
||||
h1c = B * h1
|
||||
h2c = B * h2
|
||||
|
||||
u1p = self._strategy.calculate_q_phi(pos1)
|
||||
u2p = self._strategy.calculate_q_phi(pos2)
|
||||
|
||||
# Create modified unit vectors t1, t2 and t3 in crystal and phi systems
|
||||
t1c = h1c
|
||||
t3c = cross3(h1c, h2c)
|
||||
t2c = cross3(t3c, t1c)
|
||||
|
||||
t1p = u1p # FIXED from h1c 9July08
|
||||
t3p = cross3(u1p, u2p)
|
||||
t2p = cross3(t3p, t1p)
|
||||
|
||||
# ...and nornmalise and check that the reflections used are appropriate
|
||||
SMALL = 1e-4 # Taken from Vlieg's code
|
||||
e = DiffcalcException("Invalid orientation reflection(s)")
|
||||
|
||||
def normalise(m):
|
||||
d = norm(m)
|
||||
if d < SMALL:
|
||||
raise e
|
||||
return m / d
|
||||
|
||||
t1c = normalise(t1c)
|
||||
t2c = normalise(t2c)
|
||||
t3c = normalise(t3c)
|
||||
|
||||
t1p = normalise(t1p)
|
||||
t2p = normalise(t2p)
|
||||
t3p = normalise(t3p)
|
||||
|
||||
Tc = hstack([t1c, t2c, t3c])
|
||||
Tp = hstack([t1p, t2p, t3p])
|
||||
self._state.configure_calc_type(or0=1, or1=2)
|
||||
self._U = Tp * Tc.I
|
||||
self._UB = self._U * B
|
||||
self.save()
|
||||
|
||||
def calculate_UB_from_primary_only(self):
|
||||
"""
|
||||
Calculate orientation matrix with the shortest absolute angle change.
|
||||
Uses first orientation reflection
|
||||
"""
|
||||
|
||||
# Algorithm from http://www.j3d.org/matrix_faq/matrfaq_latest.html
|
||||
|
||||
# Get hkl and angle values for the first two refelctions
|
||||
if self._state.reflist is None:
|
||||
raise DiffcalcException(
|
||||
"Cannot calculate a u matrix until a UBCalcaluation has been "
|
||||
"started with newub")
|
||||
try:
|
||||
(h, pos, _, _, _) = self._state.reflist.getReflection(1)
|
||||
except IndexError:
|
||||
raise DiffcalcException(
|
||||
"One reflection is required to calculate a u matrix")
|
||||
|
||||
h = matrix([h]).T # row->column
|
||||
pos.changeToRadians()
|
||||
B = self._state.crystal.B
|
||||
h_crystal = B * h
|
||||
h_crystal = h_crystal * (1 / norm(h_crystal))
|
||||
|
||||
q_measured_phi = self._strategy.calculate_q_phi(pos)
|
||||
q_measured_phi = q_measured_phi * (1 / norm(q_measured_phi))
|
||||
|
||||
rotation_axis = cross3(h_crystal, q_measured_phi)
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
|
||||
cos_rotation_angle = dot3(h_crystal, q_measured_phi)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
|
||||
uvw = rotation_axis.T.tolist()[0] # TODO: cleanup
|
||||
print "resulting U angle: %.5f deg" % (rotation_angle * TODEG)
|
||||
u_repr = (', '.join(['% .5f' % el for el in uvw]))
|
||||
print "resulting U axis direction: [%s]" % u_repr
|
||||
|
||||
u, v, w = uvw
|
||||
rcos = cos(rotation_angle)
|
||||
rsin = sin(rotation_angle)
|
||||
m = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] # TODO: tidy
|
||||
m[0][0] = rcos + u * u * (1 - rcos)
|
||||
m[1][0] = w * rsin + v * u * (1 - rcos)
|
||||
m[2][0] = -v * rsin + w * u * (1 - rcos)
|
||||
m[0][1] = -w * rsin + u * v * (1 - rcos)
|
||||
m[1][1] = rcos + v * v * (1 - rcos)
|
||||
m[2][1] = u * rsin + w * v * (1 - rcos)
|
||||
m[0][2] = v * rsin + u * w * (1 - rcos)
|
||||
m[1][2] = -u * rsin + v * w * (1 - rcos)
|
||||
m[2][2] = rcos + w * w * (1 - rcos)
|
||||
|
||||
if self._UB is None:
|
||||
print "Calculating UB matrix from the first reflection only."
|
||||
else:
|
||||
print "Recalculating UB matrix from the first reflection only."
|
||||
print ("NOTE: A new UB matrix will not be automatically calculated "
|
||||
"when the orientation reflections are modified.")
|
||||
|
||||
self._state.configure_calc_type(or0=1)
|
||||
|
||||
self._U = matrix(m)
|
||||
self._UB = self._U * B
|
||||
|
||||
self.save()
|
||||
|
||||
def get_hkl_plane_distance(self, hkl):
|
||||
"""Calculates and returns the distance between planes"""
|
||||
return self._state.crystal.get_hkl_plane_distance(hkl)
|
||||
180
script/__Lib/diffcalc_old/diffcalc/ub/calcstate.py
Normal file
180
script/__Lib/diffcalc_old/diffcalc/ub/calcstate.py
Normal file
@@ -0,0 +1,180 @@
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
from diffcalc.ub.crystal import CrystalUnderTest
|
||||
from diffcalc.ub.reflections import ReflectionList, _Reflection
|
||||
from math import pi
|
||||
import datetime # @UnusedImport For crazy time eval code!
|
||||
from diffcalc.ub.reference import YouReference
|
||||
|
||||
try:
|
||||
from collection import OrderedDict
|
||||
except ImportError:
|
||||
from simplejson import OrderedDict
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
class UBCalcState():
|
||||
|
||||
def __init__(self, name=None, crystal=None, reflist=None, tau=0, sigma=0,
|
||||
manual_U=None, manual_UB=None, or0=None, or1=None, reference=None):
|
||||
|
||||
assert reflist is not None
|
||||
self.name = name
|
||||
self.crystal = crystal
|
||||
self.reflist = reflist
|
||||
self.tau = tau # degrees
|
||||
self.sigma = sigma # degrees
|
||||
self.manual_U = manual_U
|
||||
self.manual_UB = manual_UB
|
||||
self.or0 = or0
|
||||
self.or1 = or1
|
||||
self.reference = reference
|
||||
|
||||
@property
|
||||
def is_okay_to_autocalculate_ub(self):
|
||||
nothing_set = ((self.manual_U is None) and
|
||||
(self.manual_UB is None) and
|
||||
(self.or0 is None) and
|
||||
(self.or1 is None))
|
||||
or0_and_or1_used = (self.or0 is not None) and (self.or1 is not None)
|
||||
return nothing_set or or0_and_or1_used
|
||||
|
||||
|
||||
def configure_calc_type(self,
|
||||
manual_U=None,
|
||||
manual_UB=None,
|
||||
or0=None,
|
||||
or1=None):
|
||||
self.manual_U = manual_U
|
||||
self.manual_UB = manual_UB
|
||||
self.or0 = or0
|
||||
self.or1 = or1
|
||||
|
||||
|
||||
class UBCalcStateEncoder(json.JSONEncoder):
|
||||
|
||||
def default(self, obj):
|
||||
|
||||
if isinstance(obj, UBCalcState):
|
||||
d = OrderedDict()
|
||||
d['name'] = obj.name
|
||||
d['crystal'] = obj.crystal
|
||||
d['reflist'] = obj.reflist
|
||||
d['tau'] = obj.tau
|
||||
d['sigma'] = obj.sigma
|
||||
d['reference'] = obj.reference
|
||||
d['u'] = obj.manual_U
|
||||
d['ub'] = obj.manual_UB
|
||||
d['or0'] = obj.or0
|
||||
d['or1'] = obj.or1
|
||||
|
||||
return d
|
||||
|
||||
if isinstance(obj, CrystalUnderTest):
|
||||
return repr([obj._name, obj._a1, obj._a2, obj._a3, obj._alpha1 * TODEG,
|
||||
obj._alpha2 * TODEG, obj._alpha3 * TODEG])
|
||||
|
||||
if isinstance(obj, matrix):
|
||||
l = [', '.join((repr(e) for e in row)) for row in obj.tolist()]
|
||||
return l
|
||||
|
||||
if isinstance(obj, ReflectionList):
|
||||
d = OrderedDict()
|
||||
for n, ref in enumerate(obj._reflist):
|
||||
d[str(n+1)] = ref
|
||||
return d
|
||||
|
||||
if isinstance(obj, _Reflection):
|
||||
d = OrderedDict()
|
||||
d['tag'] = obj.tag
|
||||
d['hkl'] = repr([obj.h, obj.k, obj.l])
|
||||
d['pos'] = repr(list(obj.pos.totuple()))
|
||||
d['energy'] = obj.energy
|
||||
dt = eval(obj.time) # e.g. --> datetime.datetime(2013, 8, 5, 15, 47, 7, 962432)
|
||||
d['time'] = None if dt is None else dt.isoformat()
|
||||
return d
|
||||
|
||||
if isinstance(obj, YouReference):
|
||||
d = OrderedDict()
|
||||
if obj.n_hkl_configured is not None:
|
||||
d['n_hkl_configured'] = repr(obj.n_hkl_configured.T.tolist()[0])
|
||||
else:
|
||||
d['n_hkl_configured'] = None
|
||||
if obj.n_phi_configured is not None:
|
||||
d['n_phi_configured'] = repr(obj.n_phi_configured.T.tolist()[0])
|
||||
else:
|
||||
d['n_phi_configured'] = None
|
||||
return d
|
||||
|
||||
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
||||
|
||||
def decode_ubcalcstate(state, geometry, diffractometer_axes_names):
|
||||
|
||||
return UBCalcState(
|
||||
name=state['name'],
|
||||
crystal=state['crystal'] and CrystalUnderTest(*eval(state['crystal'])),
|
||||
reflist=decode_reflist(state['reflist'], geometry, diffractometer_axes_names),
|
||||
tau=state['tau'],
|
||||
sigma=state['sigma'],
|
||||
manual_U=state['u'] and decode_matrix(state['u']),
|
||||
manual_UB=state['ub'] and decode_matrix(state['ub']),
|
||||
or0=state['or0'],
|
||||
or1=state['or1'],
|
||||
reference=decode_reference(state.get('reference', None))
|
||||
)
|
||||
|
||||
|
||||
def decode_matrix(rows):
|
||||
return matrix([[eval(e) for e in row.split(', ')] for row in rows])
|
||||
|
||||
|
||||
def decode_reflist(reflist_dict, geometry, diffractometer_axes_names):
|
||||
reflections = []
|
||||
for key in sorted(reflist_dict.keys()):
|
||||
reflections.append(decode_reflection(reflist_dict[key], geometry))
|
||||
|
||||
return ReflectionList(geometry, diffractometer_axes_names, reflections)
|
||||
|
||||
|
||||
def decode_reflection(ref_dict, geometry):
|
||||
h, k, l = eval(ref_dict['hkl'])
|
||||
time = ref_dict['time'] and gt(ref_dict['time'])
|
||||
pos_tuple = eval(ref_dict['pos'])
|
||||
try:
|
||||
position = geometry.create_position(*pos_tuple)
|
||||
except AttributeError:
|
||||
position = VliegPosition(*pos_tuple)
|
||||
return _Reflection(h, k, l, position, ref_dict['energy'], str(ref_dict['tag']), repr(time))
|
||||
|
||||
|
||||
def decode_reference(ref_dict):
|
||||
|
||||
reference = YouReference(None) # TODO: We can't set get_ub method yet (tangles!)
|
||||
if ref_dict:
|
||||
nhkl = ref_dict.get('n_hkl_configured', None)
|
||||
nphi = ref_dict.get('n_phi_configured', None)
|
||||
if nhkl:
|
||||
reference.n_hkl_configured = matrix([eval(nhkl)]).T
|
||||
if nphi:
|
||||
reference.n_phi_configured = matrix([eval(nphi)]).T
|
||||
return reference
|
||||
|
||||
# From: http://stackoverflow.com/questions/127803/how-to-parse-iso-formatted-date-in-python
|
||||
def gt(dt_str):
|
||||
dt, _, us= dt_str.partition(".")
|
||||
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
|
||||
us= int(us.rstrip("Z"), 10)
|
||||
return dt + datetime.timedelta(microseconds=us)
|
||||
137
script/__Lib/diffcalc_old/diffcalc/ub/crystal.py
Normal file
137
script/__Lib/diffcalc_old/diffcalc/ub/crystal.py
Normal file
@@ -0,0 +1,137 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, cos, sin, acos, sqrt
|
||||
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
SMALL = 1e-7
|
||||
|
||||
def z(num):
|
||||
"""Round to zero if small. This is useful to get rid of erroneous
|
||||
minus signs resulting from float representation close to zero.
|
||||
"""
|
||||
if abs(num) < SMALL:
|
||||
num = 0
|
||||
return num
|
||||
|
||||
|
||||
class CrystalUnderTest(object):
|
||||
"""
|
||||
Contains the lattice parameters and calculated B matrix for the crytsal
|
||||
under test. Also Calculates the distance between planes at a given hkl
|
||||
value.
|
||||
|
||||
The lattice paraemters can be specified and then if desired saved to a
|
||||
__library to be loaded later. The parameters are persisted across restarts.
|
||||
Lattices stored in config/var/crystals.xml .
|
||||
"""
|
||||
|
||||
def __init__(self, name, a, b, c, alpha, beta, gamma):
|
||||
'''Creates a new lattice and calculates related values.
|
||||
|
||||
Keyword arguments:
|
||||
name -- a string
|
||||
a,b,c,alpha,beta,gamma -- lengths and angles (in degrees)
|
||||
'''
|
||||
|
||||
self._name = name
|
||||
|
||||
# Set the direct lattice parameters
|
||||
self._a1 = a1 = a
|
||||
self._a2 = a2 = b
|
||||
self._a3 = a3 = c
|
||||
self._alpha1 = alpha1 = alpha * TORAD
|
||||
self._alpha2 = alpha2 = beta * TORAD
|
||||
self._alpha3 = alpha3 = gamma * TORAD
|
||||
|
||||
# Calculate the reciprocal lattice parameters
|
||||
self._beta1 = acos((cos(alpha2) * cos(alpha3) - cos(alpha1)) /
|
||||
(sin(alpha2) * sin(alpha3)))
|
||||
|
||||
self._beta2 = beta2 = acos((cos(alpha1) * cos(alpha3) - cos(alpha2)) /
|
||||
(sin(alpha1) * sin(alpha3)))
|
||||
|
||||
self._beta3 = beta3 = acos((cos(alpha1) * cos(alpha2) - cos(alpha3)) /
|
||||
(sin(alpha1) * sin(alpha2)))
|
||||
|
||||
volume = (a1 * a2 * a3 *
|
||||
sqrt(1 + 2 * cos(alpha1) * cos(alpha2) * cos(alpha3) -
|
||||
cos(alpha1) ** 2 - cos(alpha2) ** 2 - cos(alpha3) ** 2))
|
||||
|
||||
self._b1 = b1 = 2 * pi * a2 * a3 * sin(alpha1) / volume
|
||||
self._b2 = b2 = 2 * pi * a1 * a3 * sin(alpha2) / volume
|
||||
self._b3 = b3 = 2 * pi * a1 * a2 * sin(alpha3) / volume
|
||||
|
||||
# Calculate the BMatrix from the direct and reciprical parameters.
|
||||
# Reference: Busang and Levy (1967)
|
||||
self._bMatrix = matrix([
|
||||
[b1, b2 * cos(beta3), b3 * cos(beta2)],
|
||||
[0.0, b2 * sin(beta3), -b3 * sin(beta2) * cos(alpha1)],
|
||||
[0.0, 0.0, 2 * pi / a3]])
|
||||
|
||||
@property
|
||||
def B(self):
|
||||
'''
|
||||
Returns the B matrix, may be null if crystal is not set, or if there
|
||||
was a problem calculating this'''
|
||||
return self._bMatrix
|
||||
|
||||
def get_hkl_plane_distance(self, hkl):
|
||||
'''Calculates and returns the distance between planes'''
|
||||
hkl = matrix([hkl])
|
||||
bReduced = self._bMatrix / (2 * pi)
|
||||
bMT = bReduced.I * bReduced.T.I
|
||||
return 1.0 / sqrt((hkl * bMT.I * hkl.T)[0,0])
|
||||
|
||||
def __str__(self):
|
||||
''' Returns lattice name and all set and calculated parameters'''
|
||||
return '\n'.join(self.str_lines())
|
||||
|
||||
def str_lines(self):
|
||||
WIDTH = 13
|
||||
if self._name is None:
|
||||
return [" none specified"]
|
||||
|
||||
b = self._bMatrix
|
||||
lines = []
|
||||
lines.append(" name:".ljust(WIDTH) + self._name.rjust(9))
|
||||
lines.append("")
|
||||
lines.append(" a, b, c:".ljust(WIDTH) +
|
||||
"% 9.5f % 9.5f % 9.5f" % (self.getLattice()[1:4]))
|
||||
lines.append(" " * WIDTH +
|
||||
"% 9.5f % 9.5f % 9.5f" % (self.getLattice()[4:]))
|
||||
lines.append("")
|
||||
|
||||
fmt = "% 9.5f % 9.5f % 9.5f"
|
||||
lines.append(" B matrix:".ljust(WIDTH) +
|
||||
fmt % (z(b[0, 0]), z(b[0, 1]), z(b[0, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(b[1, 0]), z(b[1, 1]), z(b[1, 2])))
|
||||
lines.append(' ' * WIDTH + fmt % (z(b[2, 0]), z(b[2, 1]), z(b[2, 2])))
|
||||
return lines
|
||||
|
||||
def getLattice(self):
|
||||
return(self._name, self._a1, self._a2, self._a3, self._alpha1 * TODEG,
|
||||
self._alpha2 * TODEG, self._alpha3 * TODEG)
|
||||
|
||||
151
script/__Lib/diffcalc_old/diffcalc/ub/persistence.py
Normal file
151
script/__Lib/diffcalc_old/diffcalc/ub/persistence.py
Normal file
@@ -0,0 +1,151 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import os, glob
|
||||
from diffcalc.ub.calcstate import UBCalcStateEncoder
|
||||
import datetime
|
||||
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
|
||||
|
||||
def is_writable(directory):
|
||||
"""Return true if the file is writable from the current user
|
||||
"""
|
||||
probe = os.path.join(directory, "probe")
|
||||
try:
|
||||
open(probe, 'w')
|
||||
except IOError:
|
||||
return False
|
||||
else:
|
||||
os.remove(probe)
|
||||
return True
|
||||
|
||||
def check_directory_appropriate(directory):
|
||||
|
||||
if not os.path.exists(directory):
|
||||
raise IOError("'%s' does not exist")
|
||||
|
||||
if not os.path.isdir(directory):
|
||||
raise IOError("'%s' is not a directory")
|
||||
|
||||
if not is_writable(directory):
|
||||
raise IOError("'%s' is not writable")
|
||||
|
||||
|
||||
class UBCalculationJSONPersister(object):
|
||||
|
||||
def __init__(self, directory):
|
||||
check_directory_appropriate(directory)
|
||||
self.directory = directory
|
||||
self.description = directory
|
||||
|
||||
def filepath(self, name):
|
||||
return os.path.join(self.directory, name + '.json')
|
||||
|
||||
def save(self, state, name):
|
||||
# FORMAT = '%Y-%m-%d %H:%M:%S'
|
||||
# time_string = datetime.datetime.strftime(datetime.datetime.now(), FORMAT)
|
||||
with open(self.filepath(name), 'w') as f:
|
||||
json.dump(state, f, indent=4, cls=UBCalcStateEncoder)
|
||||
|
||||
def load(self, name):
|
||||
with open(self.filepath(name), 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
def list(self): # @ReservedAssignment
|
||||
files = self._get_save_files()
|
||||
return [os.path.basename(f + '.json').split('.json')[0] for f in files]
|
||||
|
||||
def list_metadata(self):
|
||||
metadata = []
|
||||
for f in self._get_save_files():
|
||||
dt = datetime.datetime.fromtimestamp(os.path.getmtime(f))
|
||||
metadata.append(dt.strftime('%d %b %Y (%H:%M)'))
|
||||
return metadata
|
||||
|
||||
def _get_save_files(self):
|
||||
files = filter(os.path.isfile, glob.glob(os.path.join(self.directory, '*.json')))
|
||||
files.sort(key=lambda x: os.path.getmtime(x))
|
||||
files.reverse()
|
||||
return files
|
||||
|
||||
def remove(self, name):
|
||||
os.remove(self.filepath(name))
|
||||
|
||||
|
||||
|
||||
class UBCalculationPersister(object):
|
||||
"""Attempts to the use the gda's database to store ub calculation state
|
||||
"""
|
||||
def __init__(self):
|
||||
try:
|
||||
from uk.ac.diamond.daq.persistence.jythonshelf import LocalJythonShelfManager
|
||||
from uk.ac.diamond.daq.persistence.jythonshelf.LocalDatabase import \
|
||||
LocalDatabaseException
|
||||
self.shelf = LocalJythonShelfManager.getLocalObjectShelf(
|
||||
'diffcalc.ub')
|
||||
except ImportError, e:
|
||||
print ("!!! UBCalculationPersister could not import the gda database "
|
||||
"code: " + repr(e))
|
||||
self.shelf = None
|
||||
except LocalDatabaseException, e:
|
||||
print ("UBCalculationPersister could not connect to the gda "
|
||||
"database: " + repr(e))
|
||||
self.shelf = None
|
||||
self.description = 'GDA sql database'
|
||||
|
||||
def save(self, state, key):
|
||||
if self.shelf is not None:
|
||||
self.shelf[key] = state
|
||||
else:
|
||||
print "<<<no database available to save UB calculation>>>"
|
||||
|
||||
def load(self, name):
|
||||
if self.shelf is not None:
|
||||
return self.shelf[name]
|
||||
else:
|
||||
raise IOError("Could not load UB calculation: no database available")
|
||||
|
||||
def list(self): # @ReservedAssignment
|
||||
if self.shelf is not None:
|
||||
names = list(self.shelf.keys())
|
||||
names.sort()
|
||||
return names
|
||||
else:
|
||||
return []
|
||||
|
||||
def remove(self, name):
|
||||
if self.shelf is not None:
|
||||
del self.shelf[name]
|
||||
else:
|
||||
raise IOError("Could not remove UB calculation: no database available")
|
||||
|
||||
|
||||
class UbCalculationNonPersister(UBCalculationPersister):
|
||||
"""
|
||||
A version of UBCalculationPersister that simply stores to a local dict
|
||||
rather than a database. Useful for testing.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.shelf = dict()
|
||||
self.description = 'memory only'
|
||||
99
script/__Lib/diffcalc_old/diffcalc/ub/reference.py
Normal file
99
script/__Lib/diffcalc_old/diffcalc/ub/reference.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from math import pi
|
||||
|
||||
try:
|
||||
from numpy import matrix, hstack
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix, hstack
|
||||
from numjy.linalg import norm
|
||||
|
||||
|
||||
from math import pi, sin, cos, tan, acos, atan2, asin, sqrt, atan
|
||||
|
||||
from diffcalc.util import DiffcalcException, bound, angle_between_vectors
|
||||
from diffcalc.util import cross3, z_rotation, x_rotation, dot3
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
SMALL = 1e-7
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
|
||||
class YouReference(object):
|
||||
|
||||
def __init__(self, get_UB):
|
||||
self.get_UB = get_UB # callable
|
||||
self._n_phi_configured = None
|
||||
self._n_hkl_configured = None
|
||||
self._set_n_phi_configured(matrix('0; 0; 1'))
|
||||
|
||||
def _set_n_phi_configured(self, n_phi):
|
||||
self._n_phi_configured = n_phi
|
||||
self._n_hkl_configured = None
|
||||
|
||||
def _get_n_phi_configured(self):
|
||||
return self._n_phi_configured
|
||||
|
||||
n_phi_configured = property(_get_n_phi_configured, _set_n_phi_configured)
|
||||
|
||||
def _set_n_hkl_configured(self, n_hkl):
|
||||
self._n_phi_configured = None
|
||||
self._n_hkl_configured = n_hkl
|
||||
|
||||
def _get_n_hkl_configured(self):
|
||||
return self._n_hkl_configured
|
||||
|
||||
n_hkl_configured = property(_get_n_hkl_configured, _set_n_hkl_configured)
|
||||
|
||||
@property
|
||||
def n_phi(self):
|
||||
n_phi = (self.get_UB() * self._n_hkl_configured if self._n_phi_configured is None
|
||||
else self._n_phi_configured)
|
||||
return n_phi / norm(n_phi)
|
||||
|
||||
@property
|
||||
def n_hkl(self):
|
||||
n_hkl = (self.get_UB().I * self._n_phi_configured if self._n_hkl_configured is None
|
||||
else self._n_hkl_configured)
|
||||
return n_hkl / norm(n_hkl)
|
||||
|
||||
def _pretty_vector(self, m):
|
||||
return ' '.join([('% 9.5f' % e).rjust(9) for e in m.T.tolist()[0]])
|
||||
|
||||
def repr_lines(self, ub_calculated, WIDTH=9):
|
||||
SET_LABEL = ' <- set'
|
||||
lines = []
|
||||
if self._n_phi_configured is not None:
|
||||
nphi_label = SET_LABEL
|
||||
nhkl_label = ''
|
||||
elif self._n_hkl_configured is not None:
|
||||
nphi_label = ''
|
||||
nhkl_label = SET_LABEL
|
||||
else:
|
||||
raise AssertionError("Neither a manual n_phi nor n_hkl is configured")
|
||||
|
||||
if ub_calculated:
|
||||
lines.append(" n_phi:".ljust(WIDTH) + self._pretty_vector(self.n_phi) + nphi_label)
|
||||
lines.append(" n_hkl:".ljust(WIDTH) + self._pretty_vector(self.n_hkl) + nhkl_label)
|
||||
rotation_axis = cross3(matrix('0; 0; 1'), self.n_phi)
|
||||
if abs(norm(rotation_axis)) < SMALL:
|
||||
lines.append(" miscut:".ljust(WIDTH) + " None")
|
||||
else:
|
||||
rotation_axis = rotation_axis * (1 / norm(rotation_axis))
|
||||
cos_rotation_angle = dot3(matrix('0; 0; 1'), self.n_phi)
|
||||
rotation_angle = acos(cos_rotation_angle)
|
||||
lines.append(" miscut:")
|
||||
lines.append(" angle:".ljust(WIDTH) + "% 9.5f" % (rotation_angle * TODEG))
|
||||
lines.append(" axis:".ljust(WIDTH) + self._pretty_vector(rotation_axis))
|
||||
|
||||
else: # no ub calculated
|
||||
if self._n_phi_configured is not None:
|
||||
lines.append(" n_phi:".ljust(WIDTH) + self._pretty_vector(self._n_phi_configured) + SET_LABEL)
|
||||
elif self._n_hkl_configured is not None:
|
||||
lines.append(" n_hkl:".ljust(WIDTH) + self._pretty_vector(self._n_hkl_configured) + SET_LABEL)
|
||||
|
||||
return lines
|
||||
|
||||
126
script/__Lib/diffcalc_old/diffcalc/ub/reflections.py
Normal file
126
script/__Lib/diffcalc_old/diffcalc/ub/reflections.py
Normal file
@@ -0,0 +1,126 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from copy import deepcopy
|
||||
import datetime # @UnusedImport for the eval below
|
||||
from diffcalc.util import DiffcalcException, bold
|
||||
from diffcalc.hkl.vlieg.geometry import VliegPosition
|
||||
|
||||
|
||||
class _Reflection:
|
||||
"""A reflection"""
|
||||
def __init__(self, h, k, l, position, energy, tag, time):
|
||||
|
||||
self.h = float(h)
|
||||
self.k = float(k)
|
||||
self.l = float(l)
|
||||
self.pos = position
|
||||
self.tag = tag
|
||||
self.energy = float(energy) # energy=12.39842/lambda
|
||||
self.wavelength = 12.3984 / self.energy
|
||||
self.time = time # Saved as e.g. repr(datetime.now())
|
||||
|
||||
def __str__(self):
|
||||
return ("energy=%-6.3f h=%-4.2f k=%-4.2f l=%-4.2f alpha=%-8.4f "
|
||||
"delta=%-8.4f gamma=%-8.4f omega=%-8.4f chi=%-8.4f "
|
||||
"phi=%-8.4f %-s %s" % (self.energy, self.h, self.k, self.l,
|
||||
self.pos.alpha, self.pos.delta, self.pos.gamma, self.pos.omega,
|
||||
self.pos.chi, self.pos.phi, self.tag, self.time))
|
||||
|
||||
|
||||
class ReflectionList:
|
||||
|
||||
def __init__(self, diffractometerPluginObject, externalAngleNames, reflections=None):
|
||||
self._geometry = diffractometerPluginObject
|
||||
self._externalAngleNames = externalAngleNames
|
||||
self._reflist = reflections if reflections else []
|
||||
|
||||
|
||||
def add_reflection(self, h, k, l, position, energy, tag, time):
|
||||
"""adds a reflection, position in degrees
|
||||
"""
|
||||
if type(position) in (list, tuple):
|
||||
try:
|
||||
position = self._geometry.create_position(*position)
|
||||
except AttributeError:
|
||||
position = VliegPosition(*position)
|
||||
self._reflist += [_Reflection(h, k, l, position, energy, tag,
|
||||
time.__repr__())]
|
||||
|
||||
def edit_reflection(self, num, h, k, l, position, energy, tag, time):
|
||||
"""num starts at 1"""
|
||||
if type(position) in (list, tuple):
|
||||
position = VliegPosition(*position)
|
||||
try:
|
||||
self._reflist[num - 1] = _Reflection(h, k, l, position, energy, tag,
|
||||
time.__repr__())
|
||||
except IndexError:
|
||||
raise DiffcalcException("There is no reflection " + repr(num)
|
||||
+ " to edit.")
|
||||
|
||||
def getReflection(self, num):
|
||||
"""
|
||||
getReflection(num) --> ( [h, k, l], position, energy, tag, time ) --
|
||||
num starts at 1 position in degrees
|
||||
"""
|
||||
r = deepcopy(self._reflist[num - 1]) # for convenience
|
||||
return [r.h, r.k, r.l], deepcopy(r.pos), r.energy, r.tag, eval(r.time)
|
||||
|
||||
def get_reflection_in_external_angles(self, num):
|
||||
"""getReflection(num) --> ( [h, k, l], (angle1...angleN), energy, tag )
|
||||
-- num starts at 1 position in degrees"""
|
||||
r = deepcopy(self._reflist[num - 1]) # for convenience
|
||||
externalAngles = self._geometry.internal_position_to_physical_angles(r.pos)
|
||||
result = [r.h, r.k, r.l], externalAngles, r.energy, r.tag, eval(r.time)
|
||||
return result
|
||||
|
||||
def removeReflection(self, num):
|
||||
del self._reflist[num - 1]
|
||||
|
||||
def swap_reflections(self, num1, num2):
|
||||
orig1 = self._reflist[num1 - 1]
|
||||
self._reflist[num1 - 1] = self._reflist[num2 - 1]
|
||||
self._reflist[num2 - 1] = orig1
|
||||
|
||||
def __len__(self):
|
||||
return len(self._reflist)
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(self.str_lines())
|
||||
|
||||
def str_lines(self):
|
||||
axes = tuple(s.upper() for s in self._externalAngleNames)
|
||||
if not self._reflist:
|
||||
return [" <<< none specified >>>"]
|
||||
|
||||
lines = []
|
||||
|
||||
format = (" %6s %5s %5s %5s " + "%8s " * len(axes) + " TAG")
|
||||
values = ('ENERGY', 'H', 'K', 'L') + axes
|
||||
lines.append(bold(format % values))
|
||||
|
||||
for n in range(len(self._reflist)):
|
||||
ref_tuple = self.get_reflection_in_external_angles(n + 1)
|
||||
[h, k, l], externalAngles, energy, tag, _ = ref_tuple
|
||||
if tag is None:
|
||||
tag = ""
|
||||
format = (" %2d %6.3f % 4.2f % 4.2f % 4.2f " +
|
||||
"% 8.4f " * len(axes) + " %s")
|
||||
values = (n + 1, energy, h, k, l) + externalAngles + (tag,)
|
||||
lines.append(format % values)
|
||||
return lines
|
||||
532
script/__Lib/diffcalc_old/diffcalc/ub/ub.py
Normal file
532
script/__Lib/diffcalc_old/diffcalc/ub/ub.py
Normal file
@@ -0,0 +1,532 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from diffcalc import settings
|
||||
from diffcalc.ub.calc import UBCalculation
|
||||
|
||||
from math import asin, pi
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from numpy import matrix
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
|
||||
|
||||
from diffcalc.util import getInputWithDefault as promptForInput, \
|
||||
promptForNumber, promptForList, allnum, isnum, bold
|
||||
from diffcalc.util import command
|
||||
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
# When using ipython magic, these functions must not be imported to the top
|
||||
# level namespace. Doing so will stop them from being called with magic.
|
||||
|
||||
__all__ = ['addref', 'c2th', 'calcub', 'delref', 'editref', 'listub', 'loadub',
|
||||
'newub', 'saveubas', 'setlat', 'setu', 'setub', 'showref', 'swapref',
|
||||
'trialub', 'checkub', 'ub', 'ubcalc', 'rmub', 'clearref', 'lastub']
|
||||
|
||||
if settings.include_sigtau:
|
||||
__all__.append('sigtau')
|
||||
|
||||
if settings.include_reference:
|
||||
__all__.append('setnphi')
|
||||
__all__.append('setnhkl')
|
||||
|
||||
|
||||
ubcalc = UBCalculation(settings.hardware,
|
||||
settings.geometry,
|
||||
settings.ubcalc_persister,
|
||||
settings.ubcalc_strategy,
|
||||
settings.include_sigtau,
|
||||
settings.include_reference)
|
||||
|
||||
|
||||
|
||||
### UB state ###
|
||||
|
||||
@command
|
||||
def newub(name=None):
|
||||
"""newub {'name'} -- start a new ub calculation name
|
||||
"""
|
||||
if name is None:
|
||||
# interactive
|
||||
name = promptForInput('calculation name')
|
||||
ubcalc.start_new(name)
|
||||
setlat()
|
||||
elif isinstance(name, str):
|
||||
# just trying might cause confusion here
|
||||
ubcalc.start_new(name)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def loadub(name_or_num):
|
||||
"""loadub 'name' | num -- load an existing ub calculation
|
||||
"""
|
||||
if isinstance(name_or_num, str):
|
||||
ubcalc.load(name_or_num)
|
||||
else:
|
||||
ubcalc.load(ubcalc.listub()[int(name_or_num)])
|
||||
|
||||
@command
|
||||
def lastub():
|
||||
"""lastub -- load the last used ub calculation
|
||||
"""
|
||||
try:
|
||||
lastub_name = ubcalc.listub()[0]
|
||||
print "Loading ub calculation: '%s'" % lastub_name
|
||||
loadub(0)
|
||||
except IndexError:
|
||||
print "WARNING: There is no record of the last ub calculation used"
|
||||
|
||||
@command
|
||||
def rmub(name_or_num):
|
||||
"""rmub 'name'|num -- remove existing ub calculation
|
||||
"""
|
||||
if isinstance(name_or_num, str):
|
||||
ubcalc.remove(name_or_num)
|
||||
else:
|
||||
ubcalc.remove(ubcalc.listub()[int(name_or_num)])
|
||||
|
||||
@command
|
||||
def listub():
|
||||
"""listub -- list the ub calculations available to load.
|
||||
"""
|
||||
if hasattr(ubcalc._persister, 'description'):
|
||||
print "UB calculations in: " + ubcalc._persister.description
|
||||
else:
|
||||
print "UB calculations:"
|
||||
print
|
||||
ubnames = ubcalc.listub()
|
||||
# TODO: whole mechanism of making two calls is messy
|
||||
try:
|
||||
ub_metadata = ubcalc.listub_metadata()
|
||||
except AttributeError:
|
||||
ub_metadata = [''] * len(ubnames)
|
||||
|
||||
for n, name, data in zip(range(len(ubnames)), ubnames, ub_metadata):
|
||||
print "%2i) %-15s %s" % (n, name, data)
|
||||
|
||||
@command
|
||||
def saveubas(name):
|
||||
"""saveubas 'name' -- save the ub calculation with a new name
|
||||
"""
|
||||
if isinstance(name, str):
|
||||
# just trying might cause confusion here
|
||||
ubcalc.saveas(name)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def ub():
|
||||
"""ub -- show the complete state of the ub calculation
|
||||
"""
|
||||
#wavelength = float(hardware.get_wavelength())
|
||||
#energy = float(hardware.get_energy())
|
||||
print ubcalc.__str__()
|
||||
|
||||
### UB lattice ###
|
||||
|
||||
@command
|
||||
def setlat(name=None, *args):
|
||||
"""
|
||||
setlat -- interactively enter lattice parameters (Angstroms and Deg)
|
||||
setlat name a -- assumes cubic
|
||||
setlat name a b -- assumes tetragonal
|
||||
setlat name a b c -- assumes ortho
|
||||
setlat name a b c gamma -- assumes mon/hex with gam not equal to 90
|
||||
setlat name a b c alpha beta gamma -- arbitrary
|
||||
"""
|
||||
|
||||
if name is None: # Interactive
|
||||
name = promptForInput("crystal name")
|
||||
a = promptForNumber(' a', 1)
|
||||
b = promptForNumber(' b', a)
|
||||
c = promptForNumber(' c', a)
|
||||
alpha = promptForNumber('alpha', 90)
|
||||
beta = promptForNumber('beta', 90)
|
||||
gamma = promptForNumber('gamma', 90)
|
||||
ubcalc.set_lattice(name, a, b, c, alpha, beta, gamma)
|
||||
|
||||
elif (isinstance(name, str) and
|
||||
len(args) in (1, 2, 3, 4, 6) and
|
||||
allnum(args)):
|
||||
# first arg is string and rest are numbers
|
||||
ubcalc.set_lattice(name, *args)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def c2th(hkl, en=None):
|
||||
"""
|
||||
c2th [h k l] -- calculate two-theta angle for reflection
|
||||
"""
|
||||
if en is None:
|
||||
wl = settings.hardware.get_wavelength() # @UndefinedVariable
|
||||
else:
|
||||
wl = 12.39842 / en
|
||||
d = ubcalc.get_hkl_plane_distance(hkl)
|
||||
if wl > (2 * d):
|
||||
raise ValueError(
|
||||
'Reflection un-reachable as wavelength (%f) is more than twice\n'
|
||||
'the plane distance (%f)' % (wl, d))
|
||||
try:
|
||||
return 2.0 * asin(wl / (d * 2)) * TODEG
|
||||
except ValueError as e:
|
||||
raise ValueError('asin(wl / (d * 2) with wl=%f and d=%f: ' %(wl, d) + e.args[0])
|
||||
|
||||
|
||||
### Surface and reference vector stuff ###
|
||||
|
||||
@command
|
||||
def sigtau(sigma=None, tau=None):
|
||||
"""sigtau {sigma tau} -- sets or displays sigma and tau"""
|
||||
if sigma is None and tau is None:
|
||||
chi = settings.hardware.get_position_by_name('chi') # @UndefinedVariable
|
||||
phi = settings.hardware.get_position_by_name('phi') # @UndefinedVariable
|
||||
_sigma, _tau = ubcalc.sigma, ubcalc.tau
|
||||
print "sigma, tau = %f, %f" % (_sigma, _tau)
|
||||
print " chi, phi = %f, %f" % (chi, phi)
|
||||
sigma = promptForInput("sigma", -chi)
|
||||
tau = promptForInput(" tau", -phi)
|
||||
ubcalc.sigma = sigma
|
||||
ubcalc.tau = tau
|
||||
else:
|
||||
ubcalc.sigma = float(sigma)
|
||||
ubcalc.tau = float(tau)
|
||||
|
||||
|
||||
@command
|
||||
def setnphi(xyz = None):
|
||||
"""setnphi {[x y z]} -- sets or displays n_phi reference"""
|
||||
if xyz is None:
|
||||
ubcalc.print_reference()
|
||||
else:
|
||||
ubcalc.set_n_phi_configured(_to_column_vector_triple(xyz))
|
||||
ubcalc.print_reference()
|
||||
|
||||
@command
|
||||
def setnhkl(hkl):
|
||||
"""setnhkl {[h k l]} -- sets or displays n_hkl reference"""
|
||||
if hkl is None:
|
||||
ubcalc.print_reference()
|
||||
else:
|
||||
ubcalc.set_n_hkl_configured(_to_column_vector_triple(hkl))
|
||||
ubcalc.print_reference()
|
||||
|
||||
|
||||
def _to_column_vector_triple(o):
|
||||
m = matrix(o)
|
||||
if m.shape == (1, 3):
|
||||
return m.T
|
||||
elif m.shape == (3, 1):
|
||||
return m
|
||||
else:
|
||||
raise ValueError("Unexpected shape matrix: " + m)
|
||||
|
||||
### UB refelections ###
|
||||
|
||||
@command
|
||||
def showref():
|
||||
"""showref -- shows full reflection list"""
|
||||
if ubcalc._state.reflist:
|
||||
print '\n'.join(ubcalc._state.reflist.str_lines())
|
||||
else:
|
||||
print "<<< No reflections stored >>>"
|
||||
|
||||
@command
|
||||
def addref(*args):
|
||||
"""
|
||||
addref -- add reflection interactively
|
||||
addref [h k l] {'tag'} -- add reflection with current position and energy
|
||||
addref [h k l] (p1, .., pN) energy {'tag'} -- add arbitrary reflection
|
||||
"""
|
||||
|
||||
if len(args) == 0:
|
||||
h = promptForNumber('h', 0.)
|
||||
k = promptForNumber('k', 0.)
|
||||
l = promptForNumber('l', 0.)
|
||||
if None in (h, k, l):
|
||||
_handleInputError("h,k and l must all be numbers")
|
||||
reply = promptForInput('current pos', 'y')
|
||||
if reply in ('y', 'Y', 'yes'):
|
||||
positionList = settings.hardware.get_position() # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
else:
|
||||
currentPos = settings.hardware.get_position() # @UndefinedVariable
|
||||
positionList = []
|
||||
names = settings.hardware.get_axes_names() # @UndefinedVariable
|
||||
for i, angleName in enumerate(names):
|
||||
val = promptForNumber(angleName.rjust(7), currentPos[i])
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press"
|
||||
" Return to accept default!")
|
||||
return
|
||||
positionList.append(val)
|
||||
energy = promptForNumber('energy', settings.hardware.get_energy()) # @UndefinedVariable
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press "
|
||||
"Return to accept default!")
|
||||
return
|
||||
muliplier = settings.hardware.energyScannableMultiplierToGetKeV # @UndefinedVariable
|
||||
energy = energy * muliplier
|
||||
tag = promptForInput("tag")
|
||||
if tag == '':
|
||||
tag = None
|
||||
pos = settings.geometry.physical_angles_to_internal_position(positionList) # @UndefinedVariable
|
||||
ubcalc.add_reflection(h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
elif len(args) in (1, 2, 3, 4):
|
||||
args = list(args)
|
||||
h, k, l = args.pop(0)
|
||||
if not (isnum(h) and isnum(k) and isnum(l)):
|
||||
raise TypeError()
|
||||
if len(args) >= 2:
|
||||
pos = settings.geometry.physical_angles_to_internal_position( # @UndefinedVariable
|
||||
args.pop(0))
|
||||
energy = args.pop(0)
|
||||
if not isnum(energy):
|
||||
raise TypeError()
|
||||
else:
|
||||
pos = settings.geometry.physical_angles_to_internal_position( # @UndefinedVariable
|
||||
settings.hardware.get_position()) # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
if len(args) == 1:
|
||||
tag = args.pop(0)
|
||||
if not isinstance(tag, str):
|
||||
raise TypeError()
|
||||
else:
|
||||
tag = None
|
||||
ubcalc.add_reflection(h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
@command
|
||||
def editref(num):
|
||||
"""editref num -- interactively edit a reflection.
|
||||
"""
|
||||
num = int(num)
|
||||
|
||||
# Get old reflection values
|
||||
[oldh, oldk, oldl], oldExternalAngles, oldEnergy, oldTag, oldT = \
|
||||
ubcalc.get_reflection_in_external_angles(num)
|
||||
del oldT # current time will be used.
|
||||
|
||||
h = promptForNumber('h', oldh)
|
||||
k = promptForNumber('k', oldk)
|
||||
l = promptForNumber('l', oldl)
|
||||
if None in (h, k, l):
|
||||
_handleInputError("h,k and l must all be numbers")
|
||||
reply = promptForInput('update position with current hardware setting',
|
||||
'n')
|
||||
if reply in ('y', 'Y', 'yes'):
|
||||
positionList = settings.hardware.get_position() # @UndefinedVariable
|
||||
energy = settings.hardware.get_energy() # @UndefinedVariable
|
||||
else:
|
||||
positionList = []
|
||||
names = settings.hardware.get_axes_names() # @UndefinedVariable
|
||||
for i, angleName in enumerate(names):
|
||||
val = promptForNumber(angleName.rjust(7), oldExternalAngles[i])
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press "
|
||||
"Return to accept default!")
|
||||
return
|
||||
positionList.append(val)
|
||||
energy = promptForNumber('energy', oldEnergy)
|
||||
if val is None:
|
||||
_handleInputError("Please enter a number, or press Return "
|
||||
"to accept default!")
|
||||
return
|
||||
energy = energy * settings.hardware.energyScannableMultiplierToGetKeV # @UndefinedVariable
|
||||
tag = promptForInput("tag", oldTag)
|
||||
if tag == '':
|
||||
tag = None
|
||||
pos = settings.geometry.physical_angles_to_internal_position(positionList) # @UndefinedVariable
|
||||
ubcalc.edit_reflection(num, h, k, l, pos, energy, tag,
|
||||
datetime.now())
|
||||
|
||||
@command
|
||||
def delref(num):
|
||||
"""delref num -- deletes a reflection (numbered from 1)
|
||||
"""
|
||||
ubcalc.del_reflection(int(num))
|
||||
|
||||
@command
|
||||
def clearref():
|
||||
"""clearref -- deletes all the reflections
|
||||
"""
|
||||
while ubcalc.get_number_reflections():
|
||||
ubcalc.del_reflection(1)
|
||||
|
||||
@command
|
||||
def swapref(num1=None, num2=None):
|
||||
"""
|
||||
swapref -- swaps first two reflections used for calulating U matrix
|
||||
swapref num1 num2 -- swaps two reflections (numbered from 1)
|
||||
"""
|
||||
if num1 is None and num2 is None:
|
||||
ubcalc.swap_reflections(1, 2)
|
||||
elif isinstance(num1, int) and isinstance(num2, int):
|
||||
ubcalc.swap_reflections(num1, num2)
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
### UB calculations ###
|
||||
|
||||
@command
|
||||
def setu(U=None):
|
||||
"""setu {[[..][..][..]]} -- manually set u matrix
|
||||
"""
|
||||
if U is None:
|
||||
U = _promptFor3x3MatrixDefaultingToIdentity()
|
||||
if U is None:
|
||||
return # an error will have been printed or thrown
|
||||
if _is3x3TupleOrList(U) or _is3x3Matrix(U):
|
||||
ubcalc.set_U_manually(U)
|
||||
else:
|
||||
raise TypeError("U must be given as 3x3 list or tuple")
|
||||
|
||||
@command
|
||||
def setub(UB=None):
|
||||
"""setub {[[..][..][..]]} -- manually set ub matrix"""
|
||||
if UB is None:
|
||||
UB = _promptFor3x3MatrixDefaultingToIdentity()
|
||||
if UB is None:
|
||||
return # an error will have been printed or thrown
|
||||
if _is3x3TupleOrList(UB):
|
||||
ubcalc.set_UB_manually(UB)
|
||||
else:
|
||||
raise TypeError("UB must be given as 3x3 list or tuple")
|
||||
|
||||
def _promptFor3x3MatrixDefaultingToIdentity():
|
||||
estring = "Please enter a number, or press Return to accept default!"
|
||||
row1 = promptForList("row1", (1, 0, 0))
|
||||
if row1 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
row2 = promptForList("row2", (0, 1, 0))
|
||||
if row2 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
row3 = promptForList("row3", (0, 0, 1))
|
||||
if row3 is None:
|
||||
_handleInputError(estring)
|
||||
return None
|
||||
return [row1, row2, row3]
|
||||
|
||||
@command
|
||||
def calcub():
|
||||
"""calcub -- (re)calculate u matrix from ref1 and ref2.
|
||||
"""
|
||||
ubcalc.calculate_UB()
|
||||
|
||||
@command
|
||||
def trialub():
|
||||
"""trialub -- (re)calculate u matrix from ref1 only (check carefully).
|
||||
"""
|
||||
ubcalc.calculate_UB_from_primary_only()
|
||||
|
||||
|
||||
# This command requires the ubcalc
|
||||
|
||||
def checkub():
|
||||
"""checkub -- show calculated and entered hkl values for reflections.
|
||||
"""
|
||||
|
||||
s = "\n %7s %4s %4s %4s %6s %6s %6s TAG\n" % \
|
||||
('ENERGY', 'H', 'K', 'L', 'H_COMP', 'K_COMP', 'L_COMP')
|
||||
s = bold(s)
|
||||
nref = ubcalc.get_number_reflections()
|
||||
if not nref:
|
||||
s += "<<empty>>"
|
||||
for n in range(nref):
|
||||
hklguess, pos, energy, tag, _ = ubcalc.get_reflection(n + 1)
|
||||
wavelength = 12.39842 / energy
|
||||
hkl = settings.angles_to_hkl_function(pos.inRadians(), wavelength, ubcalc.UB)
|
||||
h, k, l = hkl
|
||||
if tag is None:
|
||||
tag = ""
|
||||
s += ("% 2d % 6.4f % 4.2f % 4.2f % 4.2f % 6.4f % 6.4f "
|
||||
"% 6.4f %6s\n" % (n + 1, energy, hklguess[0],
|
||||
hklguess[1], hklguess[2], h, k, l, tag))
|
||||
print s
|
||||
|
||||
|
||||
commands_for_help = ['State',
|
||||
newub,
|
||||
loadub,
|
||||
lastub,
|
||||
listub,
|
||||
rmub,
|
||||
saveubas,
|
||||
ub,
|
||||
'Lattice',
|
||||
setlat,
|
||||
c2th]
|
||||
|
||||
if ubcalc.include_reference:
|
||||
commands_for_help.extend([
|
||||
'Reference (surface)',
|
||||
setnphi,
|
||||
setnhkl])
|
||||
|
||||
if ubcalc.include_sigtau:
|
||||
commands_for_help.extend([
|
||||
'Surface',
|
||||
sigtau])
|
||||
|
||||
commands_for_help.extend([
|
||||
'Reflections',
|
||||
showref,
|
||||
addref,
|
||||
editref,
|
||||
delref,
|
||||
clearref,
|
||||
swapref,
|
||||
'ub matrix',
|
||||
checkub,
|
||||
setu,
|
||||
setub,
|
||||
calcub,
|
||||
trialub])
|
||||
|
||||
|
||||
|
||||
def _is3x3TupleOrList(m):
|
||||
if type(m) not in (list, tuple):
|
||||
return False
|
||||
if len(m) != 3:
|
||||
return False
|
||||
for mrow in m:
|
||||
if type(mrow) not in (list, tuple):
|
||||
return False
|
||||
if len(mrow) != 3:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _is3x3Matrix(m):
|
||||
return isinstance(m, matrix) and tuple(m.shape) == (3, 3)
|
||||
|
||||
|
||||
def _handleInputError(msg):
|
||||
raise TypeError(msg)
|
||||
349
script/__Lib/diffcalc_old/diffcalc/util.py
Normal file
349
script/__Lib/diffcalc_old/diffcalc/util.py
Normal file
@@ -0,0 +1,349 @@
|
||||
###
|
||||
# Copyright 2008-2011 Diamond Light Source Ltd.
|
||||
# This file is part of Diffcalc.
|
||||
#
|
||||
# Diffcalc 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.
|
||||
#
|
||||
# Diffcalc 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 Diffcalc. If not, see <http://www.gnu.org/licenses/>.
|
||||
###
|
||||
|
||||
from math import pi, acos, cos, sin
|
||||
from functools import wraps
|
||||
import textwrap
|
||||
|
||||
try:
|
||||
from gda.jython.commands.InputCommands import requestInput as raw_input
|
||||
GDA = True
|
||||
except ImportError:
|
||||
GDA = False
|
||||
pass # raw_input unavailable in gda
|
||||
try:
|
||||
from numpy import matrix
|
||||
from numpy.linalg import norm
|
||||
except ImportError:
|
||||
from numjy import matrix
|
||||
from numjy.linalg import norm
|
||||
|
||||
|
||||
# from http://physics.nist.gov/
|
||||
h_in_eV_per_s = 4.135667516E-15
|
||||
c = 299792458
|
||||
TWELVEISH = c * h_in_eV_per_s # 12.39842
|
||||
|
||||
|
||||
SMALL = 1e-10
|
||||
TORAD = pi / 180
|
||||
TODEG = 180 / pi
|
||||
|
||||
|
||||
COLOURISE_TERMINAL_OUTPUT = not GDA
|
||||
|
||||
def bold(s):
|
||||
if not COLOURISE_TERMINAL_OUTPUT:
|
||||
return s
|
||||
else:
|
||||
BOLD = '\033[1m'
|
||||
END = '\033[0m'
|
||||
return BOLD + s + END
|
||||
|
||||
|
||||
def x_rotation(th):
|
||||
return matrix(((1, 0, 0), (0, cos(th), -sin(th)), (0, sin(th), cos(th))))
|
||||
|
||||
|
||||
def y_rotation(th):
|
||||
return matrix(((cos(th), 0, sin(th)), (0, 1, 0), (-sin(th), 0, cos(th))))
|
||||
|
||||
|
||||
def z_rotation(th):
|
||||
return matrix(((cos(th), -sin(th), 0), (sin(th), cos(th), 0), (0, 0, 1)))
|
||||
|
||||
|
||||
def xyz_rotation(u, angle):
|
||||
u = [list(u), [0, 0, 0], [0, 0, 0]]
|
||||
u = matrix(u) / norm(matrix(u))
|
||||
e11=u[0,0]**2+(1-u[0,0]**2)*cos(angle)
|
||||
e12=u[0,0]*u[0,1]*(1-cos(angle))-u[0,2]*sin(angle)
|
||||
e13=u[0,0]*u[0,2]*(1-cos(angle))+u[0,1]*sin(angle)
|
||||
e21=u[0,0]*u[0,1]*(1-cos(angle))+u[0,2]*sin(angle)
|
||||
e22=u[0,1]**2+(1-u[0,1]**2)*cos(angle)
|
||||
e23=u[0,1]*u[0,2]*(1-cos(angle))-u[0,0]*sin(angle)
|
||||
e31=u[0,0]*u[0,2]*(1-cos(angle))-u[0,1]*sin(angle)
|
||||
e32=u[0,1]*u[0,2]*(1-cos(angle))+u[0,0]*sin(angle)
|
||||
e33=u[0,2]**2+(1-u[0,2]**2)*cos(angle)
|
||||
return matrix([[e11,e12,e13],[e21,e22,e23],[e31,e32,e33]])
|
||||
|
||||
|
||||
class DiffcalcException(Exception):
|
||||
"""Error caused by user misuse of diffraction calculator.
|
||||
"""
|
||||
def __str__(self):
|
||||
lines = []
|
||||
for msg_line in self.message.split('\n'):
|
||||
lines.append('* ' + msg_line)
|
||||
width = max(len(l) for l in lines)
|
||||
lines.insert(0, '\n\n' + '*' * width)
|
||||
lines.append('*' * width)
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
class AbstractPosition(object):
|
||||
|
||||
def inRadians(self):
|
||||
pos = self.clone()
|
||||
pos.changeToRadians()
|
||||
return pos
|
||||
|
||||
def inDegrees(self):
|
||||
pos = self.clone()
|
||||
pos.changeToDegrees()
|
||||
return pos
|
||||
|
||||
def changeToRadians(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def changeToDegrees(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def totuple(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
### Matrices
|
||||
|
||||
def cross3(x, y):
|
||||
"""z = cross3(x ,y) -- where x, y & z are 3*1 Jama matrices"""
|
||||
[[x1], [x2], [x3]] = x.tolist()
|
||||
[[y1], [y2], [y3]] = y.tolist()
|
||||
return matrix([[x2 * y3 - x3 * y2],
|
||||
[x3 * y1 - x1 * y3],
|
||||
[x1 * y2 - x2 * y1]])
|
||||
|
||||
|
||||
def dot3(x, y):
|
||||
"""z = dot3(x ,y) -- where x, y are 3*1 Jama matrices"""
|
||||
return x[0, 0] * y[0, 0] + x[1, 0] * y[1, 0] + x[2, 0] * y[2, 0]
|
||||
|
||||
|
||||
def angle_between_vectors(a, b):
|
||||
costheta = dot3(a * (1 / norm(a)), b * (1 / norm(b)))
|
||||
return acos(bound(costheta))
|
||||
|
||||
|
||||
## Math
|
||||
|
||||
def bound(x):
|
||||
"""
|
||||
moves x between -1 and 1. Used to correct for rounding errors which may
|
||||
have moved the sin or cosine of a value outside this range.
|
||||
"""
|
||||
|
||||
SMALL = 1e-3 ###GOBBO
|
||||
if abs(x) > (1 + SMALL):
|
||||
raise AssertionError(
|
||||
"The value (%f) was unexpectedly too far outside -1 or 1 to "
|
||||
"safely bound. Please report this." % x)
|
||||
if x > 1:
|
||||
return 1
|
||||
if x < -1:
|
||||
return -1
|
||||
return x
|
||||
|
||||
|
||||
def matrixToString(m):
|
||||
''' str = matrixToString(m) --- displays a Jama matrix m as a string
|
||||
'''
|
||||
toReturn = ''
|
||||
for row in m.array:
|
||||
for el in row:
|
||||
toReturn += str(el) + '\t'
|
||||
toReturn += '\n'
|
||||
return toReturn
|
||||
|
||||
|
||||
def nearlyEqual(first, second, tolerance):
|
||||
if type(first) in (int, float):
|
||||
return abs(first - second) <= tolerance
|
||||
|
||||
if type(first) != type(matrix([[1]])):
|
||||
# lists
|
||||
first = matrix([list(first)])
|
||||
second = matrix([list(second)])
|
||||
diff = first - (second)
|
||||
return norm(diff) <= tolerance
|
||||
|
||||
|
||||
def radiansEquivilant(first, second, tolerance):
|
||||
if abs(first - second) <= tolerance:
|
||||
return True
|
||||
if abs((first - 2 * pi) - second) <= tolerance:
|
||||
return True
|
||||
if abs((first + 2 * pi) - second) <= tolerance:
|
||||
return True
|
||||
if abs(first - (second - 2 * pi)) <= tolerance:
|
||||
return True
|
||||
if abs(first - (second + 2 * pi)) <= tolerance:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def degreesEquivilant(first, second, tolerance):
|
||||
return radiansEquivilant(first * TORAD, second * TORAD, tolerance)
|
||||
|
||||
|
||||
def differ(first, second, tolerance):
|
||||
"""Returns error message if the norm of the difference between two arrays
|
||||
or numbers is greater than the given tolerance. Else returns False.
|
||||
"""
|
||||
# TODO: Fix spaghetti
|
||||
nonArray = False
|
||||
if type(first) in (int, float):
|
||||
if type(second) not in (int, float):
|
||||
raise TypeError(
|
||||
"If first is an int or float, so must second. "
|
||||
"first=%s, second=%s" & (repr(first), repr(second)))
|
||||
first = [first]
|
||||
second = [second]
|
||||
nonArray = True
|
||||
if not isinstance(first, matrix):
|
||||
first = matrix([list(first)])
|
||||
if not isinstance(second, matrix):
|
||||
second = matrix([list(second)])
|
||||
diff = first - second
|
||||
if norm(diff) >= tolerance:
|
||||
if nonArray:
|
||||
return ('%s!=%s' %
|
||||
(repr(first.tolist()[0][0]), repr(second.tolist()[0][0])))
|
||||
return ('%s!=%s' %
|
||||
(repr(tuple(first.tolist()[0])),
|
||||
repr(tuple(second.tolist()[0]))))
|
||||
return False
|
||||
|
||||
|
||||
### user input
|
||||
|
||||
def getInputWithDefault(prompt, default=""):
|
||||
"""
|
||||
Prompts user for input and returns if possible a float or a list of floats,
|
||||
or if failing this a string. default may be a number, array of numbers,
|
||||
or string.
|
||||
"""
|
||||
if default is not "":
|
||||
# Generate default string
|
||||
if type(default) in (list, tuple):
|
||||
defaultString = ""
|
||||
for val in default:
|
||||
defaultString += str(val) + ' '
|
||||
defaultString = defaultString.strip()
|
||||
else:
|
||||
defaultString = str(default)
|
||||
prompt = str(prompt) + '[' + defaultString + ']: '
|
||||
else:
|
||||
prompt = str(prompt) + ': '
|
||||
|
||||
rawresult = raw_input(prompt)
|
||||
|
||||
# Return default if no input provided
|
||||
if rawresult == "":
|
||||
return default
|
||||
|
||||
# Try to process result into list of numbers
|
||||
try:
|
||||
result = []
|
||||
for val in rawresult.split():
|
||||
result.append(float(val))
|
||||
except ValueError:
|
||||
# return a string
|
||||
return rawresult
|
||||
if len(result) == 1:
|
||||
result = result[0]
|
||||
return result
|
||||
|
||||
|
||||
class MockRawInput(object):
|
||||
def __init__(self, toReturnList):
|
||||
if type(toReturnList) != list:
|
||||
toReturnList = [toReturnList]
|
||||
self.toReturnList = toReturnList
|
||||
|
||||
def __call__(self, prompt):
|
||||
toReturn = self.toReturnList.pop(0)
|
||||
if type(toReturn) != str:
|
||||
raise TypeError
|
||||
print prompt + toReturn
|
||||
return toReturn
|
||||
|
||||
|
||||
def getMessageFromException(e):
|
||||
try: # Jython
|
||||
return e.args[0]
|
||||
except:
|
||||
try: # Python
|
||||
return e.message
|
||||
except:
|
||||
# Java
|
||||
return e.args[0]
|
||||
|
||||
|
||||
def promptForNumber(prompt, default=""):
|
||||
val = getInputWithDefault(prompt, default)
|
||||
if type(val) not in (float, int):
|
||||
return None
|
||||
return val
|
||||
|
||||
|
||||
def promptForList(prompt, default=""):
|
||||
val = getInputWithDefault(prompt, default)
|
||||
if type(val) not in (list, tuple):
|
||||
return None
|
||||
return val
|
||||
|
||||
|
||||
def isnum(o):
|
||||
return isinstance(o, (int, float))
|
||||
|
||||
|
||||
def allnum(l):
|
||||
return not [o for o in l if not isnum(o)]
|
||||
|
||||
|
||||
DEBUG = False
|
||||
|
||||
|
||||
|
||||
def command(f):
|
||||
"""A decorator to wrap a command method or function.
|
||||
|
||||
Calls to the decorated method or function are wrapped by call_command.
|
||||
"""
|
||||
# TODO: remove one level of stack trace by not using wraps
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwds):
|
||||
return call_command(f, args)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def call_command(f, args):
|
||||
|
||||
if DEBUG:
|
||||
return f(*args)
|
||||
try:
|
||||
return f(*args)
|
||||
except TypeError:
|
||||
# NOTE: TypeErrors resulting from bugs in the core code will be
|
||||
# erroneously caught here! TODO: check depth of TypeError stack
|
||||
raise TypeError('\n\nUSAGE:\n' + f.__doc__)
|
||||
except DiffcalcException, e:
|
||||
# TODO: log and create a new one to shorten stack trace for user
|
||||
raise DiffcalcException(e.message)
|
||||
0
script/__Lib/diffcalc_old/diffcmd/__init__.py
Normal file
0
script/__Lib/diffcalc_old/diffcmd/__init__.py
Normal file
86
script/__Lib/diffcalc_old/diffcmd/diffcalc_launcher.py
Executable file
86
script/__Lib/diffcalc_old/diffcmd/diffcalc_launcher.py
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import os
|
||||
import getpass
|
||||
|
||||
DIFFCALC_BIN = os.path.split(os.path.realpath(__file__))[0]
|
||||
DIFFCALC_ROOT = os.path.abspath(os.path.join(DIFFCALC_BIN, os.pardir))
|
||||
|
||||
MODULE_FOR_MANUALS = '_make_sixcircle_manual'
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Diffcalc: A diffraction condition calculator of x-ray and neutron crystalography')
|
||||
parser.add_argument('--modules', dest='show_modules', action='store_true',
|
||||
help='list available modules')
|
||||
parser.add_argument('--python', dest='use_python', action='store_true',
|
||||
help='run within python rather than ipython')
|
||||
parser.add_argument('--debug', dest='debug', action='store_true',
|
||||
help='run in debug mode')
|
||||
parser.add_argument('--make-manuals-source', dest='make_manuals', action='store_true',
|
||||
help='make .rst manual files by running template through sixcircle')
|
||||
parser.add_argument('--non-interactive', dest='non_interactive', action='store_true',
|
||||
help='do not enter interactive mode after startup')
|
||||
parser.add_argument('module', type=str, nargs='?',
|
||||
help='the module to startup with')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create list of available modules
|
||||
module_names = []
|
||||
for module_path in os.listdir(os.path.join(DIFFCALC_ROOT, 'startup')):
|
||||
if not module_path.startswith('_') and module_path.endswith('.py'):
|
||||
module_names.append(module_path.split('.')[0])
|
||||
module_names.sort()
|
||||
|
||||
if args.show_modules:
|
||||
print_available_modules(module_names)
|
||||
exit(0)
|
||||
|
||||
if not args.make_manuals and not args.module:
|
||||
print "A module name should be provided. Choose one of:"
|
||||
print_available_modules(module_names)
|
||||
exit(0)
|
||||
|
||||
if args.make_manuals:
|
||||
if args.module:
|
||||
print "When building the manuals no module should be given"
|
||||
exit(1)
|
||||
args.module = MODULE_FOR_MANUALS
|
||||
|
||||
if not args.make_manuals and args.module not in module_names:
|
||||
print "The provided argument '%s' is not one of:" % args.module
|
||||
print_available_modules(module_names)
|
||||
exit(1)
|
||||
|
||||
env = os.environ.copy()
|
||||
|
||||
if 'PYTHONPATH' not in env:
|
||||
env['PYTHONPATH'] = ''
|
||||
env['PYTHONPATH'] = DIFFCALC_ROOT + ':' + env['PYTHONPATH']
|
||||
|
||||
diffcmd_start_path = os.path.join(DIFFCALC_ROOT, 'diffcmd', 'start.py')
|
||||
|
||||
if args.use_python:
|
||||
cmd = 'python'
|
||||
else: # ipython
|
||||
cmd = 'ipython --no-banner --HistoryManager.hist_file=/tmp/ipython_hist_%s.sqlite' % getpass.getuser()
|
||||
|
||||
iflag = '' if args.non_interactive else '-i'
|
||||
cmd = cmd + ' ' + ' '.join([iflag, diffcmd_start_path, args.module, str(args.debug)])
|
||||
|
||||
print 'Running: ' + cmd
|
||||
rc = subprocess.call(cmd, env=env, shell=True)
|
||||
exit(rc)
|
||||
|
||||
|
||||
def print_available_modules(module_names):
|
||||
lines = []
|
||||
for m in sorted(module_names):
|
||||
lines.append(' ' + m)
|
||||
print '\n'.join(lines)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
#
|
||||
43
script/__Lib/diffcalc_old/diffcmd/diffcmd_utils.py
Normal file
43
script/__Lib/diffcalc_old/diffcmd/diffcmd_utils.py
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# General utility functions to handle Diffcalc commands
|
||||
#
|
||||
|
||||
from gda.jython.commands.GeneralCommands import alias
|
||||
|
||||
try:
|
||||
import gda
|
||||
GDA = True
|
||||
except ImportError:
|
||||
GDA = False
|
||||
|
||||
|
||||
|
||||
def alias_commands(global_namespace_dict):
|
||||
"""Alias commands left in global_namespace_dict by previous import from
|
||||
diffcalc.
|
||||
|
||||
This is the equivalent of diffcmd/ipython/magic_commands() for use
|
||||
when IPython is not available
|
||||
"""
|
||||
gnd = global_namespace_dict
|
||||
global GLOBAL_NAMESPACE_DICT
|
||||
GLOBAL_NAMESPACE_DICT = gnd
|
||||
print "Aliasing commands"
|
||||
|
||||
### Alias commands in namespace ###
|
||||
commands = gnd['hkl_commands_for_help']
|
||||
commands += gnd['ub_commands_for_help']
|
||||
if not GDA: # TODO: encapsulation issue: this should be done outside this function!
|
||||
commands.append(gnd['pos'])
|
||||
commands.append(gnd['scan'])
|
||||
aliased_names = []
|
||||
|
||||
for f in commands:
|
||||
# Skip section headers like 'Motion'
|
||||
if not hasattr(f, '__call__'):
|
||||
continue
|
||||
|
||||
alias(f.__name__)
|
||||
aliased_names.append(f.__name__)
|
||||
|
||||
print "Aliased commands: " + ' '.join(aliased_names)
|
||||
302
script/__Lib/diffcalc_old/diffcmd/ipython.py
Normal file
302
script/__Lib/diffcalc_old/diffcmd/ipython.py
Normal file
@@ -0,0 +1,302 @@
|
||||
import re
|
||||
from functools import wraps
|
||||
from IPython.core.magic import register_line_magic
|
||||
from IPython import get_ipython # @UnusedImport (used by register_line_magic)
|
||||
from diffcalc.gdasupport.scannable.hkl import Hkl
|
||||
|
||||
"""
|
||||
For wrapping functions:
|
||||
|
||||
In [1]: import diffcmd.ipython
|
||||
|
||||
In [2]: diffcmd.ipython.GLOBAL_NAMESPACE_DICT = globals()
|
||||
|
||||
In [3]: from IPython.core.magic import register_line_magic
|
||||
|
||||
In [4]: from diffcmd.ipython import parse_line
|
||||
|
||||
In [5]: @register_line_magic
|
||||
...: @parse_line
|
||||
...: def check_parser(*args):
|
||||
...: return args
|
||||
...:
|
||||
|
||||
In [6]: check_parser
|
||||
Out[6]: <function __main__.check_parser>
|
||||
|
||||
In [7]: del check_parser
|
||||
|
||||
In [8]: check_parser
|
||||
Out[8]: ()
|
||||
|
||||
In [9]: check_parser 1
|
||||
Out[9]: (1,)
|
||||
|
||||
In [10]: check_parser 1 2
|
||||
Out[10]: (1, 2)
|
||||
|
||||
In [11]: check_parser 1 2 [3]
|
||||
Out[11]: (1, 2, [3])
|
||||
|
||||
In [12]: b='bbb'
|
||||
|
||||
In [13]: check_parser 1 2 [3] b
|
||||
Out[13]: (1, 2, [3], 'bbb')
|
||||
|
||||
|
||||
And to create something dynamically from a function:
|
||||
|
||||
In [28]: def f(a, b, c):
|
||||
....: ....: return a, b, c
|
||||
....:
|
||||
|
||||
In [29]: register_line_magic(parse_line(f))
|
||||
Out[29]: <function __main__.f>
|
||||
|
||||
In [30]: del f
|
||||
|
||||
In [31]: f 'a' -2 [1 3 -4]
|
||||
Out[31]: ('a', -2, [1, 3, -4])
|
||||
|
||||
And from a list of functions:
|
||||
|
||||
In [32]: def one(a):
|
||||
....: return a
|
||||
....:
|
||||
|
||||
In [33]: def two(a, b):
|
||||
....: return a, b
|
||||
....:
|
||||
|
||||
In [34]: functions = one, two
|
||||
|
||||
In [35]: del one, two
|
||||
|
||||
In [36]: for f in functions:
|
||||
....: register_line_magic(parse_line(f))
|
||||
....:
|
||||
|
||||
In [37]: one 1
|
||||
Out[37]: 1
|
||||
|
||||
In [39]: two 1 2
|
||||
Out[39]: (1, 2)
|
||||
|
||||
And to check if we are running in iPython:
|
||||
|
||||
In [47]: 'get_ipython' in globals()
|
||||
Out[47]: True
|
||||
|
||||
def in_ipython():
|
||||
try:
|
||||
get_ipython()
|
||||
return True
|
||||
except NameError:
|
||||
return False
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
GLOBAL_NAMESPACE_DICT = {}
|
||||
|
||||
MATH_OPERATORS = set(['-', '+', '/', '*'])
|
||||
|
||||
# Keep a copy of python's original help as we may remove it later
|
||||
if 'help' in __builtins__:
|
||||
ORIGINAL_PYTHON_HELP = __builtins__['help']
|
||||
|
||||
|
||||
COMMA_USAGE_HELP = \
|
||||
'''
|
||||
| When calling a function without brackets, whitespace must be used in
|
||||
| place of commas. For example:
|
||||
|
|
||||
| >>> function a b [1 2 3] 'c'
|
||||
|
|
||||
| is equivalent to:
|
||||
|
|
||||
| >>> function(a, b, [1, 2, 3], 'c')
|
||||
|
|
||||
'''
|
||||
|
||||
|
||||
MATH_OPERATOR_USAGE_HELP = \
|
||||
'''
|
||||
| When calling a function without brackets, whitespace is used in place of
|
||||
| commas. Therefore terms which require evaluation must contain no space.
|
||||
| These will fail for example:
|
||||
|
|
||||
| >>> function - 1
|
||||
| >>> function a() * 2
|
||||
|
||||
| But this
|
||||
|
||||
| >>> function -1 1-1 +1 a()+1 [-1 0+1 b()] c+1
|
||||
|
|
||||
| is okay and equivalent to:
|
||||
|
|
||||
| >>> function(-1, 0, 1, a() + 1, [-1, 1, b()], c + 1)
|
||||
|
|
||||
|
||||
'''
|
||||
|
||||
comma_finder = re.compile(r'''((?:[^,"']|"[^"]*"|'[^']*')+)''')
|
||||
space_finder = re.compile(r'''((?:[^ "']|"[^"]*"|'[^']*')+)''')
|
||||
hash_finder = re.compile(r'''((?:[^#"']|"[^"]*"|'[^']*')+)''')
|
||||
open_square_finder = re.compile(r'''((?:[^["']|"[^"]*"|'[^']*')+)''')
|
||||
close_square_finder = re.compile(r'''((?:[^]"']|"[^"]*"|'[^']*')+)''')
|
||||
|
||||
def tokenify(s):
|
||||
|
||||
# Don't accept commas outside strings.
|
||||
# Users are frustrated by not knowing when commas _are_ required.
|
||||
# Making it clear when they are not helps them understand the
|
||||
# difference.
|
||||
|
||||
if ',' in comma_finder.split(s):
|
||||
print COMMA_USAGE_HELP
|
||||
print "(string was: %s)" % s
|
||||
raise SyntaxError('unexpected comma')
|
||||
|
||||
# ignore comment
|
||||
hash_split = hash_finder.split(s)
|
||||
if '#' in hash_split:
|
||||
s = '' if hash_split[0] == '#' else hash_split[1]
|
||||
|
||||
# surround square brackets with spaces to simplify token extraction
|
||||
s = ''.join(' [ ' if e == '[' else e for e in open_square_finder.split(s))
|
||||
s = ''.join(' ] ' if e == ']' else e for e in close_square_finder.split(s))
|
||||
|
||||
|
||||
# tokens are now separated by spaces
|
||||
|
||||
tokens = space_finder.split(s)[1::2]
|
||||
tokens = [tok for tok in tokens if tok != '']
|
||||
return tokens
|
||||
|
||||
|
||||
def parse(s, d):
|
||||
s = str(s)
|
||||
tokens = tokenify(s)
|
||||
for tok in tokens:
|
||||
if tok in MATH_OPERATORS:
|
||||
print MATH_OPERATOR_USAGE_HELP
|
||||
raise SyntaxError('could not evaluate: "%s"' % tok)
|
||||
|
||||
|
||||
s = ', '.join(tokens)
|
||||
|
||||
s = s.replace('[, ', '[')
|
||||
s = s.replace(',]', ']')
|
||||
s = s.replace(', ]', ']')
|
||||
|
||||
try:
|
||||
args = eval('[' + s + ']', d)
|
||||
except SyntaxError:
|
||||
raise SyntaxError('could not evaluate: "%s"' % s)
|
||||
return args
|
||||
|
||||
def parse_line(f, global_namespace_dict=None):
|
||||
'''A decorator that parses a single string argument into a list of arguments
|
||||
and calls the wrapped function with these.
|
||||
'''
|
||||
if not global_namespace_dict:
|
||||
global_namespace_dict = GLOBAL_NAMESPACE_DICT
|
||||
@wraps(f)
|
||||
def wrapper(line):
|
||||
args = parse(line, global_namespace_dict)
|
||||
return f(*args)
|
||||
return wrapper
|
||||
|
||||
|
||||
|
||||
_DEFAULT_HELP = \
|
||||
"""
|
||||
For help with diffcalc's orientation phase try:
|
||||
|
||||
>>> help ub
|
||||
|
||||
For help with moving in reciprocal lattice space try:
|
||||
|
||||
>>> help hkl
|
||||
|
||||
For more detailed help try for example:
|
||||
|
||||
>>> help newub
|
||||
|
||||
For help with driving axes or scanning:
|
||||
|
||||
>>> help pos
|
||||
>>> help scan
|
||||
|
||||
For help with regular python try for example:
|
||||
|
||||
>>> help list
|
||||
|
||||
For more detailed help with diffcalc go to:
|
||||
|
||||
https://diffcalc.readthedocs.io
|
||||
|
||||
"""
|
||||
|
||||
def magic_commands(global_namespace_dict):
|
||||
"""Magic commands left in global_namespace_dict by previous import from
|
||||
diffcalc.
|
||||
|
||||
Also creates a help command. NOTE that calling this will
|
||||
remove the original commands from the global namespace as otherwise these
|
||||
would shadow the ipython magiced versions.
|
||||
|
||||
Depends on hkl_commands_for_help & ub_commands_for_help list having been
|
||||
left in the global namespace and assumes there is pos and scan command.
|
||||
"""
|
||||
gnd = global_namespace_dict
|
||||
global GLOBAL_NAMESPACE_DICT
|
||||
GLOBAL_NAMESPACE_DICT = gnd
|
||||
|
||||
### Magic commands in namespace ###
|
||||
commands = list(gnd['hkl_commands_for_help'])
|
||||
commands += gnd['ub_commands_for_help']
|
||||
commands.append(gnd['pos'])
|
||||
commands.append(gnd['scan'])
|
||||
command_map = {}
|
||||
for f in commands:
|
||||
# Skip section headers like 'Motion'
|
||||
if not hasattr(f, '__call__'):
|
||||
continue
|
||||
# magic the function and remove from namespace (otherwise it would
|
||||
# shadow the magiced command)
|
||||
register_line_magic(parse_line(f, gnd))
|
||||
del gnd[f.__name__]
|
||||
command_map[f.__name__] = f
|
||||
|
||||
### Create help function ###
|
||||
#Expects python's original help to be named pythons_help and to be
|
||||
#available in the top-level global namespace (where non-diffcalc
|
||||
#objects may have help called from).
|
||||
def help(s): # @ReservedAssignment
|
||||
"""Diffcalc help for iPython
|
||||
"""
|
||||
if s == '':
|
||||
print _DEFAULT_HELP
|
||||
elif s == 'hkl':
|
||||
# Use help injected into hkl object
|
||||
print Hkl.dynamic_docstring
|
||||
elif s == 'ub':
|
||||
# Use help injected into ub command
|
||||
print command_map['ub'].__doc__
|
||||
elif s in command_map:
|
||||
print "%s (diffcalc command):" %s
|
||||
print command_map[s].__doc__
|
||||
else:
|
||||
exec('pythons_help(%s)' %s, gnd)
|
||||
|
||||
|
||||
### Setup help command ###
|
||||
gnd['pythons_help'] = ORIGINAL_PYTHON_HELP
|
||||
register_line_magic(help)
|
||||
# Remove builtin help
|
||||
# (otherwise it would shadow magiced command
|
||||
if 'help' in __builtins__:
|
||||
del __builtins__['help']
|
||||
79
script/__Lib/diffcalc_old/diffcmd/ipythonmagic.py
Normal file
79
script/__Lib/diffcalc_old/diffcmd/ipythonmagic.py
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
import diffcmd.ipython
|
||||
from IPython.core.magic import register_line_magic
|
||||
from diffcmd.ipython import parse_line
|
||||
|
||||
command_map = {}
|
||||
|
||||
_DEFAULT_HELP = """
|
||||
For help with diffcalc's orientation phase try:
|
||||
|
||||
>>> help ub
|
||||
|
||||
For help with moving in reciprocal lattice space try:
|
||||
|
||||
>>> help hkl
|
||||
|
||||
For more detailed help try for example:
|
||||
|
||||
>>> help newub
|
||||
|
||||
For help with driving axes or scanning:
|
||||
|
||||
>>> help pos
|
||||
>>> help scan
|
||||
|
||||
For help with regular python try for example:
|
||||
|
||||
>>> help list
|
||||
|
||||
For more detailed help with diffcalc go to:
|
||||
|
||||
https://diffcalc.readthedocs.io
|
||||
|
||||
"""
|
||||
|
||||
# This function should be called with parameter globals()
|
||||
def define_commands(dictionary):
|
||||
print "Ipython detected - magicing commands"
|
||||
magiced_names = []
|
||||
commands = hkl_commands_for_help + ub_commands_for_help # @UndefinedVariable
|
||||
commands += [pos, scan] # @UndefinedVariable
|
||||
ipython.GLOBAL_NAMESPACE_DICT = dictionary
|
||||
for f in commands:
|
||||
# Skip section headers like 'Motion'
|
||||
if not hasattr(f, '__call__'):
|
||||
continue
|
||||
|
||||
# magic the function and remove from namespace (otherwise it would
|
||||
# shadow the magiced command)
|
||||
register_line_magic(parse_line(f))
|
||||
del dictionary[f.__name__]
|
||||
command_map[f.__name__] = f
|
||||
magiced_names.append(f.__name__)
|
||||
|
||||
print "Magiced commands: " + ' '.join(magiced_names)
|
||||
|
||||
# because the functions have gone from namespace we need to override
|
||||
pythons_help = __builtins__.help
|
||||
del __builtins__.help
|
||||
|
||||
register_line_magic(help)
|
||||
del help
|
||||
|
||||
def help(s):
|
||||
"""Diffcalc help for iPython
|
||||
"""
|
||||
if s == '':
|
||||
print _DEFAULT_HELP
|
||||
elif s == 'hkl':
|
||||
# Use help injected into hkl object
|
||||
print hkl.__doc__
|
||||
elif s == 'ub':
|
||||
# Use help injected into ub command
|
||||
print command_map['ub'].__doc__
|
||||
elif s in command_map:
|
||||
print "%s (diffcalc command):" %s
|
||||
print command_map[s].__doc__
|
||||
else:
|
||||
exec('pythons_help(%s)' %s)
|
||||
146
script/__Lib/diffcalc_old/diffcmd/make_manual.py
Normal file
146
script/__Lib/diffcalc_old/diffcmd/make_manual.py
Normal file
@@ -0,0 +1,146 @@
|
||||
|
||||
|
||||
from StringIO import StringIO
|
||||
from IPython import get_ipython
|
||||
import sys
|
||||
from diffcalc.dc.help import format_commands_for_rst_table
|
||||
|
||||
|
||||
TEST_INPUT="""
|
||||
Diffcalc's Scannables
|
||||
=====================
|
||||
|
||||
Please see :ref:`moving-in-hkl-space` and :ref:`scanning-in-hkl-space` for some relevant examples.
|
||||
|
||||
To list and show the current positions of your beamline's scannables
|
||||
use ``pos`` with no arguments::
|
||||
|
||||
>>> pos wl
|
||||
|
||||
should do nought, but this should be replaced::
|
||||
|
||||
==> pos wl 2
|
||||
|
||||
should do the thing
|
||||
|
||||
==> abcd
|
||||
"""
|
||||
|
||||
|
||||
|
||||
def echorun(magic_cmd):
|
||||
print "\n>>> " + str(magic_cmd)
|
||||
|
||||
|
||||
|
||||
def make_manual(input_file_path,
|
||||
output_file_path,
|
||||
ub_commands_for_help,
|
||||
hkl_commands_for_help):
|
||||
|
||||
# Read input file (should be .rst file)
|
||||
with open(input_file_path, 'r') as f:
|
||||
input_string = f.read()
|
||||
|
||||
# Parse input string
|
||||
output_lines = []
|
||||
for lineno, line in enumerate(input_string.split('\n')):
|
||||
process = '==>' in line
|
||||
|
||||
if process and 'STOP' in line:
|
||||
print "'==> STOP' found on line. STOPPING", lineno + 1
|
||||
return
|
||||
|
||||
elif process and 'UB_HELP_TABLE' in line:
|
||||
print 'Creating UB help table'
|
||||
output_lines_from_line = format_commands_for_rst_table(
|
||||
'', ub_commands_for_help)
|
||||
|
||||
elif process and 'HKL_HELP_TABLE' in line:
|
||||
print 'Creating HKL help table'
|
||||
output_lines_from_line = format_commands_for_rst_table(
|
||||
'', hkl_commands_for_help)
|
||||
|
||||
else:
|
||||
output_lines_from_line = parse_line(
|
||||
line, lineno + 1, input_file_path)
|
||||
|
||||
# print '\n'.join(output_lines_from_line)
|
||||
output_lines.extend(output_lines_from_line)
|
||||
|
||||
# Write output file
|
||||
if output_file_path:
|
||||
with open(output_file_path, 'w') as f:
|
||||
f.write('\n'.join(output_lines))
|
||||
print "Wrote file:", output_file_path
|
||||
# try:
|
||||
# if output_file_path:
|
||||
# orig_stdout = sys.stdout
|
||||
# f = file(output_file_path, 'w')
|
||||
# sys.stdout = f
|
||||
#
|
||||
#
|
||||
#
|
||||
# finally:
|
||||
# if output_file_path:
|
||||
# sys.stdout = orig_stdout
|
||||
# f.close()
|
||||
|
||||
|
||||
def parse_line(linein, lineno, filepath):
|
||||
output_lines = []
|
||||
if '==>' in linein:
|
||||
pre, cmd = linein.split('==>')
|
||||
_check_spaces_only(pre, lineno, filepath)
|
||||
cmd = cmd.strip() # strip whitespace
|
||||
output_lines.append(pre + ">>> " + cmd)
|
||||
result_lines = _capture_magic_command_output(cmd, lineno, filepath)
|
||||
|
||||
|
||||
# append to output
|
||||
for line in result_lines:
|
||||
output_lines.append(pre + line)
|
||||
else:
|
||||
output_lines.append(linein)
|
||||
return output_lines
|
||||
|
||||
|
||||
def _check_spaces_only(s, lineno, filepath):
|
||||
for c in s:
|
||||
if c != ' ':
|
||||
raise Exception('Error on line %i of %s :\n text proceeding --> must be '
|
||||
'spaces only' % (lineno, filepath))
|
||||
|
||||
def _capture_magic_command_output(magic_cmd, lineno, filepath):
|
||||
orig_stdout = sys.stdout
|
||||
result = StringIO()
|
||||
sys.stdout = result
|
||||
|
||||
def log_error():
|
||||
msg = "Error on line %i of %s evaluating '%s'" % (lineno, filepath, magic_cmd)
|
||||
sys.stderr.write('\n' + '=' * 79 + '\n' + msg + '\n' +'v' * 79 + '\n')
|
||||
return msg
|
||||
|
||||
try:
|
||||
line_magics = get_ipython().magics_manager.magics['line']
|
||||
magic = magic_cmd.split(' ')[0]
|
||||
if magic not in line_magics:
|
||||
msg = log_error()
|
||||
raise Exception(msg + " ('%s' is not a magic command)" % magic)
|
||||
get_ipython().magic(magic_cmd)
|
||||
except:
|
||||
log_error()
|
||||
raise
|
||||
finally:
|
||||
sys.stdout = orig_stdout
|
||||
|
||||
result_lines = result.getvalue().split('\n')
|
||||
|
||||
# trim trailing lines which are whitespace only
|
||||
while result_lines and (result_lines[-1].isspace() or not result_lines[-1]):
|
||||
result_lines.pop()
|
||||
|
||||
return result_lines
|
||||
|
||||
|
||||
|
||||
87
script/__Lib/diffcalc_old/diffcmd/start.py
Normal file
87
script/__Lib/diffcalc_old/diffcmd/start.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
start the diffcmd environemt using a script from startup.
|
||||
This should normally be run by the main diffcalc.py program.
|
||||
|
||||
with diffcalc on PYTHONPATH
|
||||
$ ipython -i -m diffcm.diffcmd module_name_string debug_bool
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import diffcalc
|
||||
import diffcalc.settings
|
||||
import os
|
||||
import sys
|
||||
from diffcalc.ub.persistence import UBCalculationJSONPersister
|
||||
from diffcalc.util import bold
|
||||
import diffcalc.util
|
||||
import diffcalc.gdasupport.minigda.command
|
||||
DIFFCALC_ROOT = os.path.realpath(diffcalc.__file__).split('diffcalc/__init__.py')[0]
|
||||
|
||||
try:
|
||||
__IPYTHON__ # @UndefinedVariable
|
||||
IPYTHON = True
|
||||
except NameError:
|
||||
IPYTHON = False
|
||||
|
||||
|
||||
module_name = sys.argv[1] #3 if IPYTHON else 1]
|
||||
debug = sys.argv[2] == 'True' #4 if IPYTHON else 2])
|
||||
|
||||
print
|
||||
print bold('-' * 34 + ' DIFFCALC ' + '-' * 35)
|
||||
|
||||
# configure persisentence
|
||||
DIFFCALC_VAR = os.path.join(os.path.expanduser('~'), '.diffcalc', module_name)
|
||||
if not os.path.exists(DIFFCALC_VAR):
|
||||
print "Making diffcalc var folder:'%s'" % DIFFCALC_VAR
|
||||
os.makedirs(DIFFCALC_VAR)
|
||||
diffcalc.settings.ubcalc_persister = UBCalculationJSONPersister(DIFFCALC_VAR)
|
||||
|
||||
# configure debug
|
||||
diffcalc.util.DEBUG = debug
|
||||
if debug:
|
||||
print "WARNING: debug mode on; help for command syntax errors disabled."
|
||||
|
||||
# import script
|
||||
script = os.path.join(DIFFCALC_ROOT, 'startup', module_name) + '.py'
|
||||
|
||||
print "Startup script: '%s'" % script
|
||||
namespace = {}
|
||||
execfile(script, namespace)
|
||||
globals().update(namespace)
|
||||
diffcalc.gdasupport.minigda.command.ROOT_NAMESPACE_DICT = dict(namespace)
|
||||
print bold('-' * 36 + ' Help ' + '-' * 37)
|
||||
print HELP_STRING # @UndefinedVariable
|
||||
if 'LOCAL_MANUAL' in locals():
|
||||
print "Local: " + LOCAL_MANUAL # @UndefinedVariable
|
||||
print bold('-' * 79)
|
||||
print
|
||||
|
||||
|
||||
# magic commands if IPython
|
||||
if IPYTHON:
|
||||
from diffcmd.ipython import magic_commands
|
||||
magic_commands(globals())
|
||||
|
||||
|
||||
if 'MANUALS_TO_MAKE' in locals():
|
||||
summary_lines = ['Made manuals:']
|
||||
from diffcmd.make_manual import make_manual
|
||||
for source_path in MANUALS_TO_MAKE: # @UndefinedVariable
|
||||
import diffcalc.ub.ub
|
||||
try:
|
||||
diffcalc.ub.ub.rmub('example')
|
||||
except KeyError:
|
||||
pass
|
||||
target_path = source_path.replace('_template', '')
|
||||
print '@' * 79
|
||||
print "Making manual"
|
||||
print " Source:", source_path
|
||||
print " Target:", target_path
|
||||
|
||||
make_manual(source_path, target_path,
|
||||
ub_commands_for_help, # @UndefinedVariable
|
||||
hkl_commands_for_help) # @UndefinedVariable
|
||||
summary_lines.append(' - ' + source_path + ' -- > ' + target_path)
|
||||
print '\n'.join(summary_lines)
|
||||
|
||||
24
script/__Lib/diffcalc_old/doc/ACKS_diffcalc.rst
Normal file
24
script/__Lib/diffcalc_old/doc/ACKS_diffcalc.rst
Normal file
@@ -0,0 +1,24 @@
|
||||
I would like to acknowledge the people who have made a direct impact on the
|
||||
Diffcalc project, knowingly or not, in terms of encouragement, suggestions,
|
||||
criticism, bug reports, code contributions, and related projects.
|
||||
|
||||
Names are ordered alphabetically by surname.
|
||||
|
||||
.. If you add new entries, keep the list sorted by surname!
|
||||
|
||||
.. acks::
|
||||
|
||||
* Allesandro Bombardi
|
||||
* Mark Booth
|
||||
* W. R. Busing
|
||||
* Steve Collins
|
||||
* H. A. Levy
|
||||
* Martin Lohmier
|
||||
* Chris Nicklin
|
||||
* Elias Vlieg --- writer of DIF software used as a model for Diffcalc
|
||||
* Robert Walton
|
||||
* H. You
|
||||
|
||||
Thank you!
|
||||
|
||||
Rob Walton
|
||||
193
script/__Lib/diffcalc_old/doc/Makefile
Normal file
193
script/__Lib/diffcalc_old/doc/Makefile
Normal file
@@ -0,0 +1,193 @@
|
||||
# Makefile for documentation
|
||||
# This makefile is a modified version of the makefile generated by the sphinx-quickstart command
|
||||
|
||||
# set environment for Diamond Light Source
|
||||
ifeq ($(CONTEXT),diamond)
|
||||
@echo "Environment variable CONTEXT=diamond, so setting build environment suitable for Diamond Light Source"
|
||||
# get the location of a Python that has Sphinx installed
|
||||
SPHINXBUILD?=$(shell module load python/2.7.2;which sphinx-build)
|
||||
# set http proxy
|
||||
export http_proxy?=http://wwwcache.rl.ac.uk:8080
|
||||
export https_proxy?=https://wwwcache.rl.ac.uk:8080
|
||||
endif
|
||||
|
||||
# optionally use Sphinx's "-W" options, which converts warnings into errors
|
||||
ifeq ($(HALTONWARNING),y)
|
||||
SPHINXEXTRAOPT=-W
|
||||
else ifeq ($(HALTONWARNING),Y)
|
||||
SPHINXEXTRAOPT=-W
|
||||
else
|
||||
SPHINXEXTRAOPT=
|
||||
endif
|
||||
|
||||
### <-- start of Makefile contents generated by sphinx-quickstart --> ###
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
PAPER ?=
|
||||
BUILDDIR ?= build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXEXTRAOPT) $(SPHINXOPTS) source
|
||||
|
||||
.PHONY: help helpfull pwd clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest pdfa4 pdfletter pdf all
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " pdf to create pdf files for both A4- and Letter-sized paper"
|
||||
@echo " pdfa4 to create pdf files for A4-sized paper"
|
||||
@echo " pdfletter to create pdf files for Letter-sized paper"
|
||||
@echo " all to build html and pdf"
|
||||
@echo " clean to wipe the build directory"
|
||||
@echo
|
||||
@echo "You can use \`make helpfull' to get a full list of targets (not all have been tested)"
|
||||
|
||||
helpfull:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
pwd:
|
||||
@echo
|
||||
@echo "*******************************************************************************************************"
|
||||
@echo "Current directory = "`pwd`
|
||||
@echo "*******************************************************************************************************"
|
||||
|
||||
clean: pwd
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html: pwd
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GDA.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GDA.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/GDA"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GDA"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex: pwd
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf: pwd
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
make -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
### <-- end of Makefile contents generated by sphinx-quickstart --> ###
|
||||
|
||||
pdfa4: pwd
|
||||
rm -rf $(BUILDDIR)/latex
|
||||
rm -rf $(BUILDDIR)/pdf-a4
|
||||
make latexpdf PAPER=a4
|
||||
mkdir $(BUILDDIR)/pdf-a4/
|
||||
cp $(BUILDDIR)/latex/*.pdf $(BUILDDIR)/pdf-a4/.
|
||||
@echo
|
||||
@echo "Build finished for A4-sized PDFs. The PDF files are in $(BUILDDIR)/pdf-a4."
|
||||
|
||||
pdfletter: pwd
|
||||
rm -rf $(BUILDDIR)/latex
|
||||
rm -rf $(BUILDDIR)/pdf-letter
|
||||
make latexpdf PAPER=letter
|
||||
mkdir $(BUILDDIR)/pdf-letter/
|
||||
cp $(BUILDDIR)/latex/*.pdf $(BUILDDIR)/pdf-letter/.
|
||||
@echo
|
||||
@echo "Build finished for Letter-sized PDFs. The PDF files are in $(BUILDDIR)/pdf-letter."
|
||||
|
||||
pdf: pwd pdfa4 pdfletter
|
||||
|
||||
all: pwd html pdf
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${project}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/make"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="${string_prompt:the target(s), which can be one or more of "clean html pdfa4 pdfletter pdf all" (all means "html pdf").:clean all} HALTONWARNING=${string_prompt:treat warnings as errors (and halt the build):y} CONTEXT=${string_prompt:a keyword (typically the name of your organization) which identifies any setup required (can be omitted).:diamond}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${project_loc:diffcalc}/doc"/>
|
||||
</launchConfiguration>
|
||||
22
script/__Lib/diffcalc_old/doc/references
Normal file
22
script/__Lib/diffcalc_old/doc/references
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
|
||||
.. [Vlieg1993] Martin Lohmeier and Elias Vlieg. *Angle calculations for a six-circle
|
||||
surface x-ray diffractometer.* J. Appl. Cryst. (1993). **26**, 706-716. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1993/05/00/la0044/la0044.pdf>`__.
|
||||
|
||||
.. [Vlieg1998] Elias Vlieg. *A (2+3)-type surface diffractometer: mergence of the z-axis and
|
||||
(2+2)-type geometries.* J. Appl. Cryst. (1998). **31**, 198-203. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1998/02/00/pe0028/pe0028.pdf>`__.
|
||||
|
||||
.. [Willmott2011] C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans'l and
|
||||
P. R. Willmott. *Angle calculations for a (2+3)-type diffractometer: focus
|
||||
on area detectors.* J. Appl. Cryst. (2011). **44**, 73-83. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/2011/01/00/db5088/db5088.pdf>`__.
|
||||
|
||||
243
script/__Lib/diffcalc_old/doc/source/conf.py
Normal file
243
script/__Lib/diffcalc_old/doc/source/conf.py
Normal file
@@ -0,0 +1,243 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Apr 15 10:03:07 2011.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os, time
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Diffcalc'
|
||||
copyright = u'2017-%s, Diamond Light Source' % time.strftime('%Y')
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '2.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
# html_theme_options = {
|
||||
# 'sidebarbgcolor' : '#f2f2f2',
|
||||
# 'sidebartextcolor': '#444a95',
|
||||
# 'sidebarlinkcolor': '#0b0f40',
|
||||
# }
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
|
||||
import sphinx_rtd_theme
|
||||
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
html_logo = 'diffcalc_web.png'
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
#html_static_path = ['_static']
|
||||
html_static_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
html_show_sourcelink = False
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
html_show_sphinx = False
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
latex_paper_size = 'a4'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('youmanual', 'diffcalc_user_guide.tex', u'Diffcalc User Guide',
|
||||
u'Diamond Light Source', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page
|
||||
latex_logo = 'diffcalc_pdf.png'
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
#man_pages = []
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {}
|
||||
|
||||
"""
|
||||
Additional options for Diffcalc
|
||||
"""
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
extlinks = {
|
||||
'opengda_url' :('http://www.opengda.org/%s', None),
|
||||
}
|
||||
|
||||
rst_prolog = """
|
||||
.. |DLS| replace:: :abbr:`DLS (Diamond Light Source)`
|
||||
"""
|
||||
7
script/__Lib/diffcalc_old/doc/source/developer/ACKS.rst
Normal file
7
script/__Lib/diffcalc_old/doc/source/developer/ACKS.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
********
|
||||
Thanks
|
||||
********
|
||||
|
||||
.. Do not add the names of contributors here. Instead, add them to the common list, so that they can be included in separate documents.
|
||||
|
||||
.. include:: ../../ACKS_diffcalc.rst
|
||||
26
script/__Lib/diffcalc_old/doc/source/developer/contents.rst
Normal file
26
script/__Lib/diffcalc_old/doc/source/developer/contents.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
########################
|
||||
Diffcalc Developer Guide
|
||||
########################
|
||||
|
||||
:Author: Rob Walton
|
||||
:Contact: rob.walton (at) diamond (dot) ac (dot) uk
|
||||
:Website: http://www.opengda.org/
|
||||
|
||||
.. rubric:: Diffcalc: A diffraction condition calculator for diffractometer control
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
intro
|
||||
package
|
||||
quickstart_api
|
||||
development
|
||||
ACKS
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -0,0 +1,24 @@
|
||||
Development
|
||||
===========
|
||||
|
||||
The files are kept here_ on github_. See bootcamp for an introduction to
|
||||
using github. To contribute please fork the project. Otherwise you can make
|
||||
a read-only clone or export.
|
||||
|
||||
Code format should follow pep8 guidelines. PyDev has a good pep8 checker.
|
||||
|
||||
To run the tests install nose_, change directory into the test folder and run::
|
||||
|
||||
$ nosetests
|
||||
.......... ...
|
||||
----------------------------------------------------------------------
|
||||
Ran 3914 tests in 9.584s
|
||||
|
||||
OK (SKIP=15)
|
||||
|
||||
|
||||
|
||||
.. _here: https://github.com/DiamondLightSource/diffcalc
|
||||
.. _github: https://github.com
|
||||
.. _nose: http://nose.readthedocs.org/en/latest/
|
||||
.. _pep8: http://www.python.org/dev/peps/pep-0008/
|
||||
55
script/__Lib/diffcalc_old/doc/source/developer/intro.rst
Normal file
55
script/__Lib/diffcalc_old/doc/source/developer/intro.rst
Normal file
@@ -0,0 +1,55 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
Diffcalc is a diffraction condition calculator used for controlling
|
||||
diffractometers within reciprocal lattice space. It performs the same
|
||||
task as the ``fourc``, ``sixc``, ``twoc``, ``kappa``, ``psic`` and
|
||||
``surf`` macros from SPEC_.
|
||||
|
||||
Diffcalc's standard calculation engine is an implementation of
|
||||
[You1999]_ . The first versions of Diffcalc were based on
|
||||
[Vlieg1993]_ and [Vlieg1998]_ and a 'Vlieg' engine is still
|
||||
available. The 'You' engine is more generic and the plan is to remove
|
||||
the old 'Vlieg' engine once beamlines have been migrated. New users
|
||||
should use the 'You' engine.
|
||||
|
||||
The foundations for this type of calculation were laid by by Busing &
|
||||
Levi in their classic paper [Busing1967]_. Diffcalc's orientation
|
||||
algorithm is taken from this paper. Busing & Levi also provided the
|
||||
original definition of the coordinate frames and of the U and B
|
||||
matrices used to describe a crystal's orientation and to convert between
|
||||
Cartesian and reciprical lattice space.
|
||||
|
||||
Geometry plugins are used to adapt the six circle model used
|
||||
internally by Diffcalc to apply to other diffractometers. These
|
||||
contain a dictionary of the 'missing' angles which Diffcalc uses to
|
||||
constrain these angles internally, and a methods to map from external
|
||||
angles to Diffcalc angles and visa versa.
|
||||
|
||||
Options to use Diffcalc:
|
||||
|
||||
- **The User manual next to this developer manual or README file on github.**
|
||||
- The :ref:`quickstart-api` section describes how to run up only
|
||||
the core in Python_. This provides a base option for system integration.
|
||||
|
||||
Diffcalc will work with Python 2.7 or higher with numpy_, or with
|
||||
Jython 2.7 of higher with Jama_.
|
||||
|
||||
|
||||
.. [*] The very small 'Willmott' engine currently handles the case for
|
||||
surface diffraction where the surface normal is held vertical
|
||||
[Willmott2011]_. The 'You' engine handles this case fine, but
|
||||
currently spins nu into an unhelpful quadrant. We hope to
|
||||
remove the need for this engine soon.
|
||||
|
||||
|
||||
.. _SPEC: http://www.certif.com/
|
||||
.. _Python: http://python.org
|
||||
.. _IPython: http://http://ipython.org/
|
||||
.. _Jython: http://jython.org
|
||||
.. _OpenGDA: http://opengda.org
|
||||
.. _numpy: http://numpy.scipy.org/
|
||||
.. _Jama: http://math.nist.gov/javanumerics/jama/
|
||||
|
||||
|
||||
.. include:: ../../references
|
||||
30
script/__Lib/diffcalc_old/doc/source/developer/package.rst
Normal file
30
script/__Lib/diffcalc_old/doc/source/developer/package.rst
Normal file
@@ -0,0 +1,30 @@
|
||||
Project Files & Directories
|
||||
===========================
|
||||
|
||||
diffcalc
|
||||
The main source package.
|
||||
|
||||
test
|
||||
Diffcalcs unit-test package (use Nose_ to run them).
|
||||
|
||||
diffcmd
|
||||
A spec-like openGDA emulator.
|
||||
|
||||
numjy
|
||||
A *very* minimal implentation of numpy for jython. It supports only what
|
||||
Diffcalc needs.
|
||||
|
||||
doc
|
||||
The documentation is written in reStructuredText and can be compiled into
|
||||
html and pdf using Python's `Sphinx <http://sphinx.pocoo.org>`_. With Sphinx
|
||||
installed use ``make clean all`` from within the user and developer guide
|
||||
folders to build the documentation.
|
||||
|
||||
startup
|
||||
Starup scripts called by diffcmd or openGDA to startup diffcalc
|
||||
|
||||
model
|
||||
Vrml models of diffractometers and a hokey script for animating then and
|
||||
controlling them from diffcalc.
|
||||
|
||||
.. _Nose: http://readthedocs.org/docs/nose/en/latest/
|
||||
@@ -0,0 +1,266 @@
|
||||
.. _quickstart-api:
|
||||
|
||||
.. warning:: This documentation is out of date. The README and the user doc has been updated recently. For now if you need help with API, please contact me at Diamond. -- Rob Walton
|
||||
|
||||
Quick-Start: Python API
|
||||
=======================
|
||||
|
||||
This section describes how to run up only the core in Python or
|
||||
IPython. This provides an API which could be used to integrate Diffcalc into an
|
||||
existing data acquisition system; although the interface described in
|
||||
the README would normally provide a better starting point.
|
||||
|
||||
For a full description of what Diffcalc does and how to use it please
|
||||
see the 'Diffcalc user manual'.
|
||||
|
||||
Setup environment
|
||||
-----------------
|
||||
|
||||
.. include:: quickstart_setup_environment
|
||||
|
||||
|
||||
Start
|
||||
-----
|
||||
|
||||
With Python start the sixcircle_api.py example startup script (notice
|
||||
the -i and -m) and call `demo_all()`::
|
||||
|
||||
$ python -i -m startup.api.sixcircle
|
||||
>>> demo_all()
|
||||
|
||||
IPython requires::
|
||||
|
||||
$ ipython -i startup/api/sixcircle.py
|
||||
>>> demo_all()
|
||||
|
||||
Alternatively start Python or IPython and cut and paste lines from the rest of
|
||||
this tutorial.
|
||||
|
||||
Configure a diffraction calculator
|
||||
----------------------------------
|
||||
|
||||
By default some exceptions are handled in a way to make user interaction
|
||||
friendlier. Switch this off with::
|
||||
|
||||
>>> import diffcalc.util
|
||||
>>> diffcalc.util.DEBUG = True
|
||||
|
||||
To setup a Diffcalc calculator, first configure `diffcalc.settings` module::
|
||||
|
||||
>>> from diffcalc import settings
|
||||
>>> from diffcalc.hkl.you.geometry import SixCircle
|
||||
>>> from diffcalc.hardware import DummyHardwareAdapter
|
||||
>>> settings.hardware = DummyHardwareAdapter(('mu', 'delta', 'gam', 'eta', 'chi', 'phi'))
|
||||
>>> settings.geometry = SixCircle() # @UndefinedVariable
|
||||
|
||||
The hardware adapter is used by Diffcalc to read up the current angle
|
||||
settings, wavelength and axes limits. It is primarily used to simplify
|
||||
commands for end users. It could be dropped for this API use, but it
|
||||
is also used for the important job of checking axes limits while
|
||||
choosing solutions.
|
||||
|
||||
Geometry plugins are used to adapt the six circle model used
|
||||
internally by Diffcalc to apply to other diffractometers. These
|
||||
contain a dictionary of the 'missing' angles which Diffcalc internally
|
||||
uses to constrain these angles, and a methods to map from
|
||||
external angles to Diffcalc angles and visa versa.
|
||||
|
||||
|
||||
Calling the API
|
||||
---------------
|
||||
|
||||
The ``diffcalc.dc.dcyou`` module (and others) read the ``diffcalc.settings`` module when first
|
||||
imported. Note that this means that changes to the settings will most likely
|
||||
have no effect unless ``diffcalc.dc.dcyou`` is reloaded::
|
||||
|
||||
>>> import diffcalc.dc.dcyou as dc
|
||||
|
||||
This includes the two critical functions::
|
||||
|
||||
def hkl_to_angles(h, k, l, energy=None):
|
||||
"""Convert a given hkl vector to a set of diffractometer angles
|
||||
|
||||
return angle tuple and virtual angles dictionary
|
||||
"""
|
||||
|
||||
def angles_to_hkl(angle_tuple, energy=None):
|
||||
"""Converts a set of diffractometer angles to an hkl position
|
||||
|
||||
Return hkl tuple and virtual angles dictionary
|
||||
"""
|
||||
|
||||
``diffcalc.dc.dcyou`` also brings in all the commands from ``diffcalc.ub.ub``,
|
||||
``diffcalc.hardware`` and ``diffcalc.hkl.you.hkl``. That is it includes all the
|
||||
commands exposed in the top level namespace when diffcalc is used interactively::
|
||||
|
||||
>>> dir(dc)
|
||||
|
||||
['__builtins__', '__doc__', '__file__', '__name__', '__package__',
|
||||
'_hardware','_hkl', '_ub', 'addref', 'allhkl', 'angles_to_hkl', 'c2th',
|
||||
'calcub', 'checkub', 'clearref', 'con', 'constraint_manager', 'delref',
|
||||
'diffcalc', 'editref', 'energy_to_wavelength', 'hardware', 'hkl_to_angles',
|
||||
'hklcalc', 'lastub', 'listub', 'loadub', 'newub', 'rmub', 'saveubas', 'setcut',
|
||||
'setlat', 'setmax', 'setmin', 'settings', 'setu', 'setub', 'showref',
|
||||
'swapref', 'trialub', 'ub', 'ub_commands_for_help', 'ubcalc', 'uncon']
|
||||
|
||||
This doesn't form the best API to program against though, so it is best to
|
||||
use the four modules more directly. The example below assumes you have
|
||||
also imported::
|
||||
|
||||
>>> from diffcalc.ub import ub
|
||||
>>> from diffcalc import hardware
|
||||
>>> from diffcalc.hkl.you import hkl
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
To get help for the diffcalc angle calculations, the orientation phase, the
|
||||
angle calculation phase, and the dummy hardware adapter commands::
|
||||
|
||||
>>> help(dc)
|
||||
>>> help(ub)
|
||||
>>> help(hkl)
|
||||
>>> help(hardware)
|
||||
|
||||
|
||||
Orientation
|
||||
-----------
|
||||
|
||||
To orient the crystal for example (see the user manual for a fuller
|
||||
tutorial) first find some reflections::
|
||||
|
||||
# Create a new ub calculation and set lattice parameters
|
||||
ub.newub('test')
|
||||
ub.setlat('cubic', 1, 1, 1, 90, 90, 90)
|
||||
|
||||
# Add 1st reflection (demonstrating the hardware adapter)
|
||||
hardware.settings.hardware.wavelength = 1
|
||||
ub.c2th([1, 0, 0]) # energy from hardware
|
||||
settings.hardware.position = 0, 60, 0, 30, 0, 0 # mu del nu eta chi ph
|
||||
ub.addref([1, 0, 0]) # energy & pos from hardware
|
||||
|
||||
# Add 2nd reflection (this time without the hardware adapter)
|
||||
ub.c2th([0, 1, 0], 12.39842)
|
||||
ub.addref([0, 1, 0], [0, 60, 0, 30, 0, 90], 12.39842)
|
||||
|
||||
|
||||
To check the state of the current UB calculation::
|
||||
|
||||
>>> ub.ub()
|
||||
|
||||
UBCALC
|
||||
|
||||
name: test
|
||||
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
|
||||
CRYSTAL
|
||||
|
||||
name: cubic
|
||||
|
||||
a, b, c: 1.00000 1.00000 1.00000
|
||||
90.00000 90.00000 90.00000
|
||||
|
||||
B matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
UB MATRIX
|
||||
|
||||
U matrix: 1.00000 0.00000 0.00000
|
||||
0.00000 1.00000 0.00000
|
||||
0.00000 0.00000 1.00000
|
||||
|
||||
U angle: 0
|
||||
|
||||
UB matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
REFLECTIONS
|
||||
|
||||
ENERGY H K L MU DELTA GAM ETA CHI PHI TAG
|
||||
1 12.398 1.00 0.00 0.00 0.0000 60.0000 0.0000 30.0000 0.0000 0.0000
|
||||
2 12.398 0.00 1.00 0.00 0.0000 60.0000 0.0000 30.0000 0.0000 90.0000
|
||||
|
||||
And finally to check the reflections were specified acurately::
|
||||
|
||||
>>> dc.checkub()
|
||||
|
||||
ENERGY H K L H_COMP K_COMP L_COMP TAG
|
||||
1 12.3984 1.00 0.00 0.00 1.0000 0.0000 0.0000
|
||||
2 12.3984 0.00 1.00 0.00 -0.0000 1.0000 0.0000
|
||||
|
||||
Motion
|
||||
------
|
||||
|
||||
Hkl positions and virtual angles can now be read up from angle
|
||||
settings (the easy direction!)::
|
||||
|
||||
|
||||
>>> dc.angles_to_hkl((0., 60., 0., 30., 0., 0.)) # energy from hardware
|
||||
|
||||
((1.0, 5.5511151231257827e-17, 0.0),
|
||||
{'alpha': -0.0,
|
||||
'beta': 3.5083546492674376e-15,
|
||||
'naz': 0.0,
|
||||
'psi': 90.0,
|
||||
'qaz': 90.0,
|
||||
'tau': 90.0,
|
||||
'theta': 29.999999999999996})
|
||||
|
||||
Before calculating the settings to reach an hkl position (the trickier
|
||||
direction) hardware limits must be set and combination of constraints
|
||||
chosen. The constraints here result in a four circle like mode with a
|
||||
vertical scattering plane and incident angle 'alpha' equal to the exit
|
||||
angle 'beta'::
|
||||
|
||||
>>> hkl.con('qaz', 90)
|
||||
! 2 more constraints required
|
||||
qaz: 90.0000
|
||||
|
||||
>>> hkl.con('a_eq_b')
|
||||
! 1 more constraint required
|
||||
qaz: 90.0000
|
||||
a_eq_b
|
||||
|
||||
>>> hkl.con('mu', 0)
|
||||
qaz: 90.0000
|
||||
a_eq_b
|
||||
mu: 0.0000
|
||||
|
||||
To check the constraints::
|
||||
|
||||
>>> hkl.con()
|
||||
DET REF SAMP
|
||||
====== ====== ======
|
||||
delta --> a_eq_b --> mu
|
||||
alpha eta
|
||||
--> qaz beta chi
|
||||
naz psi phi
|
||||
mu_is_nu
|
||||
|
||||
qaz: 90.0000
|
||||
a_eq_b
|
||||
mu: 0.0000
|
||||
|
||||
Type 'help con' for instructions
|
||||
|
||||
Limits can be set to help Diffcalc choose a solution::
|
||||
|
||||
>>> hardware.setmin('delta', 0) # used when choosing solution
|
||||
|
||||
Angles and virtual angles are then easily determined for a given hkl reflection::
|
||||
|
||||
>>> dc.hkl_to_angles(1, 0, 0) # energy from hardware
|
||||
((0.0, 60.0, 0.0, 30.0, 0.0, 0.0),
|
||||
{'alpha': -0.0,
|
||||
'beta': 0.0,
|
||||
'naz': 0.0,
|
||||
'psi': 90.0,
|
||||
'qaz': 90.0,
|
||||
'tau': 90.0,
|
||||
'theta': 30.0}
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Change directory to the diffcalc project (python adds the current
|
||||
working directory to the path)::
|
||||
|
||||
$ cd diffcalc
|
||||
$ ls
|
||||
COPYING diffcalc doc example mock.py mock.pyc model numjy test
|
||||
|
||||
If using Python make sure numpy and diffcalc can be imported::
|
||||
|
||||
$ python
|
||||
Python 2.7.2+ (default, Oct 4 2011, 20:06:09)
|
||||
[GCC 4.6.1] on linux2
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> import numpy
|
||||
>>> import diffcalc
|
||||
|
||||
If using Jython make sure Jama and diffcalc can be imported::
|
||||
|
||||
$ jython -Dpython.path=<diffcalc_root>:<path_to_Jama>/Jama-1.0.1.jar
|
||||
|
||||
Jython 2.2.1 on java1.5.0_11
|
||||
Type "copyright", "credits" or "license" for more information.
|
||||
>>> import Jama
|
||||
>>> import diffcalc
|
||||
BIN
script/__Lib/diffcalc_old/doc/source/diffcalc_pdf.png
Normal file
BIN
script/__Lib/diffcalc_old/doc/source/diffcalc_pdf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
script/__Lib/diffcalc_old/doc/source/diffcalc_web.png
Normal file
BIN
script/__Lib/diffcalc_old/doc/source/diffcalc_web.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
26
script/__Lib/diffcalc_old/doc/source/index.rst
Normal file
26
script/__Lib/diffcalc_old/doc/source/index.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
###################################
|
||||
Diffcalc User and Developer Guide
|
||||
###################################
|
||||
|
||||
:Author: Rob Walton
|
||||
:Contact: rob.walton (at) diamond.ac.uk
|
||||
:Web site: https://github.com/DiamondLightSource/diffcalc
|
||||
|
||||
.. rubric:: Diffcalc: A Diffraction Condition Calculator for Diffractometer Control
|
||||
|
||||
See also the `quickstart guide at github <https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst>`_.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
youmanual
|
||||
vliegmanual/contents
|
||||
developer/contents
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
@@ -0,0 +1,7 @@
|
||||
********
|
||||
Thanks
|
||||
********
|
||||
|
||||
.. Do not add the names of contributors here. Instead, add them to the common list, so that they can be included in separate documents.
|
||||
|
||||
.. include:: ../../ACKS_diffcalc.rst
|
||||
@@ -0,0 +1,22 @@
|
||||
#############################################
|
||||
Diffcalc User Guide (Deprecated Vlieg Engine)
|
||||
#############################################
|
||||
|
||||
:Author: Rob Walton
|
||||
:Contact: rob.walton (at) diamond (dot) ac (dot) uk
|
||||
:Website: http://www.opengda.org/
|
||||
|
||||
.. rubric:: Diffcalc: A diffraction condition calculator for diffractometer control
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
vliegmanual
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
BIN
script/__Lib/diffcalc_old/doc/source/vliegmanual/images/fix.png
Normal file
BIN
script/__Lib/diffcalc_old/doc/source/vliegmanual/images/fix.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 283 B |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
827
script/__Lib/diffcalc_old/doc/source/vliegmanual/vliegmanual.rst
Normal file
827
script/__Lib/diffcalc_old/doc/source/vliegmanual/vliegmanual.rst
Normal file
@@ -0,0 +1,827 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. warning::
|
||||
|
||||
This manual refers to the 'Vlieg' calculation available in Diffcalc I. By
|
||||
default Diffcalc II now uses its 'You' engine. This manual will be updated
|
||||
soon. For now the developer guide shows how the new constraint system works.
|
||||
|
||||
This manual assumes that you are running Diffcalc within the external
|
||||
framework of the GDA or Minigda and that Diffcalc has been configured
|
||||
for the six circle diffractometer pictured here:
|
||||
|
||||
.. figure:: images/sixcircle_gamma_on_arm.*
|
||||
:scale: 50
|
||||
:align: center
|
||||
|
||||
Gamma-on-delta six-circle diffractometer, modified from Elias Vlieg
|
||||
& Martin Lohmeier (1993)
|
||||
|
||||
Your Diffcalc configuration will have been customised for the geometry
|
||||
of your diffractometer and possibly the types of experiment you
|
||||
perform. For example: a five-circle diffractometer might be missing
|
||||
the Gamma circle above, some six-circle modes and the option to fix
|
||||
gamma that would otherwise exist in some modes.
|
||||
|
||||
The laboratory, crystal and reciprocal-lattice coordinate frames are
|
||||
defined with respect to the beam and to gravity to be (for a cubic crystal):
|
||||
|
||||
.. figure:: images/fix.png
|
||||
:align: center
|
||||
|
||||
Laboratory and illustratrive crystal coordinate frames for a cubic crystal
|
||||
|
||||
The crystal lattice basis vectors are defined within the Cartesian
|
||||
crystal coordinate frame to be:
|
||||
|
||||
.. figure:: images/unit_cell.*
|
||||
:align: center
|
||||
:scale: 100
|
||||
|
||||
Unit cell defined in crystal coordinate frame
|
||||
|
||||
.. _overview:
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The following assumes that the diffractometer has been properly levelled, aligned with
|
||||
the beam and zeroed. See the `SPEC fourc manual <http://www.certif.com/spec_manual/fourc_4_2.html>`__.
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by
|
||||
specifying the crystal's lattice parameters (which define the B
|
||||
matrix) and finding two reflections (from which the
|
||||
U matrix can be inferred); and, optionally for surface-diffraction
|
||||
experiments, determine how the surface of the crystal is oriented with
|
||||
respect to the phi axis.
|
||||
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven
|
||||
in hkl coordinates. A valid diffractometer setting maps easily into a
|
||||
single hkl value. However for a diffractometer with more than three circles
|
||||
there are excess degrees of freedom when calculating a diffractometer
|
||||
setting from an hkl value. Diffcalc provides modes for using up
|
||||
the excess degrees of freedom.
|
||||
|
||||
Diffcalc does not perform scans directly. Instead, scannables that use
|
||||
diffcalc to map between reciprocal lattice space and real
|
||||
diffractometer settings are scanned using the Gda's (or minigda's)
|
||||
generic scan mechanism.
|
||||
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
Thanks to Elias Vlieg for sharing his dos based ``DIF`` software that
|
||||
Diffcalc has borrowed heavily from. (See also the THANKS.txt file).
|
||||
|
||||
See the papers (included in ``docs/ref``):
|
||||
|
||||
* Busing & Levi (1966), "Angle Calculations for 3- and 4- Circle X-ray
|
||||
and Neutron Diffractometers", Acta Cryst. 22, 457
|
||||
|
||||
* Elias Vlieg & Martin Lohmeier (1993), "Angle Calculations for a Six-Circle
|
||||
Surface X-ray Diffractometer", J. Appl. Cryst. 26, 706-716
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
There are few commands to remember. If a command is called without
|
||||
arguments, Diffcalc will prompt for arguments and provide sensible
|
||||
defaults which can be chosen by pressing enter.
|
||||
|
||||
The ``helpub`` and ``helphkl`` commands provide help with the crystal
|
||||
orientation and hkl movement phases of an experiment respectively::
|
||||
|
||||
>>> helpub
|
||||
|
||||
Diffcalc
|
||||
--------
|
||||
helpub ['command'] - lists all ub commands, or one if command is given
|
||||
helphkl ['command'] - lists all hkl commands, or one if command is given
|
||||
|
||||
UB State
|
||||
--------
|
||||
newub 'name' - starts a new ub calculation with no lattice or
|
||||
reflection list
|
||||
loadub 'name' - loads an existing ub calculation: lattice and
|
||||
reflection list
|
||||
saveubas 'name' - saves the ubcalculation with a new name (other
|
||||
changes autosaved)
|
||||
ub - shows the complete state of the ub calculation
|
||||
|
||||
UB lattice
|
||||
----------
|
||||
setlat - prompts user to enter lattice parameters (in
|
||||
Angstroms and Deg.)
|
||||
setlat 'name' a - assumes cubic
|
||||
setlat 'name' a b - assumes tetragonal
|
||||
setlat 'name' a b c - assumes ortho
|
||||
setlat 'name' a b c gam - assumes mon/hex with gam not equal to 90
|
||||
setlat 'name' a b c alpha beta gamma - arbitrary
|
||||
|
||||
UB surface
|
||||
----------
|
||||
sigtau [sigma tau] - sets sigma and tau
|
||||
|
||||
UB reflections
|
||||
--------------
|
||||
showref - shows full reflection list
|
||||
addref - add reflection
|
||||
addref h k l ['tag'] - add reflection with hardware position and energy
|
||||
addref h k l (p1,p2...pN) energy ['tag']- add reflection with specified position
|
||||
and energy
|
||||
delref num - deletes a reflection (numbered from 1)
|
||||
swapref - swaps first two reflections used for calculating U
|
||||
swapref num1 num2 - swaps two reflections (numbered from 1)
|
||||
|
||||
UB calculation
|
||||
--------------
|
||||
setu [((,,),(,,),(,,))] - manually set u matrix
|
||||
setub ((,,),(,,),(,,)) - manually set ub matrix
|
||||
calcub - (re)calculate u matrix from ref1 and ref2
|
||||
checkub - show calculated and entered hkl values for reflections
|
||||
|
||||
>>> helphkl
|
||||
|
||||
Diffcalc
|
||||
--------
|
||||
helphkl [command] - lists all hkl commands, or one if command is given
|
||||
helpub [command] - lists all ub commands, or one if command is given
|
||||
|
||||
Settings
|
||||
--------
|
||||
hklmode [num] - changes mode or shows current and available modes
|
||||
and all settings
|
||||
setalpha [num] - fixes alpha, or shows all settings if no num given
|
||||
setgamma [num] - fixes gamma, or shows all settings if no num given
|
||||
setbetain [num] - fixes betain, or shows all settings if no num given
|
||||
setbetaout [num] - fixes betaout, or shows all settings if no num given
|
||||
trackalpha [boolean] - determines wether alpha parameter will track alpha axis
|
||||
trackgamma [boolean] - determines wether gamma parameter will track gamma axis
|
||||
trackphi [boolean] - determines wether phi parameter will track phi axis
|
||||
setsectorlim [omega_high omega_low phi_high phi_low]- sets sector limits
|
||||
|
||||
Motion
|
||||
------
|
||||
pos hkl [h k l] - move diffractometer to hkl, or read hkl position.
|
||||
Use None to hold a value still
|
||||
sim hkl [h k l] - simulates moving hkl
|
||||
hkl - shows loads of info about current hkl position
|
||||
pos sixc [alpha, delta, gamma, omega, chi, phi,]- move diffractometer to Eularian
|
||||
position. Use None to hold a
|
||||
value still
|
||||
sim sixc [alpha, delta, gamma, omega, chi, phi,]- simulates moving sixc
|
||||
sixc - shows loads of info about current sixc position
|
||||
|
||||
|
||||
Diffcalc's Scannables
|
||||
=====================
|
||||
|
||||
Please see :ref:`moving-in-hkl-space` and :ref:`scanning-in-hkl-space` for some relevant examples.
|
||||
|
||||
To list and show the current positions of your beamline's scannables
|
||||
use ``pos`` with no arguments::
|
||||
|
||||
>>> pos
|
||||
|
||||
Results in:
|
||||
|
||||
**Energy and wavelength scannables**::
|
||||
|
||||
energy 12.3984
|
||||
wl: 1.0000
|
||||
|
||||
**Diffractometer scannables**, as a group and in component axes (in
|
||||
the real GDA these have limits)::
|
||||
|
||||
sixc: alpha: 0.0000 delta: 0.0000 gamma: 0.0000 omega: 0.0000 chi: 0.0000 phi: 0.0000
|
||||
alpha: 0.0000
|
||||
chi: 0.0000
|
||||
delta: 0.0000
|
||||
gamma: 0.0000
|
||||
omega: 0.0000
|
||||
phi: 0.0000
|
||||
|
||||
**Dummy counter**, which in this example simply counts at 1hit/s::
|
||||
|
||||
cnt: 0.0000
|
||||
|
||||
**Hkl scannable**, as a group and in component::
|
||||
|
||||
hkl: Error: No UB matrix
|
||||
h: Error: No UB matrix
|
||||
k: Error: No UB matrix
|
||||
l: Error: No UB matrix
|
||||
|
||||
**Parameter scannables**, used in some modes, these provide a
|
||||
scannable alternative to the series of ``fix`` commands described in
|
||||
:ref:`moving-in-hkl-space`.::
|
||||
|
||||
alpha_par:0.00000
|
||||
azimuth: ---
|
||||
betain: ---
|
||||
betaout: ---
|
||||
gamma_par:0.00000
|
||||
phi_par: ---
|
||||
|
||||
Note that where a parameter corresponds with a physical
|
||||
diffractometer axis, it can also be set to track that axis
|
||||
directly. See `Tracking axis`_ below.
|
||||
|
||||
Crystal orientation
|
||||
===================
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by
|
||||
specifying the crystal's lattice parameters (which define the B
|
||||
matrix) and finding two reflections (from which the
|
||||
U matrix can be inferred); and, optionally for surface-diffraction
|
||||
experiments, determine how the surface of the crystal is oriented with
|
||||
respect to the phi axis (see :ref:`overview`).
|
||||
|
||||
Starting a UB calculation
|
||||
-------------------------
|
||||
|
||||
A *UB-calculation* contains the description of the crystal-under-test,
|
||||
any saved reflections, sigma & tau (both default to 0), and a B & UB
|
||||
matrix pair if they have been calculated or manually specified.
|
||||
Starting a new UB calculation will clear all of these.
|
||||
|
||||
Before starting a UB-calculation, the ``ub`` command used to summarise
|
||||
the state of the current UB-calculation, will reflect that no
|
||||
UB-calculation has been started::
|
||||
|
||||
>>> ub
|
||||
No UB calculation started.
|
||||
Wavelength: 1.239842
|
||||
Energy: 10.000000
|
||||
|
||||
A new UB-calculation calculation may be started and lattice specified
|
||||
explicitly::
|
||||
|
||||
>>> newub 'b16_270608'
|
||||
>>> setlat 'xtal' 3.8401 3.8401 5.43072 90 90 90
|
||||
|
||||
or interactively::
|
||||
|
||||
>>> newub
|
||||
calculation name: b16_270608
|
||||
crystal name: xtal
|
||||
a [1]: 3.8401
|
||||
b [3.8401]: 3.8401
|
||||
c [3.8401]: 5.43072
|
||||
alpha [90]: 90
|
||||
beta [90]: 90
|
||||
gamma [90]: 90
|
||||
|
||||
where a,b and c are the lengths of the three unit cell basis vectors
|
||||
in Angstroms, and alpha, beta and gamma the typically used angles
|
||||
(defined in the figure above) in Degrees.
|
||||
|
||||
The ``ub`` command will show the state of the current UB-calculation
|
||||
(and the current energy for reference)::
|
||||
|
||||
UBCalc: b16_270608
|
||||
======
|
||||
|
||||
Crystal
|
||||
-------
|
||||
name: xtal
|
||||
|
||||
lattice: a ,b ,c = 3.84010, 3.84010, 5.43072
|
||||
alpha, beta , gamma = 90.00000, 90.00000, 90.00000
|
||||
|
||||
reciprocal: b1, b2, b3 = 1.63620, 1.63620, 1.15697
|
||||
beta1, beta2, beta3 = 1.57080, 1.57080, 1.57080
|
||||
|
||||
B matrix: 1.6362035642769 -0.0000000000000 -0.000000000000
|
||||
0.0000000000000 1.6362035642769 -0.000000000000
|
||||
0.0000000000000 0.0000000000000 1.156970955450
|
||||
|
||||
Reflections
|
||||
-----------
|
||||
energy h k l alpha delta gamma omega chi phi tag
|
||||
|
||||
UB matrix
|
||||
---------
|
||||
none calculated
|
||||
|
||||
Sigma: 0.000000
|
||||
Tau: 0.000000
|
||||
Wavelength: 1.000000
|
||||
Energy: 12.398420
|
||||
|
||||
|
||||
Specifying Sigma and Tau for surface diffraction experiments
|
||||
------------------------------------------------------------
|
||||
Sigma and Tau are used in modes that fix either the beam exit or entry angle with
|
||||
respect to the crystal surface, or that keep the surface normal in the horizontal
|
||||
laboratory plane. For non surface-diffraction experiments these can
|
||||
safely be left at zero.
|
||||
|
||||
For surface diffraction experiments, where not only the crystal's
|
||||
lattice planes must be oriented appropriately but so must the crystal's
|
||||
optical surface, two angles _Tau_ and _Sigma_ define the orientation of
|
||||
the surface with respect to the phi axis. Sigma is (minus) the amount of chi axis
|
||||
rotation and Tau (minus) the amount of phi axis rotation needed to
|
||||
move the surface normal parallel to the omega circle
|
||||
axis. These angles are often determined by reflecting a laser from the
|
||||
surface of the Crystal onto some thing and moving chi and tau until
|
||||
the reflected spot remains stationary with movements of omega.
|
||||
|
||||
Use ``sigtau`` with no args to set interactively::
|
||||
|
||||
>>> pos chi -3.1
|
||||
chi: -3.1000
|
||||
>>> pos phi 10.0
|
||||
phi: 10.0000
|
||||
>>> sigtau
|
||||
sigma, tau = 0.000000, 0.000000
|
||||
chi, phi = -3.100000, 10.000000
|
||||
sigma[ 3.1]: 3.1
|
||||
tau[-10.0]: 10.0
|
||||
|
||||
Sigma and Tau can also be set explicitly::
|
||||
|
||||
>>>sigtau 0 0
|
||||
|
||||
|
||||
Managing reflections
|
||||
--------------------
|
||||
The normal way to calculate a UB matrix is to find the position of **two**
|
||||
reflections with known hkl values. Diffcalc allows many
|
||||
reflections to be recorded but currently only uses the first two when
|
||||
calculating a UB matrix.
|
||||
|
||||
Add reflection at current location
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It is normal to first move to a reflection::
|
||||
|
||||
>>> pos en 10
|
||||
en: 10.0000
|
||||
>>> pos sixc [5.000, 22.790, 0.000, 1.552, 22.400, 14.255]
|
||||
sixc: alpha: 5.0000 delta: 22.7900 gamma: 0.0000 omega: 1.5520 chi: 22.4000 phi: 14.2550
|
||||
|
||||
|
||||
and then use the ``addref`` command either explicitly::
|
||||
|
||||
addref 1 0 1.0628 'optional_tag'
|
||||
|
||||
or interactively::
|
||||
|
||||
>>> addref
|
||||
h: 1
|
||||
k: 0
|
||||
l: 1.0628
|
||||
current pos[y]: y
|
||||
tag: 'tag_string'
|
||||
|
||||
to add a reflection.
|
||||
|
||||
Add a reflection manually
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If a reflection cannot be reached but its position is known (or if its
|
||||
position has been previously determined), a reflection may be added
|
||||
without first moving to it either explicitly::
|
||||
|
||||
>>> addref 0 1 1.0628 [5.000, 22.790, 0.000,4.575, 24.275, 101.320] 'optional_tag'
|
||||
|
||||
or interactively::
|
||||
|
||||
>>> addref
|
||||
h: 0
|
||||
k: 1
|
||||
l: 1.0628
|
||||
current pos[y]: n
|
||||
alpha[5.000]:
|
||||
delta[22.79]:
|
||||
gamma[0.000]:
|
||||
omega[1.552]: 4.575
|
||||
chi[22.40]: 24.275
|
||||
phi[14.25]: 101.320
|
||||
en[9.998]:
|
||||
tag: optional_tag2
|
||||
|
||||
Edit reflection list
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use ``showref`` to show the reflection list::
|
||||
|
||||
>>> showref
|
||||
energy h k l alpha delta gamma omega chi phi tag
|
||||
1 9.999 1.00 0.00 1.06 5.0000 22.7900 0.0000 1.5520 22.4000 14.2550 1st
|
||||
2 9.999 0.00 1.00 1.06 5.0000 22.7900 0.0000 4.5750 24.2750 101.32000 2nd
|
||||
|
||||
Use ``swapref`` to swap reflections::
|
||||
|
||||
>>> swapref 1 2
|
||||
Recalculating UB matrix.
|
||||
>>> showref
|
||||
energy h k l alpha delta gamma omega chi phi tag
|
||||
1 9.999 0.00 1.00 1.06 5.0000 22.7900 0.0000 4.5750 24.2750 101.3200 2nd
|
||||
2 9.999 1.00 0.00 1.06 5.0000 22.7900 0.0000 1.5520 22.4000 14.2550 1st
|
||||
|
||||
Use ``delref`` to delete a reflection::
|
||||
|
||||
>>> delref 1
|
||||
>>> showref
|
||||
energy h k l alpha delta gamma omega chi phi tag
|
||||
1 9.999 1.00 0.00 1.06 5.0000 22.7900 0.0000 1.5520 22.4000 14.2550 1st
|
||||
|
||||
Calculating a UB matrix
|
||||
-----------------------
|
||||
|
||||
Unless a U or UB matrix has been manually specified, a new UB matrix
|
||||
will be calculated after the second reflection has been found, or
|
||||
whenever one of the first two reflections is changed.
|
||||
|
||||
Use the command ``calcub`` to force the UB matrix to be calculated
|
||||
from the first two reflections.
|
||||
|
||||
If you have misidentified a reflection used for the orientation the
|
||||
resulting UB matrix will be incorrect. Always use the ``checkub``
|
||||
command to check that the computed values agree with the estimated values::
|
||||
|
||||
>>>checkub
|
||||
energy h k l h_comp k_comp l_comp tag
|
||||
1 9.9987 1.00 0.00 1.06 1.0000 0.0000 1.0628 1st
|
||||
2 9.9987 0.00 1.00 1.06 -0.0329 1.0114 1.0400 2nd
|
||||
|
||||
Notice that the first reflection will always match, but that the
|
||||
second will not match exactly. (The system of equations used to
|
||||
calculate the U matrix is overdetermined and some information from the
|
||||
second reflection is thrown away.)
|
||||
|
||||
Manually setting U and UB
|
||||
-------------------------
|
||||
|
||||
*To help find the initial reflections* it may be useful to set the U
|
||||
matrix manually---to the identity matrix for example. Use the ``setu``
|
||||
command to do this. Once set the diffractometer may be driven to the
|
||||
ideal location of a reflection and then the actual reflection
|
||||
sought. Normally this would be done in the default mode, four-circle-bisecting, (see
|
||||
:ref:`moving-in-hkl-space`). In the following example this has been done
|
||||
by setting the alpha to 5 and leaving gamma at 0 (it would be normal
|
||||
to leave alpha at 0)::
|
||||
|
||||
>>> hklmode 1
|
||||
1) fourc bisecting
|
||||
alpha: 0.0
|
||||
gamma: 0.0
|
||||
|
||||
>>> setalpha 5
|
||||
alpha: 0 --> 5.000000
|
||||
>>> setu
|
||||
row1[1 0 0]:
|
||||
row2[0 1 0]:
|
||||
row3[0 0 1]:
|
||||
>>> sim hkl [1,0,1.0628] # Check it all makes sense
|
||||
sixc would move to:
|
||||
alpha : 5.00000 deg
|
||||
delta : 22.79026 deg
|
||||
gamma : 0.00000 deg
|
||||
omega : 5.82845 deg
|
||||
chi : 24.57658 deg
|
||||
phi : 6.14137 deg
|
||||
|
||||
theta : 70702.991919
|
||||
2theta : 23.303705
|
||||
Bin : 6.969151
|
||||
Bout : 6.969151
|
||||
azimuth : 7.262472
|
||||
|
||||
>>> pos hkl [1,0,1.0628]
|
||||
hkl: h: 1.00000 k: 0.00000 l: 1.06280
|
||||
|
||||
>>> # scan about to find actual reflection
|
||||
|
||||
>>> addref
|
||||
h[0.0]: 1
|
||||
k[0.0]: 0
|
||||
l[0.0]: 1.0628
|
||||
current pos[y]: y
|
||||
tag: 'ref1'
|
||||
>>>
|
||||
|
||||
|
||||
There is currently no way to refine a manually specified U matrix by
|
||||
inferring as much as possible from just one found reflection.
|
||||
|
||||
.. _moving-in-hkl-space:
|
||||
|
||||
Moving in hkl space
|
||||
===================
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven
|
||||
in hkl coordinates. A given diffractometer setting maps easily into a
|
||||
single hkl value. However for a diffractometer with more than three circles
|
||||
there are excess degrees of freedom when calculating a diffractometer
|
||||
setting from an hkl value. Diffcalc provides many for using up
|
||||
the excess degrees of freedom.
|
||||
|
||||
By default Diffcalc selects four-circle bisecting mode (see below).
|
||||
|
||||
Note that to play along with the following ``run`` the file in
|
||||
``example/session/sixc_example.py`` to configure the UB-calculation.
|
||||
|
||||
|
||||
Modes
|
||||
-----
|
||||
|
||||
Use the command ``hklmode`` to summarise the state of Diffcalc's angle
|
||||
calculator. It shows a list the available modes for your
|
||||
diffractometer and the parameters that must be fixed for each, the
|
||||
current mode and the current parameter settings::
|
||||
|
||||
>>> hklmode
|
||||
Available modes:
|
||||
0) fourc fixed-bandlw (alpha, gamma, blw) (Not impl.)
|
||||
1) fourc bisecting (alpha, gamma)
|
||||
2) fourc incoming (alpha, gamma, betain)
|
||||
3) fourc outgoing (alpha, gamma, betaout)
|
||||
4) fourc azimuth (alpha, gamma, azimuth) (Not impl.)
|
||||
5) fourc fixed-phi (alpha, gamma, phi) (Not impl.)
|
||||
10) fivec bisecting (gamma)
|
||||
11) fivec incoming (gamma, betain)
|
||||
12) fivec outgoing (gamma, betaout)
|
||||
13) fivec bisecting (alpha)
|
||||
14) fivec incoming (alpha, betain)
|
||||
15) fivec outgoing (alpha, betaout)
|
||||
20) zaxis bisecting ()
|
||||
21) zaxis incoming (betain)
|
||||
22) zaxiz outgoing (betaout)
|
||||
|
||||
Current mode:
|
||||
|
||||
1) fourc bisecting
|
||||
Parameters:
|
||||
|
||||
alpha: 0.0
|
||||
gamma: 0.0
|
||||
betain: --- (not relevant in this mode)
|
||||
betaout: --- (not relevant in this mode)
|
||||
azimuth: --- (not relevant in this mode)
|
||||
phi: --- (not relevant in this mode)
|
||||
blw: --- (not relevant in this mode)
|
||||
|
||||
Note that 'Not impl.' is short for 'not implemented'. Standby.
|
||||
|
||||
Your output may differ. For example:
|
||||
|
||||
- When listed with a typical five-circle diffractometer with no gamma
|
||||
circle: the fourc modes will have no gamma parameter to fix
|
||||
(actually it will have been fixed under the covers to 0), there
|
||||
will be no gamma or alpha parameters to fix in the five circle
|
||||
modes (again, under the covers gamma will have been fixed) and
|
||||
there will be no zaxis modes (as these require six circles, or an
|
||||
actual z-axis diffractometer).
|
||||
|
||||
- When listed with a typical four-circle diffractometer with no alpha
|
||||
or gamma circle, the four-circle modes will appear with no alpha or
|
||||
gamma parameters (again, they are fixed under the covers), and
|
||||
there will be no five circle or zaxis modes.
|
||||
|
||||
To change the current mode, call ``hklmode`` with an argument::
|
||||
|
||||
>>> hklmode 2
|
||||
2) fourc incoming
|
||||
alpha: 0.0
|
||||
gamma: 0.0
|
||||
betain: ---
|
||||
|
||||
(The dashes next to the betain parameter indicate that a parameter
|
||||
has not yet been set.)
|
||||
|
||||
Mode parameters
|
||||
---------------
|
||||
|
||||
A parameter can be set using either one of the series of {{{set}}}
|
||||
commands, by moving one of the scannables associated with each
|
||||
parameter or, where appropriate, by asking that a parameter track an
|
||||
axis.
|
||||
|
||||
Set commands
|
||||
~~~~~~~~~~~~
|
||||
Use the series of commands ``set<param_name>`` to set a parameter::
|
||||
|
||||
>>> setalpha 3
|
||||
alpha: 0 --> 3.000000
|
||||
>>> setbetain 5
|
||||
WARNING: The parameter betain is not used in mode 1
|
||||
betain: --- --> 5.000000
|
||||
>>> setalpha # With no args, the current value is displayed
|
||||
alpha: 3
|
||||
>>> setbetain
|
||||
betain: ---
|
||||
|
||||
|
||||
Parameter Scannables
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In most installations there will be a scannable for each parameter. In
|
||||
this example installation, the parameters which correspond to physical
|
||||
axes have had '_par' appended to their names to prevent clashes. These
|
||||
may be used to change a parameter either with the ``pos`` command or
|
||||
by using them within a scan (see :ref:`scanning-in-hkl-space`).::
|
||||
|
||||
>>> pos betain
|
||||
betain: 0.00000
|
||||
>>> pos betain 5
|
||||
betain: 5.00000
|
||||
>>> setbetain
|
||||
betain: 5
|
||||
|
||||
>>> pos alpha_par
|
||||
alpha_par:3.00000
|
||||
>>> setalpha
|
||||
alpha: 3
|
||||
|
||||
|
||||
Tracking Axis
|
||||
~~~~~~~~~~~~~
|
||||
Where a parameter matches an axis name, that parameter may be set to
|
||||
track that axis::
|
||||
|
||||
>>> pos alpha
|
||||
alpha: 5.0000
|
||||
|
||||
>>> hklmode 1
|
||||
1) fourc bisecting
|
||||
alpha: 0.0
|
||||
gamma: 0.0
|
||||
|
||||
>>> trackalpha
|
||||
alpha: 5
|
||||
|
||||
>>> pos alpha
|
||||
alpha: 6.0000
|
||||
|
||||
>>> hklmode 1
|
||||
1) fourc bisecting
|
||||
alpha: 6.0 (tracking physical axis)
|
||||
gamma: 0.0
|
||||
|
||||
|
||||
Although convenient, there is a danger with this method that in
|
||||
geometries where the axes are built from other axes (such as in a
|
||||
kappa geometry), the position of an axis may drift slightly during a
|
||||
scan.
|
||||
|
||||
Sectors
|
||||
-------
|
||||
|
||||
When mapping from reciprocal lattice space to a set of diffractometer
|
||||
settings, there is normally a choice of solutions for the sample
|
||||
orientation. The selected sector mode will determine which solution is
|
||||
used. There is currently only one sector mode:
|
||||
|
||||
Sector mode: Find first solution within sector limits
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In this sector mode, taken from 'DIF', the first solution found within
|
||||
the 'sector limits' is chosen. These are different from the physical
|
||||
or software limits on the axes and can be checked/modified using
|
||||
``setsectorlim``::
|
||||
|
||||
>>> setsectorlim
|
||||
omega_high[270]:
|
||||
omega_low[-90]:
|
||||
phi_high[180]:
|
||||
phi_low[-180]:
|
||||
|
||||
|
||||
The hkl scannable
|
||||
-----------------
|
||||
Once a UB matrix has been calculated, a mode chosen and parmeters set,
|
||||
use the hkl scannable to move to a point in reciprocal lattice space::
|
||||
|
||||
>>> pos hkl [1,0,0]
|
||||
hkl: h: 1.00000 k: -0.00000 l: -0.00000
|
||||
>>> pos sixc
|
||||
sixc: alpha: 3.0000 delta: 17.2252 gamma: 4.0000 omega: 7.5046 chi: -24.6257 phi: 4.8026
|
||||
>>> pos hkl
|
||||
hkl: h: 1.00000 k: -0.00000 l: -0.00000
|
||||
>>> hkl
|
||||
hkl:
|
||||
h : 1.000000
|
||||
k : -0.000000
|
||||
l : -0.000000
|
||||
2theta : 18.582618
|
||||
Bin : -0.387976
|
||||
Bout : -0.387976
|
||||
azimuth : 1.646099
|
||||
|
||||
Notice that typing ``hkl`` will also display some virtual angles (such
|
||||
as twotheta and Bin), that checking the position with ``pos hkl`` will
|
||||
not.
|
||||
|
||||
To get this extra information into a scan use the scannable hklverbose
|
||||
instead of hkl::
|
||||
|
||||
>>> pos hklverbose [1,0,0]
|
||||
hklverbose: h: 1.00000 k: -0.00000 l: -0.00000 2theta : 18.582618 Bin : -0.387976
|
||||
Bout :-0.387976 azimuth : 1.646099
|
||||
|
||||
The ``sim`` command will report, without moving the diffractometer,
|
||||
where an hkl position would be found::
|
||||
|
||||
>>> sim hkl [1,0,0]
|
||||
sixc would move to:
|
||||
alpha : 3.00000 deg
|
||||
delta : 17.22516 deg
|
||||
gamma : 4.00000 deg
|
||||
omega : 7.50461 deg
|
||||
chi : -24.62568 deg
|
||||
phi : 4.80260 deg
|
||||
|
||||
theta : 70702.991919
|
||||
2theta : 18.582618
|
||||
Bin : -0.387976
|
||||
Bout : -0.387976
|
||||
azimuth : 1.646099
|
||||
|
||||
|
||||
|
||||
Moving out of range
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Not every hkl position can be reached::
|
||||
|
||||
>>> pos hkl [10,10,10]
|
||||
Exception: Could not compute delta for this hkl position
|
||||
|
||||
The diffractometer scannable (sixc)
|
||||
-----------------------------------
|
||||
We've seen this before, but it also works with sim::
|
||||
|
||||
gda>>>sim sixc [3, 17.22516, 4, 7.50461, -24.62568, 4.80260]
|
||||
hkl would move to:
|
||||
h : 1.000000
|
||||
k : 0.000000
|
||||
l : -0.000000
|
||||
|
||||
.. _scanning-in-hkl-space:
|
||||
|
||||
Scanning in hkl space
|
||||
=====================
|
||||
|
||||
All scans described below use the same generic scanning mechanism
|
||||
provided by the GDA system or by minigda. Here are some examples.
|
||||
|
||||
Fixed hkl scans
|
||||
---------------
|
||||
|
||||
In a 'fixed hkl scan' something (such as energy or Bin) is scanned,
|
||||
and at each step hkl is 'moved' to keep the sample and detector
|
||||
aligned. Also plonk the diffractometer scannable (sixc) on there with no
|
||||
destination to monitor what is actually happening and then
|
||||
throw on a detector (cnt) with an exposure time if appropriate::
|
||||
|
||||
>>> #scan scannable_name start stop step [scannable_name [pos or time]]..
|
||||
|
||||
>>> scan en 9 11 .5 hkl [1,0,0] sixc cnt 1
|
||||
|
||||
>>> scan en 9 11 .5 hklverbose [1,0,0] sixc cnt 1
|
||||
|
||||
>>> scan betain 4 5 .2 hkl [1,0,0] sixc cnt 1
|
||||
|
||||
>>> scan alpha_par 0 10 2 hkl [1,0,0] sixc cnt 1
|
||||
|
||||
>>> trackalpha
|
||||
>>> scan alpha 0 10 2 hkl [1,0,0] sixc cnt 1 # Equivalent to last scan
|
||||
|
||||
Scanning hkl
|
||||
------------
|
||||
|
||||
Hkl, or one component, may also be scanned directly::
|
||||
|
||||
>>> scan h .8 1.2 .1 hklverbose sixc cnt 1
|
||||
|
||||
At each step, this will read the current hkl position, modify the h
|
||||
component and then move to the resulting vector. There is a danger
|
||||
that with this method k and l may drift. To get around this the start,
|
||||
stop and step values may also be specified as vectors. So for example::
|
||||
|
||||
>>> scan hkl [1,0,0] [1,.3,0] [1,0.1,0] cnt1
|
||||
|
||||
is equivilant to::
|
||||
|
||||
>>> pos hkl [1,0,0]
|
||||
>>> scan k 0 .3 .1 cnt1
|
||||
|
||||
but will not suffer from drifting. This method also allows scans along
|
||||
any direction in hkl space to be performed.
|
||||
|
||||
Multidimension scans
|
||||
--------------------
|
||||
|
||||
Two and three dimensional scans::
|
||||
|
||||
>>> scan en 9 11 .5 h .9 1.1 .2 hklverbose sixc cnt 1
|
||||
>>> scan h 1 3 1 k 1 3 1 l 1 3 1 hkl cnt 1
|
||||
|
||||
|
||||
|
||||
Good luck --- RobW
|
||||
786
script/__Lib/diffcalc_old/doc/source/youmanual.rst
Normal file
786
script/__Lib/diffcalc_old/doc/source/youmanual.rst
Normal file
@@ -0,0 +1,786 @@
|
||||
################################
|
||||
Diffcalc User Guide (You Engine)
|
||||
################################
|
||||
|
||||
.. rubric:: Diffcalc: A diffraction condition calculator for diffractometer control
|
||||
|
||||
:Author: Rob Walton
|
||||
:Contact: rob.walton (at) diamond (dot) ac (dot) uk
|
||||
:Website: https://github.com/DiamondLightSource/diffcalc
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
See also the `quickstart guide at github <https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst>`_
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This manual assumes that you are running Diffcalc within OpenGDA or have started
|
||||
it using IPython. It assumes that Diffcalc has been configured for the six
|
||||
circle diffractometer pictured here:
|
||||
|
||||
.. figure:: youmanual_images/4s_2d_diffractometer.png
|
||||
:scale: 100
|
||||
:align: center
|
||||
|
||||
4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
|
||||
Your Diffcalc configuration may have been customised for the geometry of your
|
||||
diffractometer and possibly the types of experiment you perform. For example, a
|
||||
five-circle diffractometer might be missing the nu circle above.
|
||||
|
||||
The laboratory frame is shown above. With all settings at zero as shown the
|
||||
crystal cartesian frame aligns with the laboratory frame. Therefor a cubic
|
||||
crystal mounted squarely in a way that the U matrix (defined below) is unitary
|
||||
will have h||a||x, k||b||y & l||c||z, crystal and reciprocal-lattice coordinate
|
||||
frames are defined with respect to the beam and to gravity to be (for a cubic
|
||||
crystal):
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The following assumes that the diffractometer has been properly leveled, aligned
|
||||
with the beam and zeroed. See the `SPEC fourc manual
|
||||
<http://www.certif.com/spec_manual/fourc_4_2.html>`__.
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by specifying the
|
||||
crystal's lattice parameters (which define the B matrix) and finding two
|
||||
reflections (from which the U matrix defining any mismount can be inferred);
|
||||
and, optionally for surface-diffraction experiments, determine how the surface
|
||||
of the crystal is oriented with respect to the phi axis.
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven in hkl
|
||||
coordinates. A valid diffractometer setting maps easily into a single hkl value.
|
||||
However for a diffractometer with more than three circles there are excess
|
||||
degrees of freedom when calculating a diffractometer setting from an hkl value.
|
||||
Diffcalc provides modes for using up the excess degrees of freedom.
|
||||
|
||||
Diffcalc does not perform scans directly. Instead, Scannables that use diffcalc
|
||||
to map between reciprocal lattice space and real diffractometer settings are
|
||||
scanned using the Gda's (or minigda's) generic scan mechanism.
|
||||
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
Thanks to Elias Vlieg for sharing his dos based ``DIF`` software that Diffcalc
|
||||
has borrowed heavily from. The version of Diffcalc described here is based on papers by
|
||||
pHH. You. [You1999]_ and Busing & Levy [Busing1967]_. (See also the THANKS.txt file.)
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
There are few commands to remember. If a command is called without
|
||||
arguments in some cases Diffcalc will prompt for arguments and provide sensible
|
||||
defaults which can be chosen by pressing enter.
|
||||
|
||||
|
||||
**Orientation**. The ``helpub`` command lists all commands related with crystal
|
||||
orientation and the reference vector (often used with surfaces). See the
|
||||
`Orientation Commands`_ section at the end of this manual::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
|
||||
|
||||
**HKL movement**. The ``help hkl`` list all commands related to moving in reciprocal-lattice
|
||||
space. See the `Motion Commands`_ section at the end of this manual::
|
||||
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
|
||||
Call help on any command. e.g.::
|
||||
|
||||
>>> help loadub
|
||||
loadub (diffcalc command):
|
||||
loadub 'name' | num -- load an existing ub calculation
|
||||
|
||||
Diffcalc's Scannables
|
||||
=====================
|
||||
|
||||
To list and show the current positions of your beamline's scannables
|
||||
use ``pos`` with no arguments::
|
||||
|
||||
>>> pos
|
||||
|
||||
Results in:
|
||||
|
||||
**Energy and wavelength scannables**::
|
||||
|
||||
energy 12.3984
|
||||
wl: 1.0000
|
||||
|
||||
**Diffractometer scannables**, as a group and in component axes (in
|
||||
the real GDA these have limits)::
|
||||
|
||||
sixc: mu: 0.0000 delta: 0.0000 gamma: 0.0000 omega: 0.0000 chi: 0.0000 phi: 0.0000
|
||||
mu: 0.0000
|
||||
chi: 0.0000
|
||||
delta: 0.0000
|
||||
gamma: 0.0000
|
||||
omega: 0.0000
|
||||
phi: 0.0000
|
||||
|
||||
**Dummy counter**, which in this example simply counts at 1hit/s::
|
||||
|
||||
ct: 0.0000
|
||||
|
||||
**Hkl scannable**, as a group and in component::
|
||||
|
||||
hkl: Error: No UB matrix
|
||||
h: Error: No UB matrix
|
||||
k: Error: No UB matrix
|
||||
l: Error: No UB matrix
|
||||
|
||||
**Parameter scannables**, used in some modes, these provide a
|
||||
scannable alternative to the `Motion`_ section. Some constrain of
|
||||
these constrain virtual angles::
|
||||
|
||||
alpha: ---
|
||||
beta: ---
|
||||
naz: ---
|
||||
psi: ---
|
||||
qaz: ---
|
||||
|
||||
and some constrain physical angles::
|
||||
|
||||
phi_con: ---
|
||||
chi_con: ---
|
||||
delta_con:---
|
||||
eta_con: ---
|
||||
gam_con: ---
|
||||
mu_con: ---
|
||||
|
||||
|
||||
Crystal orientation
|
||||
===================
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by specifying the
|
||||
crystal's lattice parameters (which define the B matrix) and finding two
|
||||
reflections (from which the U matrix can be inferred); and, optionally for
|
||||
surface-diffraction experiments, determine how the surface of the crystal is
|
||||
oriented with respect to the phi axis.
|
||||
|
||||
Start a new UB calculation
|
||||
--------------------------
|
||||
|
||||
A *UB calculation* contains the description of the crystal-under-test,
|
||||
any saved reflections, reference angle direction, and a B & UB
|
||||
matrix pair if they have been calculated or manually specified.
|
||||
Starting a new UB calculation will clear all of these.
|
||||
|
||||
Before starting a UB-calculation, the ``ub`` command used to summarise
|
||||
the state of the current UB-calculation, will reflect that no
|
||||
UB-calculation has been started::
|
||||
|
||||
>>> ub
|
||||
<<< No UB calculation started >>>
|
||||
|
||||
A new UB-calculation calculation may be started and lattice specified
|
||||
explicitly::
|
||||
|
||||
>>> newub 'example'
|
||||
>>> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
or interactively::
|
||||
|
||||
>>> newub
|
||||
calculation name: example
|
||||
crystal name: 1Acube
|
||||
a [1]: 1
|
||||
b [1]: 1
|
||||
c [1]: 1
|
||||
alpha [90]: 90
|
||||
beta [90]: 90
|
||||
gamma [90]: 90
|
||||
|
||||
where a,b and c are the lengths of the three unit cell basis vectors
|
||||
in Angstroms, and alpha, beta and gamma are angles in Degrees.
|
||||
|
||||
The ``ub`` command will show the state of the current UB-calculation
|
||||
(and the current energy for reference)::
|
||||
|
||||
>>> ub
|
||||
UBCALC
|
||||
|
||||
name: example
|
||||
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
|
||||
CRYSTAL
|
||||
|
||||
name: 1Acube
|
||||
|
||||
a, b, c: 1.00000 1.00000 1.00000
|
||||
90.00000 90.00000 90.00000
|
||||
|
||||
B matrix: 6.28319 0.00000 0.00000
|
||||
0.00000 6.28319 0.00000
|
||||
0.00000 0.00000 6.28319
|
||||
|
||||
UB MATRIX
|
||||
|
||||
<<< none calculated >>>
|
||||
|
||||
REFLECTIONS
|
||||
|
||||
<<< none specified >>>
|
||||
|
||||
Load a UB calculation
|
||||
---------------------
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
Generate a U matrix from two reflections
|
||||
----------------------------------------
|
||||
|
||||
The normal way to calculate a U matrix is to find the position of **two**
|
||||
reflections with known hkl values. Diffcalc allows many reflections to be
|
||||
recorded but currently only uses the first two when calculating a UB matrix.
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
>>> pos wl 1
|
||||
wl: 1.0000
|
||||
>>> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
>>> pos sixc [0 60 0 30 90 0]
|
||||
sixc: mu: 0.0000 delta: 60.0000 gam: 0.0000 eta: 30.0000 chi: 90.0000 phi: 0.0000
|
||||
>>> addref [0 0 1]
|
||||
|
||||
>>> pos sixc [0 90 0 45 45 90]
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
>>> addref [0 1 1]
|
||||
Calculating UB matrix.
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
>>> checkub
|
||||
|
||||
ENERGY H K L H_COMP K_COMP L_COMP TAG
|
||||
1 12.3984 0.00 0.00 1.00 0.0000 0.0000 1.0000
|
||||
2 12.3984 0.00 1.00 1.00 0.0000 1.0000 1.0000
|
||||
|
||||
Generate a U matrix from one reflection
|
||||
---------------------------------------
|
||||
|
||||
To estimate based on first reflection only::
|
||||
|
||||
>>> trialub
|
||||
resulting U angle: 0.00000 deg
|
||||
resulting U axis direction: [-1.00000, 0.00000, 0.00000]
|
||||
Recalculating UB matrix from the first reflection only.
|
||||
NOTE: A new UB matrix will not be automatically calculated when the orientation reflections are modified.
|
||||
|
||||
Manually specify U matrix
|
||||
-------------------------
|
||||
|
||||
Set U matrix manually (pretending sample is squarely mounted)::
|
||||
|
||||
>>> setu [[1 0 0] [0 1 0] [0 0 1]]
|
||||
Recalculating UB matrix.
|
||||
NOTE: A new UB matrix will not be automatically calculated when the orientation reflections are modified.
|
||||
|
||||
Edit reflection list
|
||||
--------------------
|
||||
|
||||
Use ``showref`` to show the reflection list::
|
||||
|
||||
>>> showref
|
||||
ENERGY H K L MU DELTA GAM ETA CHI PHI TAG
|
||||
1 12.398 0.00 0.00 1.00 0.0000 60.0000 0.0000 30.0000 90.0000 0.0000
|
||||
2 12.398 0.00 1.00 1.00 0.0000 90.0000 0.0000 45.0000 45.0000 90.0000
|
||||
|
||||
Use ``swapref`` to swap reflections::
|
||||
|
||||
>>> swapref 1 2
|
||||
Not calculating UB matrix as it has been manually set. Use 'calcub' to explicitly recalculate it.
|
||||
Recalculating UB matrix.
|
||||
|
||||
Use ``delref`` to delete a reflection::
|
||||
|
||||
>>> delref 1
|
||||
|
||||
Calculate a UB matrix
|
||||
---------------------
|
||||
|
||||
Unless a U or UB matrix has been manually specified, a new UB matrix will be
|
||||
calculated after the second reflection has been found, or whenever one of the
|
||||
first two reflections is changed.
|
||||
|
||||
Use the command ``calcub`` to force the UB matrix to be calculated from the
|
||||
first two reflections.
|
||||
|
||||
If you have misidentified a reflection used for the orientation the
|
||||
resulting UB matrix will be incorrect. Always use the ``checkub``
|
||||
command to check that the computed values agree with the estimated values::
|
||||
|
||||
>>> checkub
|
||||
|
||||
ENERGY H K L H_COMP K_COMP L_COMP TAG
|
||||
1 12.3984 0.00 1.00 1.00 0.0000 1.0000 1.0000
|
||||
2 12.3984 0.00 0.00 1.00 0.0000 0.0000 1.0000
|
||||
|
||||
Set the reference vector
|
||||
-------------------------
|
||||
|
||||
When performing surface experiments the reference vector should be set normal
|
||||
to the surface. It can also be used to define other directions within the crystal
|
||||
with which we want to orient the incident or diffracted beam.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
The ``<- set`` label here indicates that the reference vector is set in the phi
|
||||
coordinate frame. In this case, therefor, its direction in the crystal's
|
||||
reciprocal lattice space is inferred from the UB matrix.
|
||||
|
||||
To set the reference vector in the phi coordinate frame use::
|
||||
|
||||
>>> setnphi [0 0 1]
|
||||
...
|
||||
|
||||
This is useful if the surface normal has be found with a laser or by x-ray
|
||||
occlusion. This vector must currently be manually calculated from the sample
|
||||
angle settings required to level the surface (sigma and tau commands on the
|
||||
way).
|
||||
|
||||
To set the reference vector in the crystal's reciprocal lattice space use (this
|
||||
is a quick way to determine the surface orientation if the surface is known to
|
||||
be cleaved cleanly along a known axis)::
|
||||
|
||||
>>> setnhkl [0 0 1] ...
|
||||
|
||||
Motion
|
||||
======
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven
|
||||
in hkl coordinates. A given diffractometer setting maps easily into a
|
||||
single hkl value. However for a diffractometer with more than three circles
|
||||
there are excess degrees of freedom when calculating a diffractometer
|
||||
setting from an hkl value. Diffcalc provides many for using up
|
||||
the excess degrees of freedom.
|
||||
|
||||
By default Diffcalc selects no mode.
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
>>> con
|
||||
DET REF SAMP
|
||||
------ ------ ------
|
||||
delta a_eq_b mu
|
||||
gam alpha eta
|
||||
qaz beta chi
|
||||
naz psi phi
|
||||
mu_is_gam
|
||||
|
||||
! 3 more constraints required
|
||||
|
||||
Type 'help con' for instructions
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
In the following the *scattering plane* is defined as the plane including the
|
||||
scattering vector, or momentum transfer vector, and the incident beam.
|
||||
|
||||
**DETECTOR COLUMN:**
|
||||
|
||||
- **delta** - physical delta setting (vertical detector motion) *del=0 is equivalent to qaz=0*
|
||||
- **gam** - physical gamma setting (horizontal detector motion) *gam=0 is equivalent to qaz=90*
|
||||
- **qaz** - azimuthal rotation of scattering vector (about the beam, from horizontal)
|
||||
- **naz** - azimuthal rotation of reference vector (about the beam, from horizontal)
|
||||
|
||||
**REFERENCE COLUMN:**
|
||||
|
||||
- **alpha** - incident angle to surface (if reference is normal to surface)
|
||||
- **beta** - exit angle from surface (if reference is normal to surface)
|
||||
- **psi** - azimuthal rotation about scattering vector of reference vector (from scattering plane)
|
||||
- **a_eq_b** - bisecting mode with alpha=beta. *Equivalent to psi=90*
|
||||
|
||||
**SAMPLE COLUMN:**
|
||||
|
||||
- **mu, eta, chi & phi** - physical settings
|
||||
- **mu_is_gam** - force mu to follow gamma (results in a 5-circle geometry)
|
||||
|
||||
Diffcalc will report two other (un-constrainable) virtual angles:
|
||||
|
||||
- **theta** - half of 2theta, the angle through the diffracted beam bends
|
||||
- **tau** - longitude of reference vector from scattering vector (in scattering plane)
|
||||
|
||||
Example constraint modes
|
||||
------------------------
|
||||
|
||||
There is sometimes more than one way to get the same effect.
|
||||
|
||||
**Vertical four-circle mode**::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b # or equivalently:
|
||||
>>> con qaz 90 mu 0 a_eq_b
|
||||
|
||||
>>> con alpha 1 # replaces a_eq_b
|
||||
|
||||
**Horizontal four-circle mode**::
|
||||
|
||||
>>> con del 0 eta 0 alpha 1 # or equivalently:
|
||||
>>> con qaz 0 mu 0 alpha 1
|
||||
|
||||
**Surface vertical mode**::
|
||||
|
||||
>>> con naz 90 mu 0 alpha 1
|
||||
|
||||
**Surface horizontal mode**::
|
||||
|
||||
>>> con naz 0 eta 0 alpha 1
|
||||
|
||||
**Z-axis mode (surface horizontal)**::
|
||||
|
||||
>>> con chi (-sigma) phi (-tau) alpha 1
|
||||
|
||||
where sigma and tau are the offsets required in chi and phi to bring the surface
|
||||
normal parallel to eta. Alpha will determine mu directly leaving eta to orient
|
||||
the planes. Or::
|
||||
|
||||
>>> con naz 0 phi 0 alpha 1 # or any another sample angle
|
||||
|
||||
**Z-axis mode (surface vertical)**::
|
||||
|
||||
>>> con naz 0 phi 0 alpha 1 # or any another sample angle
|
||||
|
||||
Changing constrained values
|
||||
---------------------------
|
||||
|
||||
Once constraints are chosen constrained values may be changed directly::
|
||||
|
||||
>>> con mu 10
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 10.0000
|
||||
|
||||
or via the associated scannable::
|
||||
|
||||
>>> pos mu_con 10
|
||||
mu_con: 10.00000
|
||||
|
||||
Configuring limits and cuts
|
||||
---------------------------
|
||||
|
||||
Diffcalc maintains its own limits on axes. These limits will be used when
|
||||
choosing solutions. If more than one detector solution is exists Diffcalc will
|
||||
ask you to reduce the the limits until there is only one. However if more than
|
||||
one solution for the sample settings is available it will choose one base on
|
||||
heuristics.
|
||||
|
||||
Use the ``hardware`` command to see the current limits and cuts::
|
||||
|
||||
>>> hardware
|
||||
mu (cut: -180.0)
|
||||
delta (cut: -180.0)
|
||||
gam (cut: -180.0)
|
||||
eta (cut: -180.0)
|
||||
chi (cut: -180.0)
|
||||
phi (cut: 0.0)
|
||||
Note: When auto sector/transforms are used,
|
||||
cuts are applied before checking limits.
|
||||
|
||||
To set the limits::
|
||||
|
||||
>>> setmin delta -1
|
||||
>>> setmax delta 145
|
||||
|
||||
To set a cut::
|
||||
|
||||
>>> setcut phi -180
|
||||
|
||||
This causes requests to move phi to be between the configured -180 and +360
|
||||
degress above this. i.e. it might dive to -10 degrees rather than 350.
|
||||
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Configure a mode, e.g. four-circle vertical::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b
|
||||
gam : 0.0000
|
||||
a_eq_b
|
||||
mu : 0.0000
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
>>> sim hkl [0 1 1]
|
||||
sixc would move to:
|
||||
mu : 0.0000
|
||||
delta : 90.0000
|
||||
gam : 0.0000
|
||||
eta : 45.0000
|
||||
chi : 45.0000
|
||||
phi : 90.0000
|
||||
|
||||
alpha : 30.0000
|
||||
beta : 30.0000
|
||||
naz : 35.2644
|
||||
psi : 90.0000
|
||||
qaz : 90.0000
|
||||
tau : 45.0000
|
||||
theta : 45.0000
|
||||
|
||||
Move to reflection::
|
||||
|
||||
>>> pos hkl [0 1 1]
|
||||
hkl: h: 0.00000 k: 1.00000 l: 1.00000
|
||||
|
||||
>>> pos sixc
|
||||
sixc: mu: 0.0000 delta: 90.0000 gam: 0.0000 eta: 45.0000 chi: 45.0000 phi: 90.0000
|
||||
|
||||
Simulate moving to a location::
|
||||
|
||||
>>> pos sixc [0 60 0 30 90 0]
|
||||
sixc: mu: 0.0000 delta: 60.0000 gam: 0.0000 eta: 30.0000 chi: 90.0000 phi: 0.0000
|
||||
|
||||
Scanning in hkl space
|
||||
=====================
|
||||
|
||||
All scans described below use the same generic scanning mechanism
|
||||
provided by the GDA system or by minigda. Here are some examples.
|
||||
|
||||
Fixed hkl scans
|
||||
---------------
|
||||
|
||||
In a 'fixed hkl scan' something (such as energy or Bin) is scanned,
|
||||
and at each step hkl is 'moved' to keep the sample and detector
|
||||
aligned. Also plonk the diffractometer scannable (sixc) on there with no
|
||||
destination to monitor what is actually happening and then
|
||||
throw on a detector (ct) with an exposure time if appropriate::
|
||||
|
||||
>>> #scan scannable_name start stop step [scannable_name [pos or time]]..
|
||||
|
||||
>>> scan en 9 11 .5 hkl [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan en 9 11 .5 hklverbose [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan betain 4 5 .2 hkl [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan alpha_par 0 10 2 hkl [1 0 0] sixc ct 1
|
||||
|
||||
Scanning hkl
|
||||
------------
|
||||
|
||||
Hkl, or one component, may also be scanned directly::
|
||||
|
||||
>>> scan h .8 1.2 .1 hklverbose sixc ct 1
|
||||
|
||||
At each step, this will read the current hkl position, modify the h
|
||||
component and then move to the resulting vector. There is a danger
|
||||
that with this method k and l may drift. To get around this the start,
|
||||
stop and step values may also be specified as vectors. So for example::
|
||||
|
||||
>>> scan hkl [1 0 0] [1 .3 0] [1 0.1 0] ct1
|
||||
|
||||
is equivilant to::
|
||||
|
||||
>>> pos hkl [1 0 0]
|
||||
>>> scan k 0 .3 .1 ct1
|
||||
|
||||
but will not suffer from drifting. This method also allows scans along
|
||||
any direction in hkl space to be performed.
|
||||
|
||||
Multidimension scans
|
||||
--------------------
|
||||
|
||||
Two and three dimensional scans::
|
||||
|
||||
>>> scan en 9 11 .5 h .9 1.1 .2 hklverbose sixc ct 1
|
||||
>>> scan h 1 3 1 k 1 3 1 l 1 3 1 hkl ct 1
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **STATE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- newub** {'name'} | start a new ub calculation name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- loadub** 'name' | num | load an existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- lastub** | load the last used ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- listub** | list the ub calculations available to load |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- rmub** 'name'|num | remove existing ub calculation |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- saveubas** 'name' | save the ub calculation with a new name |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **LATTICE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** | interactively enter lattice parameters (Angstroms |
|
||||
| | and Deg) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a | assumes cubic |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b | assumes tetragonal |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes ortho |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | assumes mon/hex with gam not equal to 90 |
|
||||
| gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setlat** name a b c | arbitrary |
|
||||
| alpha beta gamma | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- c2th** [h k l] | calculate two-theta angle for reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFERENCE (SURFACE)** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnphi** {[x y z]} | sets or displays n_phi reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setnhkl** {[h k l]} | sets or displays n_hkl reference |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **REFLECTIONS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- showref** | shows full reflection list |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** | add reflection interactively |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] | add reflection with current position and energy |
|
||||
| {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- addref** [h k l] (p1, | add arbitrary reflection |
|
||||
| .., pN) energy {'tag'} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- editref** num | interactively edit a reflection |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- delref** num | deletes a reflection (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- clearref** | deletes all the reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** | swaps first two reflections used for calulating U |
|
||||
| | matrix |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- swapref** num1 num2 | swaps two reflections (numbered from 1) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **UB MATRIX** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- checkub** | show calculated and entered hkl values for |
|
||||
| | reflections |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setu** | manually set u matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setub** | manually set ub matrix |
|
||||
| {[[..][..][..]]} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- calcub** | (re)calculate u matrix from ref1 and ref2 |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- trialub** | (re)calculate u matrix from ref1 only (check |
|
||||
| | carefully) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
Motion commands
|
||||
---------------
|
||||
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **CONSTRAINTS** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** | list available constraints and values |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | constrains and optionally sets one constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- con** <name> {val} | clears and then fully constrains |
|
||||
| <name> {val} <name> {val} | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- uncon** <name> | remove constraint |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HKL** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- allhkl** [h k l] | print all hkl solutions ignoring limits |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **HARDWARE** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hardware** | show diffcalc limits and cuts |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setcut** {name {val}} | sets cut angle |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmin** {axis {val}} | set lower limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- setmax** {name {val}} | sets upper limits used by auto sector code (None |
|
||||
| | to clear) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **MOTION** |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl scn | simulates moving scannable (not all) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sixc** | show Eularian position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** sixc [mu, delta, | move to Eularian position(None holds an axis |
|
||||
| gam, eta, chi, phi] | still) |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** sixc [mu, delta, | simulate move to Eulerian positionsixc |
|
||||
| gam, eta, chi, phi] | |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- hkl** | show hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** hkl [h k l] | move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- pos** {h | k | l} val | move h, k or l to val |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
| **-- sim** hkl [h k l] | simulate move to hkl position |
|
||||
+-----------------------------+---------------------------------------------------+
|
||||
|
||||
Good luck --- RobW
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 329 KiB |
565
script/__Lib/diffcalc_old/doc/source/youmanual_template.rst
Normal file
565
script/__Lib/diffcalc_old/doc/source/youmanual_template.rst
Normal file
@@ -0,0 +1,565 @@
|
||||
################################
|
||||
Diffcalc User Guide (You Engine)
|
||||
################################
|
||||
|
||||
.. rubric:: Diffcalc: A diffraction condition calculator for diffractometer control
|
||||
|
||||
:Author: Rob Walton
|
||||
:Contact: rob.walton (at) diamond (dot) ac (dot) uk
|
||||
:Website: https://github.com/DiamondLightSource/diffcalc
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:numbered:
|
||||
|
||||
See also the `quickstart guide at github <https://github.com/DiamondLightSource/diffcalc/blob/master/README.rst>`_
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
This manual assumes that you are running Diffcalc within OpenGDA or have started
|
||||
it using IPython. It assumes that Diffcalc has been configured for the six
|
||||
circle diffractometer pictured here:
|
||||
|
||||
.. figure:: youmanual_images/4s_2d_diffractometer.png
|
||||
:scale: 100
|
||||
:align: center
|
||||
|
||||
4s + 2d six-circle diffractometer, from H.You (1999)
|
||||
|
||||
Your Diffcalc configuration may have been customised for the geometry of your
|
||||
diffractometer and possibly the types of experiment you perform. For example, a
|
||||
five-circle diffractometer might be missing the nu circle above.
|
||||
|
||||
The laboratory frame is shown above. With all settings at zero as shown the
|
||||
crystal cartesian frame aligns with the laboratory frame. Therefor a cubic
|
||||
crystal mounted squarely in a way that the U matrix (defined below) is unitary
|
||||
will have h||a||x, k||b||y & l||c||z, crystal and reciprocal-lattice coordinate
|
||||
frames are defined with respect to the beam and to gravity to be (for a cubic
|
||||
crystal):
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
The following assumes that the diffractometer has been properly leveled, aligned
|
||||
with the beam and zeroed. See the `SPEC fourc manual
|
||||
<http://www.certif.com/spec_manual/fourc_4_2.html>`__.
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by specifying the
|
||||
crystal's lattice parameters (which define the B matrix) and finding two
|
||||
reflections (from which the U matrix defining any mismount can be inferred);
|
||||
and, optionally for surface-diffraction experiments, determine how the surface
|
||||
of the crystal is oriented with respect to the phi axis.
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven in hkl
|
||||
coordinates. A valid diffractometer setting maps easily into a single hkl value.
|
||||
However for a diffractometer with more than three circles there are excess
|
||||
degrees of freedom when calculating a diffractometer setting from an hkl value.
|
||||
Diffcalc provides modes for using up the excess degrees of freedom.
|
||||
|
||||
Diffcalc does not perform scans directly. Instead, Scannables that use diffcalc
|
||||
to map between reciprocal lattice space and real diffractometer settings are
|
||||
scanned using the Gda's (or minigda's) generic scan mechanism.
|
||||
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
Thanks to Elias Vlieg for sharing his dos based ``DIF`` software that Diffcalc
|
||||
has borrowed heavily from. The version of Diffcalc described here is based on papers by
|
||||
pHH. You. [You1999]_ and Busing & Levy [Busing1967]_. (See also the THANKS.txt file.)
|
||||
|
||||
Getting Help
|
||||
============
|
||||
|
||||
There are few commands to remember. If a command is called without
|
||||
arguments in some cases Diffcalc will prompt for arguments and provide sensible
|
||||
defaults which can be chosen by pressing enter.
|
||||
|
||||
|
||||
**Orientation**. The ``helpub`` command lists all commands related with crystal
|
||||
orientation and the reference vector (often used with surfaces). See the
|
||||
`Orientation Commands`_ section at the end of this manual::
|
||||
|
||||
>>> help ub
|
||||
...
|
||||
|
||||
|
||||
**HKL movement**. The ``help hkl`` list all commands related to moving in reciprocal-lattice
|
||||
space. See the `Motion Commands`_ section at the end of this manual::
|
||||
|
||||
>>> help hkl
|
||||
...
|
||||
|
||||
|
||||
Call help on any command. e.g.::
|
||||
|
||||
==> help loadub
|
||||
|
||||
Diffcalc's Scannables
|
||||
=====================
|
||||
|
||||
To list and show the current positions of your beamline's scannables
|
||||
use ``pos`` with no arguments::
|
||||
|
||||
>>> pos
|
||||
|
||||
Results in:
|
||||
|
||||
**Energy and wavelength scannables**::
|
||||
|
||||
energy 12.3984
|
||||
wl: 1.0000
|
||||
|
||||
**Diffractometer scannables**, as a group and in component axes (in
|
||||
the real GDA these have limits)::
|
||||
|
||||
sixc: mu: 0.0000 delta: 0.0000 gamma: 0.0000 omega: 0.0000 chi: 0.0000 phi: 0.0000
|
||||
mu: 0.0000
|
||||
chi: 0.0000
|
||||
delta: 0.0000
|
||||
gamma: 0.0000
|
||||
omega: 0.0000
|
||||
phi: 0.0000
|
||||
|
||||
**Dummy counter**, which in this example simply counts at 1hit/s::
|
||||
|
||||
ct: 0.0000
|
||||
|
||||
**Hkl scannable**, as a group and in component::
|
||||
|
||||
hkl: Error: No UB matrix
|
||||
h: Error: No UB matrix
|
||||
k: Error: No UB matrix
|
||||
l: Error: No UB matrix
|
||||
|
||||
**Parameter scannables**, used in some modes, these provide a
|
||||
scannable alternative to the `Motion`_ section. Some constrain of
|
||||
these constrain virtual angles::
|
||||
|
||||
alpha: ---
|
||||
beta: ---
|
||||
naz: ---
|
||||
psi: ---
|
||||
qaz: ---
|
||||
|
||||
and some constrain physical angles::
|
||||
|
||||
phi_con: ---
|
||||
chi_con: ---
|
||||
delta_con:---
|
||||
eta_con: ---
|
||||
gam_con: ---
|
||||
mu_con: ---
|
||||
|
||||
|
||||
Crystal orientation
|
||||
===================
|
||||
|
||||
Before moving in hkl space you must calculate a UB matrix by specifying the
|
||||
crystal's lattice parameters (which define the B matrix) and finding two
|
||||
reflections (from which the U matrix can be inferred); and, optionally for
|
||||
surface-diffraction experiments, determine how the surface of the crystal is
|
||||
oriented with respect to the phi axis.
|
||||
|
||||
Start a new UB calculation
|
||||
--------------------------
|
||||
|
||||
A *UB calculation* contains the description of the crystal-under-test,
|
||||
any saved reflections, reference angle direction, and a B & UB
|
||||
matrix pair if they have been calculated or manually specified.
|
||||
Starting a new UB calculation will clear all of these.
|
||||
|
||||
Before starting a UB-calculation, the ``ub`` command used to summarise
|
||||
the state of the current UB-calculation, will reflect that no
|
||||
UB-calculation has been started::
|
||||
|
||||
==> ub
|
||||
|
||||
A new UB-calculation calculation may be started and lattice specified
|
||||
explicitly::
|
||||
|
||||
==> newub 'example'
|
||||
==> setlat '1Acube' 1 1 1 90 90 90
|
||||
|
||||
or interactively::
|
||||
|
||||
>>> newub
|
||||
calculation name: example
|
||||
crystal name: 1Acube
|
||||
a [1]: 1
|
||||
b [1]: 1
|
||||
c [1]: 1
|
||||
alpha [90]: 90
|
||||
beta [90]: 90
|
||||
gamma [90]: 90
|
||||
|
||||
where a,b and c are the lengths of the three unit cell basis vectors
|
||||
in Angstroms, and alpha, beta and gamma are angles in Degrees.
|
||||
|
||||
The ``ub`` command will show the state of the current UB-calculation
|
||||
(and the current energy for reference)::
|
||||
|
||||
==> ub
|
||||
|
||||
Load a UB calculation
|
||||
---------------------
|
||||
|
||||
To load the last used UB-calculation::
|
||||
|
||||
>>> lastub
|
||||
Loading ub calculation: 'mono-Si'
|
||||
|
||||
To load a previous UB-calculation::
|
||||
|
||||
>>> listub
|
||||
UB calculations in: /Users/walton/.diffcalc/i16
|
||||
|
||||
0) mono-Si 15 Feb 2017 (22:32)
|
||||
1) i16-32 13 Feb 2017 (18:32)
|
||||
|
||||
>>> loadub 0
|
||||
|
||||
Generate a U matrix from two reflections
|
||||
----------------------------------------
|
||||
|
||||
The normal way to calculate a U matrix is to find the position of **two**
|
||||
reflections with known hkl values. Diffcalc allows many reflections to be
|
||||
recorded but currently only uses the first two when calculating a UB matrix.
|
||||
|
||||
Find U matrix from two reflections::
|
||||
|
||||
==> pos wl 1
|
||||
==> c2th [0 0 1]
|
||||
59.99999999999999
|
||||
|
||||
==> pos sixc [0 60 0 30 90 0]
|
||||
==> addref [0 0 1]
|
||||
|
||||
==> pos sixc [0 90 0 45 45 90]
|
||||
==> addref [0 1 1]
|
||||
|
||||
Check that it looks good::
|
||||
|
||||
==> checkub
|
||||
|
||||
Generate a U matrix from one reflection
|
||||
---------------------------------------
|
||||
|
||||
To estimate based on first reflection only::
|
||||
|
||||
==> trialub
|
||||
|
||||
Manually specify U matrix
|
||||
-------------------------
|
||||
|
||||
Set U matrix manually (pretending sample is squarely mounted)::
|
||||
|
||||
==> setu [[1 0 0] [0 1 0] [0 0 1]]
|
||||
|
||||
Edit reflection list
|
||||
--------------------
|
||||
|
||||
Use ``showref`` to show the reflection list::
|
||||
|
||||
==> showref
|
||||
|
||||
Use ``swapref`` to swap reflections::
|
||||
|
||||
==> swapref 1 2
|
||||
Recalculating UB matrix.
|
||||
|
||||
Use ``delref`` to delete a reflection::
|
||||
|
||||
>>> delref 1
|
||||
|
||||
Calculate a UB matrix
|
||||
---------------------
|
||||
|
||||
Unless a U or UB matrix has been manually specified, a new UB matrix will be
|
||||
calculated after the second reflection has been found, or whenever one of the
|
||||
first two reflections is changed.
|
||||
|
||||
Use the command ``calcub`` to force the UB matrix to be calculated from the
|
||||
first two reflections.
|
||||
|
||||
If you have misidentified a reflection used for the orientation the
|
||||
resulting UB matrix will be incorrect. Always use the ``checkub``
|
||||
command to check that the computed values agree with the estimated values::
|
||||
|
||||
==> checkub
|
||||
|
||||
Set the reference vector
|
||||
-------------------------
|
||||
|
||||
When performing surface experiments the reference vector should be set normal
|
||||
to the surface. It can also be used to define other directions within the crystal
|
||||
with which we want to orient the incident or diffracted beam.
|
||||
|
||||
By default the reference vector is set parallel to the phi axis. That is,
|
||||
along the z-axis of the phi coordinate frame.
|
||||
|
||||
The `ub` command shows the current reference vector, along with any inferred
|
||||
miscut, at the top its report (or it can be shown by calling ``setnphi`` or
|
||||
``setnhkl'`` with no args)::
|
||||
|
||||
>>> ub
|
||||
...
|
||||
n_phi: 0.00000 0.00000 1.00000 <- set
|
||||
n_hkl: -0.00000 0.00000 1.00000
|
||||
miscut: None
|
||||
...
|
||||
|
||||
The ``<- set`` label here indicates that the reference vector is set in the phi
|
||||
coordinate frame. In this case, therefor, its direction in the crystal's
|
||||
reciprocal lattice space is inferred from the UB matrix.
|
||||
|
||||
To set the reference vector in the phi coordinate frame use::
|
||||
|
||||
>>> setnphi [0 0 1]
|
||||
...
|
||||
|
||||
This is useful if the surface normal has be found with a laser or by x-ray
|
||||
occlusion. This vector must currently be manually calculated from the sample
|
||||
angle settings required to level the surface (sigma and tau commands on the
|
||||
way).
|
||||
|
||||
To set the reference vector in the crystal's reciprocal lattice space use (this
|
||||
is a quick way to determine the surface orientation if the surface is known to
|
||||
be cleaved cleanly along a known axis)::
|
||||
|
||||
>>> setnhkl [0 0 1] ...
|
||||
|
||||
Motion
|
||||
======
|
||||
|
||||
Once a UB matrix has been calculated, the diffractometer may be driven
|
||||
in hkl coordinates. A given diffractometer setting maps easily into a
|
||||
single hkl value. However for a diffractometer with more than three circles
|
||||
there are excess degrees of freedom when calculating a diffractometer
|
||||
setting from an hkl value. Diffcalc provides many for using up
|
||||
the excess degrees of freedom.
|
||||
|
||||
By default Diffcalc selects no mode.
|
||||
|
||||
Constraining solutions for moving in hkl space
|
||||
----------------------------------------------
|
||||
|
||||
To get help and see current constraints::
|
||||
|
||||
>>> help con
|
||||
...
|
||||
|
||||
==> con
|
||||
|
||||
Three constraints can be given: zero or one from the DET and REF columns and the
|
||||
remainder from the SAMP column. Not all combinations are currently available.
|
||||
Use ``help con`` to see a summary if you run into troubles.
|
||||
|
||||
To configure four-circle vertical scattering::
|
||||
|
||||
==> con gam 0 mu 0 a_eq_b
|
||||
|
||||
In the following the *scattering plane* is defined as the plane including the
|
||||
scattering vector, or momentum transfer vector, and the incident beam.
|
||||
|
||||
**DETECTOR COLUMN:**
|
||||
|
||||
- **delta** - physical delta setting (vertical detector motion) *del=0 is equivalent to qaz=0*
|
||||
- **gam** - physical gamma setting (horizontal detector motion) *gam=0 is equivalent to qaz=90*
|
||||
- **qaz** - azimuthal rotation of scattering vector (about the beam, from horizontal)
|
||||
- **naz** - azimuthal rotation of reference vector (about the beam, from horizontal)
|
||||
|
||||
**REFERENCE COLUMN:**
|
||||
|
||||
- **alpha** - incident angle to surface (if reference is normal to surface)
|
||||
- **beta** - exit angle from surface (if reference is normal to surface)
|
||||
- **psi** - azimuthal rotation about scattering vector of reference vector (from scattering plane)
|
||||
- **a_eq_b** - bisecting mode with alpha=beta. *Equivalent to psi=90*
|
||||
|
||||
**SAMPLE COLUMN:**
|
||||
|
||||
- **mu, eta, chi & phi** - physical settings
|
||||
- **mu_is_gam** - force mu to follow gamma (results in a 5-circle geometry)
|
||||
|
||||
Diffcalc will report two other (un-constrainable) virtual angles:
|
||||
|
||||
- **theta** - half of 2theta, the angle through the diffracted beam bends
|
||||
- **tau** - longitude of reference vector from scattering vector (in scattering plane)
|
||||
|
||||
Example constraint modes
|
||||
------------------------
|
||||
|
||||
There is sometimes more than one way to get the same effect.
|
||||
|
||||
**Vertical four-circle mode**::
|
||||
|
||||
>>> con gam 0 mu 0 a_eq_b # or equivalently:
|
||||
>>> con qaz 90 mu 0 a_eq_b
|
||||
|
||||
>>> con alpha 1 # replaces a_eq_b
|
||||
|
||||
**Horizontal four-circle mode**::
|
||||
|
||||
>>> con del 0 eta 0 alpha 1 # or equivalently:
|
||||
>>> con qaz 0 mu 0 alpha 1
|
||||
|
||||
**Surface vertical mode**::
|
||||
|
||||
>>> con naz 90 mu 0 alpha 1
|
||||
|
||||
**Surface horizontal mode**::
|
||||
|
||||
>>> con naz 0 eta 0 alpha 1
|
||||
|
||||
**Z-axis mode (surface horizontal)**::
|
||||
|
||||
>>> con chi (-sigma) phi (-tau) alpha 1
|
||||
|
||||
where sigma and tau are the offsets required in chi and phi to bring the surface
|
||||
normal parallel to eta. Alpha will determine mu directly leaving eta to orient
|
||||
the planes. Or::
|
||||
|
||||
>>> con naz 0 phi 0 alpha 1 # or any another sample angle
|
||||
|
||||
**Z-axis mode (surface vertical)**::
|
||||
|
||||
>>> con naz 0 phi 0 alpha 1 # or any another sample angle
|
||||
|
||||
Changing constrained values
|
||||
---------------------------
|
||||
|
||||
Once constraints are chosen constrained values may be changed directly::
|
||||
|
||||
==> con mu 10
|
||||
|
||||
or via the associated scannable::
|
||||
|
||||
==> pos mu_con 10
|
||||
|
||||
Configuring limits and cuts
|
||||
---------------------------
|
||||
|
||||
Diffcalc maintains its own limits on axes. These limits will be used when
|
||||
choosing solutions. If more than one detector solution is exists Diffcalc will
|
||||
ask you to reduce the the limits until there is only one. However if more than
|
||||
one solution for the sample settings is available it will choose one base on
|
||||
heuristics.
|
||||
|
||||
Use the ``hardware`` command to see the current limits and cuts::
|
||||
|
||||
==> hardware
|
||||
|
||||
To set the limits::
|
||||
|
||||
==> setmin delta -1
|
||||
==> setmax delta 145
|
||||
|
||||
To set a cut::
|
||||
|
||||
==> setcut phi -180
|
||||
|
||||
This causes requests to move phi to be between the configured -180 and +360
|
||||
degress above this. i.e. it might dive to -10 degrees rather than 350.
|
||||
|
||||
|
||||
Moving in hkl space
|
||||
-------------------
|
||||
|
||||
Configure a mode, e.g. four-circle vertical::
|
||||
|
||||
==> con gam 0 mu 0 a_eq_b
|
||||
|
||||
Simulate moving to a reflection::
|
||||
|
||||
==> sim hkl [0 1 1]
|
||||
|
||||
Move to reflection::
|
||||
|
||||
==> pos hkl [0 1 1]
|
||||
|
||||
==> pos sixc
|
||||
|
||||
Simulate moving to a location::
|
||||
|
||||
==> pos sixc [0 60 0 30 90 0]
|
||||
|
||||
Scanning in hkl space
|
||||
=====================
|
||||
|
||||
All scans described below use the same generic scanning mechanism
|
||||
provided by the GDA system or by minigda. Here are some examples.
|
||||
|
||||
Fixed hkl scans
|
||||
---------------
|
||||
|
||||
In a 'fixed hkl scan' something (such as energy or Bin) is scanned,
|
||||
and at each step hkl is 'moved' to keep the sample and detector
|
||||
aligned. Also plonk the diffractometer scannable (sixc) on there with no
|
||||
destination to monitor what is actually happening and then
|
||||
throw on a detector (ct) with an exposure time if appropriate::
|
||||
|
||||
>>> #scan scannable_name start stop step [scannable_name [pos or time]]..
|
||||
|
||||
>>> scan en 9 11 .5 hkl [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan en 9 11 .5 hklverbose [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan betain 4 5 .2 hkl [1 0 0] sixc ct 1
|
||||
|
||||
>>> scan alpha_par 0 10 2 hkl [1 0 0] sixc ct 1
|
||||
|
||||
Scanning hkl
|
||||
------------
|
||||
|
||||
Hkl, or one component, may also be scanned directly::
|
||||
|
||||
>>> scan h .8 1.2 .1 hklverbose sixc ct 1
|
||||
|
||||
At each step, this will read the current hkl position, modify the h
|
||||
component and then move to the resulting vector. There is a danger
|
||||
that with this method k and l may drift. To get around this the start,
|
||||
stop and step values may also be specified as vectors. So for example::
|
||||
|
||||
>>> scan hkl [1 0 0] [1 .3 0] [1 0.1 0] ct1
|
||||
|
||||
is equivilant to::
|
||||
|
||||
>>> pos hkl [1 0 0]
|
||||
>>> scan k 0 .3 .1 ct1
|
||||
|
||||
but will not suffer from drifting. This method also allows scans along
|
||||
any direction in hkl space to be performed.
|
||||
|
||||
Multidimension scans
|
||||
--------------------
|
||||
|
||||
Two and three dimensional scans::
|
||||
|
||||
>>> scan en 9 11 .5 h .9 1.1 .2 hklverbose sixc ct 1
|
||||
>>> scan h 1 3 1 k 1 3 1 l 1 3 1 hkl ct 1
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
Orientation Commands
|
||||
--------------------
|
||||
|
||||
==> UB_HELP_TABLE
|
||||
|
||||
Motion commands
|
||||
---------------
|
||||
|
||||
==> HKL_HELP_TABLE
|
||||
|
||||
Good luck --- RobW
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [You1999] H. You. *Angle calculations for a '4S+2D' six-circle diffractometer.*
|
||||
J. Appl. Cryst. (1999). **32**, 614-623. `(pdf link)
|
||||
<http://journals.iucr.org/j/issues/1999/04/00/hn0093/hn0093.pdf>`__.
|
||||
.. [Busing1967] W. R. Busing and H. A. Levy. *Angle calculations for 3- and 4-circle X-ray
|
||||
and neutron diffractometers.* Acta Cryst. (1967). **22**, 457-464. `(pdf link)
|
||||
<http://journals.iucr.org/q/issues/1967/04/00/a05492/a05492.pdf>`__.
|
||||
47
script/__Lib/diffcalc_old/doc/tmp/constraints.txt
Normal file
47
script/__Lib/diffcalc_old/doc/tmp/constraints.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
Take a six circle diffractometer with angles:
|
||||
|
||||
delta, nu, mu, eta, chi, phi
|
||||
|
||||
and virtual angles:
|
||||
|
||||
qaz, naz, psi, alpha, beta.
|
||||
|
||||
Many combinations of these can be constrained:
|
||||
|
||||
|
||||
constrain
|
||||
>>> con nu
|
||||
>>> con psi
|
||||
>>> con mu
|
||||
>>> con nu mu a_eq_b
|
||||
|
||||
real angles are always constrained to there last set position. If they are too far from here
|
||||
an error will result.
|
||||
|
||||
>>> pos nu 0 (moves, parameter tracks last set value (actually checks it when hkl moved))
|
||||
>>> pos psi 90 (does not move, sets parameter in diffcalc)
|
||||
>>> pos mu 0 (moves)
|
||||
>>> pos hkl [1 0 0] (moves based on last set nu, psi, mu)
|
||||
>>> pos betain --> Exception, not constrained
|
||||
|
||||
moving a virtual angle simply sets it to efftec the next hkl move
|
||||
|
||||
Here we need onlu con, uncon and pos.
|
||||
|
||||
......
|
||||
|
||||
However it would be nice to be able to pos betain for example and have it change
|
||||
betain while staying on the same reflection. This might be enabled by locking the
|
||||
the current hkl position. It would be trick to make this work with the physical angles though.
|
||||
|
||||
>>> lock hkl
|
||||
>>> pos psi 90 (moves immediately)
|
||||
>>> scan psi 0 90 1 (scans, moving immediately)
|
||||
>>> pos mu 0 (does not move immediately) (could work by listening to target positions, and triggering move when complete)
|
||||
>>> pos c(mu) moves
|
||||
>>> pos mu_c moves
|
||||
|
||||
Only one thing would be varyable at a time unless they are put in a CoordinatedMotionGroup,
|
||||
which would be hard for the real motors)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user