pax_global_header00006660000000000000000000000064141715005770014521gustar00rootroot0000000000000052 comment=22ab44f7ddb84e29797e68a16f3ae13a233d0e56 libobjcryst-2021.1.2+ds1/000077500000000000000000000000001417150057700147575ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/CHANGELOG.md000066400000000000000000000060371417150057700165760ustar00rootroot00000000000000# Release notes ## Version 2021.1.2 - 2021-11-28 ### Added - Add access to the weight (g/mol) for ScatteringPowerAtom and Crystal ### Changed - Add relative_length_tolerance and absolute_angle_tolerance_degree to SpaceGroupExplorer::Run() and RunAll() - Crystal::XMLInput(): add a hook to re-use atomic scattering power when mDeleteSubObjInDestructor is False - Better formula for Crystal and Molecule ### Fixed - Crystal::XMLInput(): take into account mDeleteSubObjInDestructor. ## Version 2021.1.1 - 2021-06-04 ### Added - Add 3D crystal visualization widget using py3Dmol. ### Changed - Improve the indexing functions. - Better access to some global optimisation variables. - Expose the ZScatterer2Molecule function inside Molecule.h. - Add a cylindrical absorption correction (Lobanov & Alte da Veiga). ## Version 2017.2.3 - 2020-06-15 ### Added - Move SpaceGroupExplorer in a separate class for non-GUI access. Allow keeping or not the tested spacegroup, or the best solution. Sort solutions by the GoF multiplied by the ratio of the number of non-extinct reflections in the spacegoup relative to P1. - MonteCarloObj: add public access to AutoLSQ option - OptimizationObj: add access to Options by number or name - RefinableObj: provide access to options by name - Add STL-type methods (begin, end, size) for ObjRegistry and Molecule objects - Add Crystal.GetFormula(). Use formula to automatically name Crystal and DiffractionDataSingleCrystal when imported from CIF and no name is given ### Changed - Better format for ObjRegistry::Print() - sync with upstream-objcryst v2017.2-52-gd5e3585 ### Fixed - Correct EstimateCellVolume estimation for orthorombic F ## Version 2017.2.2 – 2019-05-14 ### Changed - Throw `invalid_argument` when space group lookup fails. - Sync with upstream-objcryst v2017.2-37-g5ae17765. ### Fixed - Infinite recursion in `SpaceGroup("bad")` and `ChangeSpaceGroup("bad")`. ## Version 2017.2.1 – 2019-03-08 Notable differences from version 2017.1.1. ### Added - Support compilation from standard git-archive tarball, i.e, expand version metadata with `export-subst` git attribute. - Make scons scripts compatible with Python 3 and Python 2. - Declare compatible version requirements for client Anaconda packages. - Sync with upstream-objcryst v2017.2. ### Changed - Remove no-op GL functions which are relevant only for fox-objcryst. - Anaconda package recipe to use Anaconda C++ compilers. - Use c++98 language standard even if Anaconda environment sets later. ### Deprecated - Macro `LIBOBJCRYST_GIT_SHA` replaced with `LIBOBJCRYST_GIT_COMMIT`. - Member `libobjcryst_version_info::git_sha` replaced with `git_commit`. ### Removed - Hard-coded diagnostic output in `SetPowderPatternObs`. ### Fixed - Source typos, e.g., missed braces, misleading indentation, missing include. - Incomplete `scons install` when shared library fails to build. - `SetPowderPatternX` crash for empty vector argument. - Incorrectly doubled return value from `GetInversionCenter`. - Memory leak for a copy-constructed empty `CrystVector`. libobjcryst-2021.1.2+ds1/LICENSE.txt000066400000000000000000000354231417150057700166110ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS libobjcryst-2021.1.2+ds1/README.md000066400000000000000000000067631417150057700162520ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/diffpy/libobjcryst.svg?branch=master)](https://travis-ci.org/diffpy/libobjcryst) # libobjcryst [ObjCryst++](http://objcryst.sourceforge.net) repackaged for installation as a system shared library. ObjCryst++ is Object-Oriented Crystallographic Library for C++ developed by Vincent Favre-Nicolin. libobjcryst is a mirror of the ObjCryst++ sources from https://sourceforge.net/projects/objcryst, expanded with SCons build scripts to make it easier to install as a system shared library. libobjcryst does not include GUI related files from ObjCryst++. This distribution contains required sources from [cctbx](http://cctbx.sourceforge.net/current/) and [newmat](http://www.robertnz.net/nm_intro.htm) that are used in ObjCryst++. For more information about the ObjCryst++ library, see the upstream project at http://objcryst.sourceforge.net. For Python bindings to ObjCryst++ see the pyobjcryst project at https://github.com/diffpy/pyobjcryst. ## REQUIREMENTS libobjcryst requires C++ compiler and the following software: * `scons` - software constructions tool (1.0 or later) * `libboost-dev` - Boost C++ libraries development files Required software is commonly available in the system package manager, for example, on Ubuntu Linux the dependencies can be installed as: ```sh sudo apt-get install build-essential scons libboost-dev ``` libobjcryst is also available as a pre-compiled package for [Anaconda Python](https://www.anaconda.com/download) and it gets automatically installed together with pyobjcryst for Anaconda. ## INSTALLATION ### Installation from sources Use sources from the git repository or extract the latest libobjcryst bundle from https://github.com/diffpy/libobjcryst/releases/latest. ```sh tar xzf libobjcryst-VERSION.tar.gz cd libobjcryst-VERSION ``` To build and install the libobjcryst library use ```sh sudo scons -j4 install ``` This installs libobjcryst for all users under the `/usr/local` directory. If administrator (root) access is not available, see the output from `scons --help` for options to install to a user-writable location. To verify libobjcryst installation, compile and run the included test code [examples/testlib.cpp](examples/testlib.cpp) ```sh cd examples c++ testlib.cpp -lObjCryst ./a.out ``` If there is an error due to missing headers or missing libObjCryst library, adjust the `CPATH` and `LIBRARY_PATH` environment variables or use the `-I` and `-L` compiler options. If the libObjCryst shared library cannot be found at runtime, add a `-Wl,-rpath,SomePath` option to the c++ command or adjust the `LD_LIBRARY_PATH` environment variable. ### Installation for Anaconda Python The libobjcryst library is available in the "diffpy" channel of Anaconda packages ```sh conda config --add channels diffpy conda install libobjcryst ``` libobjcryst is also included in the "diffpy-cmi" collection of packages for structure analysis ```sh conda install diffpy-cmi ``` When compiling with the Anaconda version of libobjcryst it is essential to specify header path, library path and runtime path of the active Anaconda environment ```sh # resolve prefix directory P of the active Anaconda environment P="$(conda info --json | grep default_prefix | cut -d\" -f4)" cd examples c++ testlib.cpp -I$P/include -L$P/lib -Wl,-rpath,$P/lib -lObjCryst ./a.out ``` Note the Anaconda version of libobjcryst is built with C++ compilers provided by Anaconda. This may cause incompatibility with system C++. In such case please use Anaconda C++ to link with libobjcryst. libobjcryst-2021.1.2+ds1/SConstruct000066400000000000000000000045621417150057700170200ustar00rootroot00000000000000MY_SCONS_HELP = """\ SCons build rules for the libobjcryst C++ library Usage: scons [target] [var=value] Targets: lib build the shared library object [default] install install everything under prefix directory install-lib install the shared library object install-include install the C++ header files sdist create source distribution tarball from git repository Build configuration variables: %s Variables can be also assigned in a user-written script sconsvars.py. SCons construction environment can be customized in sconscript.local script. """ import os import platform def subdictionary(d, keyset): return dict(kv for kv in d.items() if kv[0] in keyset) # copy system environment variables related to compilation DefaultEnvironment(ENV=subdictionary(os.environ, ''' PATH CPATH CPLUS_INCLUDE_PATH LIBRARY_PATH LD_RUN_PATH LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH MACOSX_DEPLOYMENT_TARGET '''.split()) ) # Create construction environment env = DefaultEnvironment().Clone() # Variables definitions below work only with 0.98.1 or later. env.EnsureSConsVersion(0, 98, 1) # Customizable compile variables vars = Variables('sconsvars.py') vars.Add(PathVariable( 'prefix', 'installation prefix directory', '/usr/local')) vars.Update(env) vars.Add(PathVariable( 'libdir', 'installation directory for compiled library [prefix/lib]', env['prefix'] + '/lib', PathVariable.PathAccept)) vars.Add(PathVariable( 'includedir', 'installation directory for C++ header files [prefix/include]', env['prefix'] + '/include', PathVariable.PathAccept)) vars.Add(EnumVariable( 'build', 'compiler settings', 'fast', allowed_values=('debug', 'fast'))) vars.Add(EnumVariable( 'tool', 'C++ compiler toolkit to be used', 'default', allowed_values=('default', 'intelc'))) vars.Add(BoolVariable( 'profile', 'build with profiling information', False)) vars.Add(BoolVariable( 'with_shared_cctbx', 'compile and link with the shared cctbx library', False)) vars.Update(env) env.Help(MY_SCONS_HELP % vars.GenerateHelpText(env)) builddir = env.Dir('build/%s-%s' % (env['build'], platform.machine())) Export('env') if os.path.isfile('sconscript.local'): env.SConscript('sconscript.local') SConscript("src/SConscript", variant_dir=builddir) # vim: ft=python libobjcryst-2021.1.2+ds1/examples/000077500000000000000000000000001417150057700165755ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/examples/testlib.cpp000066400000000000000000000026561417150057700207600ustar00rootroot00000000000000// Test program for checking the installation of ObjCryst shared library. // Compile and run this code using: // // c++ testlib.cpp -lObjCryst // ./a.out #include #include #include #include int main(int argc, char* argv[]) { using namespace ObjCryst; // check simple crystal Crystal fcc(3.523, 3.523, 3.523, 90, 90, 90, "F m -3 m"); // verify parsing of space group specification in COD4316154 const char* cod4316154_sg_segment = "data_4316154\n" "_space_group_IT_number 179\n" "_symmetry_cell_setting hexagonal\n" "_symmetry_space_group_name_Hall 'P 65 2 (0 0 1)'\n" "_symmetry_space_group_name_H-M 'P 65 2 2'\n" "_cell_length_a 11.6980(17)\n" "_cell_length_b 11.6980(17)\n" "_cell_length_c 48.265(10)\n" "loop_\n" "_atom_site_label\n" "_atom_site_type_symbol\n" "_atom_site_fract_x\n" "_atom_site_fract_y\n" "_atom_site_fract_z\n" "Re1 Re 0.38627(5) 0.14503(5) 0.710514(10)\n" ; std::istringstream in1(cod4316154_sg_segment); CIF cif1(in1); Crystal* crst1 = CreateCrystalFromCIF(cif1); crst1->GetSpaceGroup().Print(); delete crst1; std::cout << "Installation of ObjCryst shared library works!\n"; return 0; } libobjcryst-2021.1.2+ds1/site_scons/000077500000000000000000000000001417150057700171305ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/site_scons/fallback_version.py000066400000000000000000000003671417150057700230140ustar00rootroot00000000000000#!/usr/bin/env python ''' Definition of FALLBACK_VERSION. Use it when git repository is not available for example, when building from git zip archive. Update FALLBACK_VERSION when tagging a new release. ''' FALLBACK_VERSION = '2021.1.1.post0' libobjcryst-2021.1.2+ds1/site_scons/gitarchive.cfg000066400000000000000000000001751417150057700217410ustar00rootroot00000000000000commit = 47fb77e10d91d3900389eb8e736c2017acc4dcc5 date = 2021-11-29 15:03:20 -0500 refnames = HEAD -> master, tag: v2021.1.2 libobjcryst-2021.1.2+ds1/site_scons/libobjcrystbuildutils.py000066400000000000000000000063271417150057700241410ustar00rootroot00000000000000#!/usr/bin/env python '''Utility functions used by scons and sphinx for version extraction. ''' import os import re MYDIR = os.path.dirname(os.path.abspath(__file__)) EMSG_GIT_MISSING = """ Cannot determine libobjcryst version. Compile from a git repository or use a source archive from https://github.com/diffpy/libobjcryst/releases """ EMSG_BAD_FALLBACK_VERSION = """ Inconsistent FALLBACK_VERSION {} vs {} from git tag. """ def gitinfo(): 'Extract dictionary of version data from git records.' from subprocess import Popen, PIPE global _cached_gitinfo if _cached_gitinfo is not None: return _cached_gitinfo nullfile = open(os.devnull, 'w') kw = dict(stdout=PIPE, stderr=nullfile, cwd=MYDIR, universal_newlines=True) proc = Popen(['git', 'describe', '--match=v[[:digit:]]*'], **kw) desc = proc.stdout.read() if proc.wait(): _cached_gitinfo = {} return gitinfo() proc = Popen(['git', 'log', '-1', '--format=%H %ci'], **kw) glog = proc.stdout.read() words = desc.strip().split('-') vtag = words[0].lstrip('v') vnum = int((words[1:2] or ['0'])[0]) rv = {} rv['commit'], rv['date'] = glog.strip().split(None, 1) rv['patchnumber'] = vnum rv['version'] = vtag if vnum: rv['version'] += '.post' + str(vnum) _cached_gitinfo = rv return gitinfo() _cached_gitinfo = None def getversion(): """Extract version from gitinfo and/or gitarchive.cfg file. Process gitinfo first and make sure it matches FALLBACK_VERSION in gitarchive.cfg. Use expanded data from gitarchive.cfg when these sources are from git archive bundle. """ from fallback_version import FALLBACK_VERSION gitarchivecfgfile = os.path.join(MYDIR, 'gitarchive.cfg') assert os.path.isfile(gitarchivecfgfile) with open(gitarchivecfgfile) as fp: gacontent = fp.read() gaitems = re.findall(r'^(\w+) *= *(\S.*?)\s*$', gacontent, re.M) ga = dict(gaitems) gi = gitinfo() rv = {} if gi: afb = FALLBACK_VERSION gfb = gi['version'].split('.post')[0] + '.post0' if gfb != afb: raise RuntimeError(EMSG_BAD_FALLBACK_VERSION.format(afb, gfb)) rv.update(gi) else: # Not a git repository. Require that gitarchive.cfg is expanded. if '$Format:' in ga['commit']: raise RuntimeError(EMSG_GIT_MISSING) rv['commit'] = ga['commit'] rv['date'] = ga['date'] # First assume we have an undetermined post-release. Keep version # suffix as ".post0", but set patchnumber to ensure we are post # FALLBACK_VERSION. rv['version'] = FALLBACK_VERSION rv['patchnumber'] = 1 # If we are at version tag turn this to regular release. mx = re.search(r'\btag: v(\d[^,]*)', ga['refnames']) if mx: rv['version'] = mx.group(1) rv['patchnumber'] = 0 # rv['version'] is resolved, let's parse its subfields. vbase = rv['version'].split('.post')[0] mx = re.match(r'^(\d+)\.(\d+)(?:\.(\d+))?((?:[ab]|rc)\d*)?', vbase) rv['major'] = int(mx.group(1)) rv['minor'] = int(mx.group(2)) rv['micro'] = int(mx.group(3) or 0) rv['prerelease'] = mx.group(4) return rv libobjcryst-2021.1.2+ds1/src/000077500000000000000000000000001417150057700155465ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/src/ObjCryst/000077500000000000000000000000001417150057700173055ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/src/ObjCryst/CrystVector/000077500000000000000000000000001417150057700215745ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/src/ObjCryst/CrystVector/CrystVector.cpp000066400000000000000000001271321417150057700245750ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/ObjCryst/General.h" #ifdef __LIBCRYST_VECTOR_USE_BLITZ__ #define CrystVector Array #define CrystMatrix Array template T MaxDifference(const Array &a,const Array &b) { return max(fabs(a-b)); } template T MaxDifference(const Array &a,const Array &b) { return max(fabs(a-b)); } #else // __LIBCRYST_VECTOR_USE_BLITZ__ //Still using pointers instead of blitz for geometrical structure factor, //due to huge memory requirements with gcc when using blitz. #define __VFN_GEOM_STRUCT_FACTOR_USE_POINTERS #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //###################################################################### // CrystVector //###################################################################### template CrystVector::CrystVector():mpData(0),mNumElements(0),mIsAreference(false) {} template CrystVector::CrystVector(const long nbElements): mNumElements(nbElements),mIsAreference(false) { mpData=new T[mNumElements]; } template CrystVector::CrystVector(const CrystVector &old): mNumElements(old.numElements()),mIsAreference(false) { mpData=new T[mNumElements]; T *p1=mpData; const T *p2=old.data(); for(long i=0;i CrystVector::~CrystVector() { if(!mIsAreference) { delete[] mpData; } } template void CrystVector::operator=(const CrystVector &old) { VFN_DEBUG_MESSAGE("CrystVector::operator=()",0) this->resize(old.numElements()); mIsAreference=false; T *p1=mpData; const T *p2=old.data(); for(long i=0;i void CrystVector::reference(CrystVector &old, const long imin, const long imax) { if(!mIsAreference) { delete[] mpData ; } if(imax>imin) { mNumElements=imax-imin; mpData=old.data()+imin; } else { mNumElements=old.numElements(); mpData=old.data(); } mIsAreference=true; } template long CrystVector::numElements()const {return mNumElements;} template long CrystVector::size()const {return mNumElements;} template T CrystVector::sum()const { T tmp=0; const T *p=this->data(); for(long i=0;inumElements();i++) tmp += *p++ ; return tmp; } template T CrystVector::min()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp>*p) tmp=*p; p++; } return tmp; } template T CrystVector::max()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp<*p) tmp=*p; p++; } return tmp; } template unsigned long CrystVector::imin(const unsigned long start0,const unsigned long finish0)const { unsigned long start=start0,finish=finish0; if(start0==finish0) { start=0; finish=this->numElements(); } T tmp=0; const T *p=this->data()+start; tmp=*p++; long im=0; for(unsigned long i=start+1;i*p) {tmp=*p;im=i;} p++; } return (unsigned long)im; } template unsigned long CrystVector::imax(const unsigned long start0,const unsigned long finish0)const { unsigned long start=start0,finish=finish0; if(start0==finish0) { start=0; finish=this->numElements(); } T tmp=0; const T *p=this->data()+start; tmp=*p++; long im=start; for(unsigned long i=start+1;i T * CrystVector::data() {return mpData;} template const T * CrystVector::data() const {return mpData;} template void CrystVector::resize(const long newNbElements) { if(mNumElements==newNbElements) return; VFN_DEBUG_MESSAGE("CrystVector::resize():("<" <0) { mpData=new T[mNumElements]; } mIsAreference=false; } template void CrystVector::resizeAndPreserve(const long newNbElements) { //:TODO: check memory allocation if(newNbElements == mNumElements) return; T * RESTRICT p=mpData; T * RESTRICT p2,*p1; mpData=0; mpData=new T[newNbElements]; p2=mpData; p1=p; const long tmp= (newNbElements > mNumElements) ? mNumElements : newNbElements ; for(long i=tmp;i>0;i--) *p2++ = *p1++ ; if(mIsAreference==false) { delete[] p ; } mNumElements=newNbElements; mIsAreference=false; } template void CrystVector::operator*=(const T num) { T * RESTRICT p=mpData; for(int i=mNumElements;i>0;i--) *p++ *= num; } template void CrystVector::operator*=(const CrystVector &vect) { #ifdef __DEBUG__ if( vect.numElements() != mNumElements) { cout<<"CrystVector::operator*=(&vect)(i): Number of elements differ:"<< mNumElements \ << "!="<< vect.numElements() <0;i--) { *p *= *rhs; p++ ; rhs++;} } else { T *p=mpData; for(int i=mNumElements;i>0;i--) { *p *= *p; p++ ;} } } template void CrystVector::operator/=(const T num) { T * RESTRICT p=mpData; const REAL d=1/num; for(int i=mNumElements;i>0;i--) *p++ *= d; } template void CrystVector::operator/=(const CrystVector &vect) { #ifdef __DEBUG__ if( vect.numElements() != mNumElements) { cout<<"CrystVector::operator/=(&vect)(i): Number of elements differ:"<< mNumElements \ << "!="<< vect.numElements() <0;i--) { *p /= *rhs; p++ ; rhs++;} } else *this=1; } template void CrystVector::operator+=(const T num) { T * RESTRICT p=mpData; for(int i=mNumElements;i>0;i--) *p++ += num; } template void CrystVector::operator+=(const CrystVector &vect) { #ifdef __DEBUG__ if( vect.numElements() != mNumElements) { cout<<"CrystVector::operator+=(&vect)(i): Number of elements differ:"<< mNumElements \ << "!="<< vect.numElements() <0;i--) *p++ += *rhs++; } else { T *p=mpData; for(int i=mNumElements;i>0;i--) {*p += *p; p++;} } } template void CrystVector::operator-=(const CrystVector &vect) { #ifdef __DEBUG__ if( vect.numElements() != mNumElements) { cout<<"CrystVector::operator-=(&vect)(i): Number of elements differ:"<< mNumElements \ << "!="<< vect.numElements() <0;i--) *p++ -= *rhs++; } else (*this)=0; } template void CrystVector::operator=(const T num) { T *p=mpData; for(int i=mNumElements;i>0;i--) *p++ = num; } template T CrystVector::operator()(const long i) const { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystVector::operator()(i): Tried to access an element out of bounds :"< T& CrystVector::operator()(const long i) { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystVector::operator()(i): Tried to access an element out of bounds !"< ostream& operator<<(ostream &os, CrystVector &vect) { //return os << FormatHorizVector(vect); for(long i=0;i CrystVector SortSubs(const CrystVector &vect) { CrystVector subscript(vect.numElements()); { long *pLong=subscript.data(); for(long i=0;i v; v=vect; QuickSortSubs(v,subscript,v.numElements()-1,0,0); return subscript; } template long QuickSortSubs(CrystVector &vect, CrystVector &subscript, long last,long first, int depth) { //assert(depth++ <50);//for up to 2^50 elements static long count=0; long low, high; T tmpT, sepValeur ; long tmpSubs; low = first; high = last; sepValeur = vect( (first + last) / 2 ); do { while( vect(low) < sepValeur ) low++; while( vect(high) > sepValeur ) high--; if( low <= high ) { count++; tmpT = vect(low); vect(low) = vect(high); vect(high) = tmpT; tmpSubs = subscript(low); subscript(low++) = subscript(high); subscript(high--) = tmpSubs; } } while( low <= high); if( first < high ) QuickSortSubs(vect,subscript, high, first,depth); if( low < last ) QuickSortSubs(vect,subscript, last, low,depth); return count ; } template CrystVector cos(const CrystVector &vect) { CrystVector cosVect(vect.numElements()); for(long i=0;i CrystVector sin(const CrystVector &vect) { CrystVector sinVect(vect.numElements()); for(long i=0;i CrystVector tan(const CrystVector &vect) { CrystVector tanVect(vect.numElements()); for(long i=0;i CrystVector sqrt(const CrystVector &vect) { CrystVector tanVect(vect.numElements()); for(long i=0;i CrystMatrix ::CrystMatrix(): mpData(0),mNumElements(0),mXSize(0),mYSize(0),mIsAreference(false){} template CrystMatrix::CrystMatrix(const long ySize,const long xSize): mNumElements(xSize*ySize),mXSize(xSize),mYSize(ySize),mIsAreference(false) { mpData=new T[mNumElements]; } template CrystMatrix::CrystMatrix(const CrystMatrix &old): mNumElements(old.numElements()),mXSize(old.cols()),mYSize(old.rows()),mIsAreference(false) { mpData=new T[mNumElements]; T *p1=mpData; const T *p2=old.data(); for(long i=0;i CrystMatrix::~CrystMatrix() { if(!mIsAreference) { delete[] mpData; } } template void CrystMatrix::operator=(const CrystMatrix &old) { mXSize=old.cols(); mYSize=old.rows(); mIsAreference=false; if(mNumElements!=old.numElements()) { if(mIsAreference==false) { delete[] mpData ; } mNumElements=old.numElements(); mpData=new T[mNumElements]; } T *p1=mpData; const T *p2=old.data(); for(long i=0;i void CrystMatrix::reference(CrystMatrix &old) { if(mIsAreference==false) { delete[] mpData ; } mIsAreference=true; mNumElements=old.numElements(); mpData=old.data(); } template long CrystMatrix::numElements()const {return mNumElements;} template long CrystMatrix::size()const {return mNumElements;} template T CrystMatrix::sum()const { T tmp=0; const T *p=this->data(); for(long i=0;inumElements();i++) tmp += *p++ ; return tmp; } template T CrystMatrix::min()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp>*p) tmp=*p; p++; } return tmp; } template T CrystMatrix::max()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp<*p) tmp=*p; p++; } return tmp; } template long CrystMatrix::cols()const {return mXSize;} template long CrystMatrix::rows()const {return mYSize;} template T* CrystMatrix::data() {return mpData;} template const T* CrystMatrix::data() const {return mpData;} template void CrystMatrix::resize(const long ySize,const long xSize) { mXSize=xSize; mYSize=ySize; if(xSize*ySize == mNumElements) return; if(!mIsAreference) { delete[] mpData ; } mpData=0; mXSize=xSize; mYSize=ySize; mNumElements=xSize*ySize; if(mNumElements>0) { mpData=new T[mNumElements]; } } template void CrystMatrix::resizeAndPreserve(const long ySize,const long xSize) { mXSize=xSize; mYSize=ySize; if(xSize*ySize == mNumElements) return; T *p=mpData; T *p2,*p1; mpData=0; mpData=new T[xSize*ySize]; p2=mpData; p1=p; long tmp= ( (xSize*ySize) > mNumElements) ? mNumElements : xSize*ySize; for(long i=0;i void CrystMatrix::operator=(const T num) { T *p=mpData; for(int i=0;i void CrystMatrix::operator*=(const T num) { T *p=mpData; for(int i=0;i void CrystMatrix::operator*=(const CrystMatrix &vect) { #ifdef __DEBUG__ if( this->numElements() != vect.numElements()) { cout<<"CrystMatrix::operator*=(): Number of elements differ !"< void CrystMatrix::operator/=(const T num) { T *p=mpData; for(int i=0;i void CrystMatrix::operator+=(const T num) { T *p=mpData; for(int i=0;i void CrystMatrix::operator-=(const T num) { T *p=mpData; for(int i=0;i CrystMatrix CrystMatrix::Mult(const CrystMatrix &rhs) { if((this->cols()!=rhs.rows())||(this->rows()!=rhs.cols())) { //throw ObjCrystException("CrystMatrix::Mult(...): matrix sizes do not match !!"); } CrystMatrix mult(this->rows(),rhs.cols()); for(unsigned int r=0;rrows();r++) for(unsigned int c=0;rcols();i++) tmp+=(*this)(r,i)*rhs(i,c); mult(r,c)=tmp; } return mult; } template T CrystMatrix::operator()(const long i) const { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystMatrix::operator()(i): element out of bounds !"< T CrystMatrix::operator()(const long i,const long j) const { #ifdef __DEBUG__ if( (i<0) || (j<0) || (i>=mYSize) || (j>=mXSize) ) { cout<<"CrystMatrix::operator()(i,j): element out of bounds:"< T& CrystMatrix::operator()(const long i) { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystMatrix::operator()(i): element out of bounds !"< T& CrystMatrix::operator()(const long i,const long j) { #ifdef __DEBUG__ if( (i<0) || (j<0) || (i>=mYSize) || (j>=mXSize) ) { cout<<"CrystMatrix::operator()(i,j): element out of bounds:"< CrystMatrix CrystMatrix::transpose()const { CrystMatrix newM(this->cols(),this->rows()); for(long i=0;icols();i++) for(long j=0;jrows();j++) newM(i,j)=(*this)(j,i); return newM; } //###################################################################### // CrystArray3D //###################################################################### template CrystArray3D ::CrystArray3D(): mpData(0),mNumElements(0),mXSize(0),mYSize(0),mZSize(0),mIsAreference(false){} template CrystArray3D::CrystArray3D(const long zSize, const long ySize, const long xSize): mNumElements(xSize*ySize*zSize),mXSize(xSize),mYSize(ySize),mZSize(zSize), mIsAreference(false) { mpData=new T[mNumElements]; } template CrystArray3D::CrystArray3D(const CrystArray3D &old): mNumElements(old.numElements()), mXSize(old.cols()),mYSize(old.rows()),mZSize(old.depth()), mIsAreference(false) { mpData=new T[mNumElements]; T *p1=mpData; const T *p2=old.data(); for(long i=0;i CrystArray3D::~CrystArray3D() { if(!mIsAreference)delete[] mpData;} template void CrystArray3D::operator=(const CrystArray3D &old) { mXSize=old.cols(); mYSize=old.rows(); mZSize=old.depth(); mIsAreference=false; if(mNumElements!=old.numElements()) { mNumElements=old.numElements(); if(mIsAreference==false)delete[] mpData ; mpData=new T[mNumElements]; } T *p1=mpData; const T *p2=old.data(); for(long i=0;i void CrystArray3D::reference(CrystArray3D &old) { if(mIsAreference==false) delete[] mpData ; mIsAreference=true; mNumElements=old.numElements(); mpData=old.data(); } template long CrystArray3D::numElements()const{return mNumElements;} template long CrystArray3D::size()const{return mNumElements;} template T CrystArray3D::sum()const { T tmp=0; const T *p=this->data(); for(long i=0;inumElements();i++) tmp += *p++ ; return tmp; } template T CrystArray3D::min()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp>*p) tmp=*p; p++; } return tmp; } template T CrystArray3D::max()const { T tmp=0; const T *p=this->data(); tmp=*p++; for(long i=1;inumElements();i++) { if(tmp<*p) tmp=*p; p++; } return tmp; } template long CrystArray3D::cols()const {return mXSize;} template long CrystArray3D::rows()const {return mYSize;} template long CrystArray3D::depth()const {return mZSize;} template T* CrystArray3D::data() {return mpData;} template const T* CrystArray3D::data() const {return mpData;} template void CrystArray3D::resize(const long zSize, const long ySize, const long xSize) { mXSize=xSize; mYSize=ySize; mZSize=zSize; if(xSize*ySize*zSize == mNumElements) return; if(!mIsAreference)delete[] mpData ; mpData=0; mNumElements=xSize*ySize*zSize; if(mNumElements>0) mpData=new T[mNumElements]; } template void CrystArray3D::resizeAndPreserve(const long zSize, const long ySize, const long xSize) { mXSize=xSize; mYSize=ySize; mZSize=zSize; if(xSize*ySize*zSize == mNumElements) return; T *p=mpData; T *p2,*p1; mpData=new T[xSize*ySize*zSize]; p2=mpData; p1=p; long tmp= ( (xSize*ySize*zSize) > mNumElements) ? mNumElements : xSize*ySize*zSize; for(long i=0;i void CrystArray3D::operator=(const T num) { VFN_DEBUG_MESSAGE("CrystArray3D::operator=():"< void CrystArray3D::operator*=(const T num) { T *p=mpData; for(int i=0;i void CrystArray3D::operator*=(const CrystArray3D &vect) { #ifdef __DEBUG__ if( this->numElements() != vect.numElements()) { cout<<"CrystArray3D::operator*=(): Number of elements differ !"< void CrystArray3D::operator/=(const T num) { T *p=mpData; for(int i=0;i void CrystArray3D::operator+=(const T num) { T *p=mpData; for(int i=0;i void CrystArray3D::operator-=(const T num) { T *p=mpData; for(int i=0;i T CrystArray3D::operator()(const long i) const { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystArray3D::operator()(i): element out of bounds !"< T CrystArray3D::operator()(const long i,const long j,const long k) const { #ifdef __DEBUG__ if( (i<0) || (j<0) || (k<0) || (i>=mZSize) || (j>=mYSize) || (k>=mXSize)) { cout<<"CrystArray3D::operator()(i,j,k): element out of bounds:"< T& CrystArray3D::operator()(const long i) { #ifdef __DEBUG__ if( (i<0) || (i>=mNumElements)) { cout<<"CrystArray3D::operator()(i): element out of bounds !"< T& CrystArray3D::operator()(const long i,const long j,const long k) { #ifdef __DEBUG__ if( (i<0) || (j<0) || (k<0) || (i>=mZSize) || (j>=mYSize) || (k>=mXSize)) { cout<<"CrystArray3D::operator()(i,j,k): element out of bounds:"< ostream& operator<<(ostream &os, const CrystMatrix &vect) { //return os << FormatHorizVector(vect); for(long i=0;i ostream& operator<<(ostream &os, const CrystArray3D &vect) { for(long i=0;i T MaxDifference(const CrystVector &a,const CrystVector &b) { const T *p1=a.data(); const T *p2=b.data(); REAL max=0; REAL tmp=0; for(long i=0;imax) max=tmp; } return (T)max; } template T MaxDifference(const CrystMatrix &a,const CrystMatrix &b) { const T *p1=a.data(); const T *p2=b.data(); T max=0; T tmp=0; for(long i=0;imax) max=tmp; } return max; } template CrystMatrix product(const CrystMatrix &a,const CrystMatrix &b) { VFN_DEBUG_ENTRY("CrystMatrix product()",2) //:TODO: check a.cols()==b.rows() CrystMatrix ab(a.rows(),b.cols()); for(long i=0;i product()",2) return ab; } //###################################################################### // explicit instantiation //###################################################################### template class CrystVector; template REAL MaxDifference(const CrystVector&,const CrystVector&); template ostream& operator<<(ostream &os, CrystVector &vect); template CrystVector SortSubs(const CrystVector &vect); template long QuickSortSubs(CrystVector &vect,CrystVector &subscript, long last,long first, int depth); template class CrystMatrix; template REAL MaxDifference(const CrystMatrix&,const CrystMatrix&); template CrystMatrix product(const CrystMatrix&,const CrystMatrix&); template ostream& operator<<(ostream &os, const CrystMatrix &vect); template CrystVector cos(const CrystVector&); template CrystVector sin(const CrystVector&); template CrystVector tan(const CrystVector&); template CrystVector sqrt(const CrystVector&); template class CrystArray3D; template ostream& operator<<(ostream &os, const CrystArray3D &vect); template class CrystVector; template long MaxDifference(const CrystVector&,const CrystVector&); template ostream& operator<<(ostream &os, CrystVector &vect); template CrystVector SortSubs(const CrystVector &vect); template long QuickSortSubs(CrystVector &vect,CrystVector &subscript, long last,long first, int depth); template class CrystMatrix; template long MaxDifference(const CrystMatrix&,const CrystMatrix&); template CrystMatrix product(const CrystMatrix&,const CrystMatrix&); template ostream& operator<<(ostream &os, const CrystMatrix &vect); template class CrystVector; template int MaxDifference(const CrystVector&,const CrystVector&); template ostream& operator<<(ostream &os, CrystVector &vect); template CrystVector SortSubs(const CrystVector &vect); template long QuickSortSubs(CrystVector &vect,CrystVector &subscript, long last,long first, int depth); template class CrystMatrix; template int MaxDifference(const CrystMatrix&,const CrystMatrix&); template CrystMatrix product(const CrystMatrix&,const CrystMatrix&); template ostream& operator<<(ostream &os, const CrystMatrix &vect); template class CrystVector; template unsigned int MaxDifference(const CrystVector&,const CrystVector&); template ostream& operator<<(ostream &os, CrystVector &vect); template CrystVector SortSubs(const CrystVector &vect); template long QuickSortSubs(CrystVector &vect,CrystVector &subscript, long last,long first, int depth); template class CrystMatrix; template unsigned int MaxDifference(const CrystMatrix&,const CrystMatrix&); template CrystMatrix product(const CrystMatrix&,const CrystMatrix&); template ostream& operator<<(ostream &os, const CrystMatrix &vect); template class CrystVector; template ostream& operator<<(ostream &os, CrystVector &vect); template class CrystMatrix; template bool MaxDifference(const CrystMatrix&,const CrystMatrix&); template ostream& operator<<(ostream &os, const CrystMatrix &vect); #endif // __LIBCRYST_VECTOR_USE_BLITZ__ //###################################################################### // Functions //###################################################################### CrystMatrix_REAL InvertMatrix(const CrystMatrix_REAL &m) {//:TODO: Check Pivoting... VFN_DEBUG_ENTRY("InvertMatrix()",2) VFN_DEBUG_MESSAGE("->Matrix to invert :"< max) { max=fabs(m(j,i)); rowMax=j; } //Check if pivot is non-singular :TODO: /* if(max < eps) { throw i; } */ } //pivot if(rowMax != i) { //cout << "Exchanging rows: "<< i << " and " << rowMax <=0;j--) { a=cm(j,i)/cm(i,i); for(long k=0;kInverted Matrix :"< void MatrixExchangeRows(CrystMatrix_T &m, const long row1, const long row2) { //cout << "Exchanging rows:begin" < T MaxAbs(const CrystVector_T &vector) { const T* pData=vector.data(); T max =(T) fabs((REAL) *pData++); for(long i=1;i max) max=(T) fabs((REAL) *pData); pData++; } return max; } //Explicit instatiation template REAL MaxAbs(const CrystVector_REAL &vector); template int MaxAbs(const CrystVector_int &vector); template unsigned int MaxAbs(const CrystVector_uint &vector); template long MaxAbs(const CrystVector_long &vector); template T MinAbs(const CrystVector_T &vector) { const T* pData=vector.data(); T min =(T) fabs((REAL) *pData++); for(long i=1;iInit(x,y,yp0,ypn); } CubicSpline::CubicSpline(const REAL *px, const REAL *py, const unsigned long nbPoints, const REAL yp0, const REAL ypn) { this->Init(px,py,nbPoints,yp0,ypn); } CubicSpline::CubicSpline(const CrystVector_REAL &x, const CrystVector_REAL &y) { this->Init(x,y); } CubicSpline::CubicSpline(const REAL *px, const REAL *py, const unsigned long nbPoints) { this->Init(px,py,nbPoints); } void CubicSpline::Init(const CrystVector_REAL &x, const CrystVector_REAL &y, const REAL yp0, const REAL ypn) { VFN_DEBUG_ENTRY("CubicSpline::Init(x,y,yp0,ypn)",5) mX=x; mY=y; mYsecond.resize(x.numElements()); this->InitSpline(yp0,ypn); VFN_DEBUG_EXIT("CubicSpline::Init(x,y,yp0,ypn)",5) } void CubicSpline::Init(const REAL *px, const REAL *py, const unsigned long nbPoints, const REAL yp0, const REAL ypn) { VFN_DEBUG_ENTRY("CubicSpline::Init(px,py,yp0,ypn)",5) mX.resize(nbPoints); mY.resize(nbPoints); mYsecond.resize(nbPoints); for(unsigned long i=0;iInitSpline(yp0,ypn); VFN_DEBUG_EXIT("CubicSpline::Init(x,y,yp0,ypn)",5) } void CubicSpline::Init(const CrystVector_REAL &x, const CrystVector_REAL &y) { VFN_DEBUG_ENTRY("CubicSpline::Init(x,y)",5) mX=x; mY=y; mYsecond.resize(x.numElements()); this->InitNaturalSpline(); VFN_DEBUG_EXIT("CubicSpline::Init(x,y)",5) } void CubicSpline::Init(const REAL *px, const REAL *py, const unsigned long nbPoints) { VFN_DEBUG_ENTRY("CubicSpline::Init(px,py,n)",5) mX.resize(nbPoints); mY.resize(nbPoints); mYsecond.resize(nbPoints); for(unsigned long i=0;iInitNaturalSpline(); VFN_DEBUG_EXIT("CubicSpline::Init(x,y,n)",5) } CubicSpline::~CubicSpline() { } REAL CubicSpline::operator()(const REAL x) const { //:TODO: faster! //:TODO: take into account beginning and end derivatives for out-of-bounds points long i; if(x=0;i--) mYsecond(i)=mYsecond(i)*mYsecond(i+1)+u(i); } void CubicSpline::InitNaturalSpline() { const long n=mX.numElements(); CrystVector_REAL u(mX.numElements()); mYsecond(0)=0; u(0)=0; REAL a,b; for(long i=1;i<=(n-2);i++) { a=(mX(i)-mX(i-1))/(mX(i+1)-mX(i-1)); b=a*mYsecond(i-1)+2; mYsecond(i)=(a-1)/b; u(i)=(6*((mY(i+1)-mY(i))/(mX(i+1)-mX(i))-(mY(i)-mY(i-1))/(mX(i)-mX(i-1))) /(mX(i+1)-mX(i-1))-a*u(i-1))/b; } mYsecond(n-1)=0; for(long i=(n-2);i>=0;i--) mYsecond(i)=mYsecond(i)*mYsecond(i+1)+u(i); } //###################################################################### // Savitzky-Golay interpolation //###################################################################### // Coefficients for smoothing (deriv=0) - is there a general formula for these ? REAL sgcoeffs_0_5[]={-0.08571429, 0.34285714, 0.48571429, 0.34285714, -0.08571429}; REAL sgcoeffs_0_7[]={-0.0952381 , 0.14285714, 0.28571429, 0.33333333, 0.28571429, 0.14285714, -0.0952381}; REAL sgcoeffs_0_9[]={-0.09090909, 0.06060606, 0.16883117, 0.23376623, 0.25541126, 0.23376623, 0.16883117, 0.06060606, -0.09090909}; REAL sgcoeffs_0_11[]={-0.08391608, 0.02097902, 0.1025641 , 0.16083916, 0.1958042 , 0.20745921, 0.1958042 , 0.16083916, 0.1025641 , 0.02097902, -0.08391608}; REAL sgcoeffs_0_13[]={-7.69230769e-02, 1.73472348e-18, 6.29370629e-02, 1.11888112e-01, 1.46853147e-01, 1.67832168e-01, 1.74825175e-01, 1.67832168e-01, 1.46853147e-01, 1.11888112e-01, 6.29370629e-02, 1.73472348e-18, -7.69230769e-02}; REAL sgcoeffs_0_15[]={-0.07058824, -0.01176471, 0.03800905, 0.07873303, 0.11040724, 0.13303167, 0.14660633, 0.15113122, 0.14660633, 0.13303167, 0.11040724, 0.07873303, 0.03800905, -0.01176471, -0.07058824}; REAL sgcoeffs_0_17[]={-0.06501548, -0.01857585, 0.02167183, 0.05572755, 0.08359133, 0.10526316, 0.12074303, 0.13003096, 0.13312693, 0.13003096, 0.12074303, 0.10526316, 0.08359133, 0.05572755, 0.02167183, -0.01857585, -0.06501548}; REAL sgcoeffs_0_19[]={-0.06015038, -0.02255639, 0.01061477, 0.03936311, 0.06368863, 0.08359133, 0.09907121, 0.11012826, 0.11676249, 0.11897391, 0.11676249, 0.11012826, 0.09907121, 0.08359133, 0.06368863, 0.03936311, 0.01061477, -0.02255639, -0.06015038}; REAL sgcoeffs_0_21[]={-0.05590062, -0.02484472, 0.00294214, 0.02745995, 0.04870873, 0.06668846, 0.08139915, 0.0928408 , 0.1010134 , 0.10591697, 0.10755149, 0.10591697, 0.1010134 , 0.0928408 , 0.08139915, 0.06668846, 0.04870873, 0.02745995, 0.00294214, -0.02484472, -0.05590062}; REAL sgcoeffs_0_23[]={-0.05217391, -0.02608696, -0.00248447, 0.01863354, 0.03726708, 0.05341615, 0.06708075, 0.07826087, 0.08695652, 0.0931677 , 0.09689441, 0.09813665, 0.09689441, 0.0931677 , 0.08695652, 0.07826087, 0.06708075, 0.05341615, 0.03726708, 0.01863354, -0.00248447, -0.02608696, -0.05217391}; CrystVector_REAL SavitzkyGolay(const CrystVector_REAL &v, const unsigned int um, const unsigned int deriv) { const int m=(int)um; REAL *sgcoeffs=0; if(deriv==0) { if(m==2)sgcoeffs=sgcoeffs_0_5; if(m==3)sgcoeffs=sgcoeffs_0_7; if(m==4)sgcoeffs=sgcoeffs_0_9; if(m==5)sgcoeffs=sgcoeffs_0_11; if(m==6)sgcoeffs=sgcoeffs_0_13; if(m==7)sgcoeffs=sgcoeffs_0_15; if(m==8)sgcoeffs=sgcoeffs_0_17; if(m==9)sgcoeffs=sgcoeffs_0_19; if(m==10)sgcoeffs=sgcoeffs_0_21; if(m==11)sgcoeffs=sgcoeffs_0_23; } if(deriv==1) { sgcoeffs=new REAL[2*m+1]; REAL *p=sgcoeffs; const REAL f=3/(REAL) (m*(m+1)*(2*m+1)); for(int j=-m;j<=m;++j) *p++ = f*j; } if(deriv==2) { sgcoeffs=new REAL[2*m+1]; REAL *p=sgcoeffs; const REAL f1=45/(REAL) (m*(m+1)*(2*m+1)*(4*m*(m+1)-3)); const REAL f2=-15/(REAL) ((2*m+1)*(4*m*(m+1)-3)); for(int j=-m;j<=m;++j) *p++ = f1*j*j + f2; } //cout<<__FILE__<<":"<<__LINE__<<"Savitzky-Golay coeeficients(m="< using namespace blitz; //Still use pointers for the Geometrical Structure computation ? //(due to the complexity of the formulas, a blitz coding requires //to much memory when compiling) #define __VFN_GEOM_STRUCT_FACTOR_USE_POINTERS #define CrystVector_REAL Array #define CrystVector_float Array #define CrystVector_long Array #define CrystVector_int Array #define CrystVector_uint Array #define CrystVector_bool Array #define CrystMatrix_REAL Array #define CrystMatrix_float Array #define CrystMatrix_long Array #define CrystMatrix_int Array #define CrystMatrix_uint Array #define CrystMatrix_bool Array #define CrystVector_T Array #define CrystMatrix_T Array #define CrystArray3D_T Array template T MaxDifference(const Array &a,const Array &b); template T MaxDifference(const Array &a,const Array &b); #else // __VFN_VECTOR_USE_BLITZ__ #define CrystVector_REAL CrystVector #define CrystVector_double CrystVector #define CrystVector_float CrystVector #define CrystVector_long CrystVector #define CrystVector_int CrystVector #define CrystVector_uint CrystVector #define CrystVector_bool CrystVector #define CrystMatrix_REAL CrystMatrix #define CrystMatrix_double CrystMatrix #define CrystMatrix_float CrystMatrix #define CrystMatrix_long CrystMatrix #define CrystMatrix_int CrystMatrix #define CrystMatrix_uint CrystMatrix #define CrystMatrix_bool CrystMatrix #define CrystArray3D_REAL CrystArray3D #define CrystVector_T CrystVector #define CrystMatrix_T CrystMatrix #define CrystArray3D_T CrystMatrix #define __VFN_GEOM_STRUCT_FACTOR_USE_POINTERS #include #include using namespace std; #ifdef _MSC_VER // MS VC++ predefined macros.... #undef min #undef max #endif //###################################################################### // CrystVector //###################################################################### /** \brief Vector library (Blitz++ mimic) for ObjCryst++ * * The CrystVector library is not a new array computation library, despite * the appearances. ObjCryst++ should used the * Blitz++ array library , which yields * excellent performance \e and simple array expressions. Unfortunately, the memory * required to \e compile the library using gcc is far too high to be reasonable * when using complex expressions and optimizing code. So until this has changed, * The CrystVector and CrystMatrix library have been created, and these emulate * (supposedly exactly) the Blitz++ interface (but not the smart handling of * mathematical expressions, so pointers must be used). For documentation about these * two libraries you should read the * Blitz++ documentation. CrystVector and CrystMatrix use the same kind of storage * in memory. * * You can use CrystVector_REAL, CrystVector_long,etc... to declare 1D vectors. Macros * ensure (well, should) ensure compatibility with Blitz++. (as of april 2001 support of * blitz++ is broken). * * \todo check again Blitz++ support in newer gcc versions. */ template class CrystVector { public: CrystVector(); CrystVector(const long nbElements); CrystVector(const CrystVector &old); ~CrystVector(); void operator=(const CrystVector &old); template void operator=(const CrystVector &old) { if(mNumElements != old.numElements()) { mNumElements = old.numElements(); delete[] mpData; mpData=new T[mNumElements]; }; mIsAreference=false; T *p1=mpData; const U *p2=old.data(); for(long i=0;i() const { CrystVector vect; vect=*this; return vect; } operator CrystVector() const { CrystVector vect; vect=*this; return vect; } operator CrystVector() const { CrystVector vect; vect=*this; return vect; } operator CrystVector() const { CrystVector vect; vect=*this; return vect; } operator CrystVector() const { CrystVector vect; vect=*this; return vect; } #else template operator CrystVector() const { CrystVector vect; vect=*this; return vect; } #endif /** Define this vector as a reference to another vector, or part of another vector * * \param old: the vector this one should point to * \param imin,imax: imax>imin, this vector will point to a part of the other * vector, from old(i) to old(imax-1) */ void reference(CrystVector &old, const long imin=0, const long imax=0); long numElements()const; long size()const; T sum()const; T min()const; T max()const; /// Find index of minimum, between start and end (if start==end, use full vector) unsigned long imin(const unsigned long start=0,const unsigned long finish=0)const; /// Find index of maximum, between start and end (if start==end, use full vector) unsigned long imax(const unsigned long start=0,const unsigned long finish=0)const; T * data(); const T * data() const; void resize(const long newNbElements); void resizeAndPreserve(const long newNbElements); void operator*=(const T num); void operator*=(const CrystVector &vect); void operator/=(const T num); void operator/=(const CrystVector &vect); void operator+=(const T num); void operator+=(const CrystVector &vect); void operator-=(const CrystVector &vect); /* Buggy ? (my version, not Blitz's!) // ListInitializer & ListInitializerSwitch are a simplified //version borrowed from the blitz++ library (see the blitz/listinit.h file) // // It allows a very convenient way of initializing arrays like this: // CrystVector arr(5); arr = 1,3,6,8,9; class ListInitializer { public: ListInitializer(T *pData):mpData(pData){}; ~ListInitializer(){cout << "toto";}; ListInitializer operator,(T x) { *mpData=x; return ListInitializer(mpData+1); } private: ListInitializer(){}; T *mpData; }; class ListInitializerSwitch { public: ListInitializerSwitch(CrystVector &vect, const T value): mVectData(vect.data()),mValue(value), mNumElements(vect.numElements()),wipeOnDestruct(true) {}; ~ListInitializerSwitch() { if(wipeOnDestruct) { //only one value given -> set all elements for(int i=0;i ostream& operator<<(ostream &os, CrystVector &vect); //Return the sorted subscripts of the array template CrystVector SortSubs(const CrystVector &vect); //Sort the array in place and also return the sorted subscripts template long QuickSortSubs(CrystVector &vect, CrystVector &subscript, long last,long first=0, int depth=0); ///Cosinus (slow routine, not memory-savy..) template CrystVector cos(const CrystVector &vect); ///Sinus (slow routine, not memory-savy...) template CrystVector sin(const CrystVector &vect); ///Tangent (slow routine, not memory-savy...) template CrystVector tan(const CrystVector &vect); ///Square root (slow routine, not memory-savy...) template CrystVector sqrt(const CrystVector &vect); //###################################################################### // CrystMatrix //###################################################################### /** \brief 2D Vector library (Blitz++ mimic) for ObjCryst++ * * The CrystVector library is not a new array computation library, despite * the appearances. ObjCryst++ should used the * Blitz++ array library , which yields * excellent performance \e and simple array expressions. Unfortunately, the memory * required to \e compile the library using gcc is far too high to be reasonable * when using complex expressions and optimizing code. So until this has changed, * The CrystVector and CrystMatrix library have been created, and these emulate * (supposedly exactly) the Blitz++ interface (but not the smart handling of * mathematical expressions, so pointers must be used). For documentation about these * two libraries you should read the * Blitz++ documentation. CrystVector and CrystMatrix use the same kind of storage * in memory. * * You can use CrystMatrix_REAL, CrystMatrix_long,etc... to declare 2D vectors. Macros * ensure (well, should) ensure compatibility with Blitz++. (as of april 2001 support of * blitz++ is broken). */ template class CrystMatrix { public: CrystMatrix(); //ySize : number of rows, xSize : number of columns CrystMatrix(const long ySize,const long xSize); CrystMatrix(const CrystMatrix &old); ~CrystMatrix(); void operator=(const CrystMatrix &old); void reference(CrystMatrix &old); long numElements()const; long size()const; T sum()const; T min()const; T max()const; long rows()const; long cols()const; T * data(); const T * data() const; void resize(const long ySize,const long xSize); void resizeAndPreserve(const long ySize,const long xSize); //void operator=(const T num); /// Element-by element multiplication (array-like) void operator*=(const T num); /// Element-by element multiplication (array-like) void operator*=(const CrystMatrix &vect); /// Element-by element division (array-like) void operator/=(const T num); /// Element-by element addition (array-like) void operator+=(const T num); /// Element-by element substraction (array-like) void operator-=(const T num); /// matrix multiplication (linear algebra) CrystMatrix Mult(const CrystMatrix &rhs); //:TODO: Check the following... // ListInitializer & ListInitializerSwitch are a simplified //version borrowed from the blitz++ library (see the blitz/listinit.h file) // // It allows a very convenient way of initializing arrays like this: // CrystVector arr(5); arr = 1,3,6,8,9; class ListInitializer { public: ListInitializer(T *pData):mpData(pData){}; ~ListInitializer(){}; ListInitializer operator,(T x) { *mpData=x; return ListInitializer(mpData+1); } private: ListInitializer(){}; T *mpData; }; class ListInitializerSwitch { public: ListInitializerSwitch(CrystMatrix &vect, const T value): mVectData(vect.data()),mValue(value), mNumElements(vect.numElements()),wipeOnDestruct(true) {}; ~ListInitializerSwitch() { if(wipeOnDestruct) { //only one value given -> set all elements for(int i=0;i ostream& operator<<(ostream &os, const CrystMatrix &vect); template T MaxDifference(const CrystVector &a,const CrystVector &b); template T MaxDifference(const CrystMatrix &a,const CrystMatrix &b); template CrystMatrix product(const CrystMatrix &a,const CrystMatrix &b); //###################################################################### // CrystArray3D //###################################################################### /** \brief 3D Vector (Blitz++ mimic) for ObjCryst++ * * The CrystVector library is not a new array computation library, despite * the appearances. ObjCryst++ should used the * Blitz++ array library , which yields * excellent performance \e and simple array expressions. Unfortunately, the memory * required to \e compile the library using gcc is far too high to be reasonable * when using complex expressions and optimizing code. So until this has changed, * The CrystVector and CrystMatrix library have been created, and these emulate * (supposedly exactly) the Blitz++ interface (but not the smart handling of * mathematical expressions, so pointers must be used). For documentation about these * two libraries you should read the * Blitz++ documentation. CrystVector and CrystMatrix use the same kind of storage * in memory. * * You can use CrystArray3D_REAL, CrystArray3D_long,etc... to declare 3D vectors. Macros * ensure (well, should) ensure compatibility with Blitz++. (as of april 2001 support of * blitz++ is broken). */ template class CrystArray3D { public: CrystArray3D(); //ySize : number of rows, xSize : number of columns CrystArray3D(const long zSize,const long ySize,const long xSize); CrystArray3D(const CrystArray3D &old); ~CrystArray3D(); void operator=(const CrystArray3D &old); void reference(CrystArray3D &old); long numElements()const; long size()const; T sum()const; T min()const; T max()const; long rows()const; long cols()const; long depth()const; T * data(); const T * data() const; void resize(const long zSize,const long ySize,const long xSize); void resizeAndPreserve(const long zSize,const long ySize,const long xSize); void operator=(const T num); void operator*=(const T num); void operator*=(const CrystArray3D &vect); void operator/=(const T num); void operator+=(const T num); void operator-=(const T num); //void operator=(const T num); T operator()(const long i) const; T operator()(const long depth,const long row,const long col) const; T& operator()(const long i); T& operator()(const long depth,const long row,const long col); protected: private: T *mpData; long mNumElements; long mXSize,mYSize,mZSize; bool mIsAreference;//is a reference to another vector ? }; template ostream& operator<<(ostream &os, const CrystArray3D &vect); #endif // __LIBCRYST_VECTOR_USE_BLITZ__ //Basic Gauss-Jordan elimination with partial pivot (rows only, using max pivot) //Definitly *not* optimized ! CrystMatrix_REAL InvertMatrix(const CrystMatrix_REAL &m); template void MatrixExchangeRows(CrystMatrix_T &m, const long row1, const long row2); ///Maximum absolute value of vector template T MaxAbs(const CrystVector_T &vector); ///Minimum absolute value of vector template T MinAbs(const CrystVector_T &vector); //###################################################################### // CubicSpline //###################################################################### /// Cubic spline interpolation. class CubicSpline { public: /// Default constructor - CubicSpline::Init() should be called afterwards CubicSpline(); /// Spline with given extremum derivatives CubicSpline(const CrystVector_REAL &x, const CrystVector_REAL &y, const REAL yp1, const REAL ypn); /// Spline with given extremum derivatives CubicSpline(const REAL *px, const REAL *py, const unsigned long nbPoints, const REAL yp1, const REAL ypn); /// Natural cubic spline CubicSpline(const CrystVector_REAL &x, const CrystVector_REAL &y); /// Natural cubic spline CubicSpline(const REAL *px, const REAL *py, const unsigned long nbPoints); ~CubicSpline(); /// Spline with given extremum derivatives void Init(const CrystVector_REAL &x, const CrystVector_REAL &y, const REAL yp1, const REAL ypn); /// Spline with given extremum derivatives void Init(const REAL *px, const REAL *py, const unsigned long nbPoints, const REAL yp1, const REAL ypn); /// Natural cubic spline void Init(const CrystVector_REAL &x, const CrystVector_REAL &y); /// Natural cubic spline void Init(const REAL *px, const REAL *py, const unsigned long nbPoints); /// Get spline value at a series of point - x is assumed to be sorted by increasing values CrystVector_REAL operator()(const CrystVector_REAL &x) const; /// Get spline value on a range of values with a fixed step CrystVector_REAL operator()(const REAL min,const REAL step, const long nbpoint) const; /// Get spline value at one point REAL operator()(const REAL x) const; private: void InitSpline(const REAL yp1, const REAL ypn); void InitNaturalSpline(); CrystVector_REAL mX; CrystVector_REAL mY; CrystVector_REAL mYsecond; }; //###################################################################### // Savitzky-Golay interpolation //###################################################################### /** Savitzky-Golay computing of smoothed data, using 2nd order polynomial coefficients * */ CrystVector_REAL SavitzkyGolay(const CrystVector_REAL &v, const unsigned int m, const unsigned int deriv); #endif // __LIBCRYST_VECTOR_H libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/000077500000000000000000000000001417150057700210445ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Atom.cpp000066400000000000000000000455151417150057700224620ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Atom.cpp * source file for the Atom scatterer * */ #include #include #include //for sprintf() #include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs.. #include "ObjCryst/Quirks/VFNDebug.h" #ifdef OBJCRYST_GL #ifdef __DARWIN__ #include #else #include #endif #endif #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxAtom.h" #endif #include #include namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // ATOM : the basic atom, within the crystal // //includes thermic factor (betas) and x,y,z,population // //////////////////////////////////////////////////////////////////////// Atom::Atom() :mScattCompList(1),mpScattPowAtom(0) { VFN_DEBUG_MESSAGE("Atom::Atom()",5) this->InitRefParList(); mScattCompList(0).mpScattPow=mpScattPowAtom; } Atom::Atom( const REAL x, const REAL y, const REAL z, const string &name,const ScatteringPower *pow) :mScattCompList(1),mpScattPowAtom(pow) { VFN_DEBUG_MESSAGE("Atom::Atom(x,y,z,name,ScatteringPower):"<Init(x,y,z,name,pow,1); } Atom::Atom( const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *pow,const REAL popu) :mScattCompList(1),mpScattPowAtom(pow) { VFN_DEBUG_MESSAGE("Atom::Atom(x,y,z,P,B,name,ScatteringPower):"<Init(x,y,z,name,mpScattPowAtom,popu); } Atom::Atom(const Atom &old) :Scatterer(old),mScattCompList(1),mpScattPowAtom(old.mpScattPowAtom) { VFN_DEBUG_MESSAGE("Atom::Atom(&old):/Name="<Init(old.mXYZ(0),old.mXYZ(1),old.mXYZ(2), old.mName,mpScattPowAtom, old.mOccupancy); this->GetPar(mXYZ.data()). CopyAttributes(old.GetPar(old.mXYZ.data())); this->GetPar(mXYZ.data()+1).CopyAttributes(old.GetPar(old.mXYZ.data()+1)); this->GetPar(mXYZ.data()+2).CopyAttributes(old.GetPar(old.mXYZ.data()+2)); this->GetPar(&mOccupancy). CopyAttributes(old.GetPar(&(old.mOccupancy))); } Atom* Atom::CreateCopy() const { VFN_DEBUG_MESSAGE("Atom::CreateCopy():/Name="<DeRegisterClient(*this); } const string& Atom::GetClassName()const { const static string className="Atom"; return className; } void Atom::operator=(const Atom &rhs) { VFN_DEBUG_MESSAGE("Atom::operator=():/Name="<Init(rhs.mXYZ(0),rhs.mXYZ(1),rhs.mXYZ(2), rhs.mName,rhs.mpScattPowAtom, rhs.mOccupancy); this->GetPar(mXYZ.data()). CopyAttributes(rhs.GetPar(rhs.mXYZ.data())); this->GetPar(mXYZ.data()+1).CopyAttributes(rhs.GetPar(rhs.mXYZ.data()+1)); this->GetPar(mXYZ.data()+2).CopyAttributes(rhs.GetPar(rhs.mXYZ.data()+2)); this->GetPar(&mOccupancy). CopyAttributes(rhs.GetPar(&(rhs.mOccupancy))); } void Atom::Init(const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *pow, const REAL popu) { VFN_DEBUG_MESSAGE("Atom::Init():"<GetName();} void Atom::Print() const { VFN_DEBUG_MESSAGE("Atom::Print()",1) if(this->IsDummy()) { cout << "Atom (DUMMY) :" << FormatString(this->GetName(),16) << " at : " << FormatFloat(this->GetX()) << FormatFloat(this->GetY()) << FormatFloat(this->GetZ()); } else { cout << "Atom (" << FormatString(mpScattPowAtom->GetSymbol(),4) << ") :" << FormatString(this->GetName(),16) << " at : " << FormatFloat(this->GetX()) << FormatFloat(this->GetY()) << FormatFloat(this->GetZ()) << ", Biso=" << FormatFloat(mpScattPowAtom->GetBiso()) << ", Popu=" << FormatFloat(this->GetOccupancy()); } cout << endl; } REAL Atom::GetMass() const { if(true==this->IsDummy()) return 0; return mpScattPowAtom->GetBiso(); } REAL Atom::GetRadius() const { if(this->IsDummy()) return 0.5; return mpScattPowAtom->GetRadius(); } ostream& Atom::POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const { if(this->IsDummy()) return os; if(options.mShowHydrogens==false && (mpScattPowAtom->GetForwardScatteringFactor(RAD_XRAY)<1.5)) return os; const REAL xMin=options.mXmin; const REAL xMax=options.mXmax; const REAL yMin=options.mYmin; const REAL yMax=options.mYmax; const REAL zMin=options.mZmin; const REAL zMax=options.mZmax; REAL x0,y0,z0; x0=mXYZ(0); y0=mXYZ(1); z0=mXYZ(2); const REAL aa=this->GetCrystal().GetLatticePar(0); const REAL bb=this->GetCrystal().GetLatticePar(1); const REAL cc=this->GetCrystal().GetLatticePar(2); CrystMatrix_REAL xyzCoords ; xyzCoords=this->GetCrystal().GetSpaceGroup().GetAllSymmetrics(x0,y0,z0,false,false,true); int nbSymmetrics=xyzCoords.rows(); os << "// Description of Atom :" << this->GetName()<< endl; for(int i=0;i=xMin) && (x<=xMax)) && ((y>=yMin) && (y<=yMax)) && ((z>=zMin) && (z<=zMax)); REAL borderdist; if(isinside) borderdist=0; else { borderdist=0; if(xMin>x) borderdist+=(xMin-x)*aa*(xMin-x)*aa; if(yMin>y) borderdist+=(yMin-y)*bb*(yMin-y)*bb; if(zMin>z) borderdist+=(zMin-z)*cc*(zMin-z)*cc; if(xMaxGetCrystal().GetDynPopCorr(this,0); if(fout>0.001) { this->GetCrystal().FractionalToOrthonormalCoords(x,y,z); os << " ObjCrystAtom(" <GetScatteringPower().GetRadius()/3.0<<"," <<"colour_"+this->GetScatteringPower().GetName()<<"," <GetOccupancy()<<","<GetName(),5) if(this->IsDummy()) return ; REAL en=1; if(displayEnantiomer==true) en=-1; const float r=mpScattPowAtom->GetColourRGB()[0]; const float g=mpScattPowAtom->GetColourRGB()[1]; const float b=mpScattPowAtom->GetColourRGB()[2]; const float f=mOccupancy; const GLfloat colour0[] = {.0, .0, .0, 0.0}; GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } const REAL aa=this->GetCrystal().GetLatticePar(0); const REAL bb=this->GetCrystal().GetLatticePar(1); const REAL cc=this->GetCrystal().GetLatticePar(2); if(hideHydrogens && (mpScattPowAtom->GetForwardScatteringFactor(RAD_XRAY)<1.5)) return; GLUquadricObj* pQuadric = gluNewQuadric(); if(true==onlyIndependentAtoms) { const GLfloat colourAtom [] = {r, g, b, f}; REAL x,y,z; x=mXYZ(0); y=mXYZ(1); z=mXYZ(2); x = fmod((REAL)x,(int)1); if(x<0) x+=1.; y = fmod((REAL)y,(int)1); if(y<0) y+=1.; z = fmod((REAL)z,(int)1); if(z<0) z+=1.; this->GetCrystal().FractionalToOrthonormalCoords(x,y,z); glPushMatrix(); glTranslatef(x*en, y, z); if(displayNames) { glMaterialfv(GL_FRONT, GL_AMBIENT, colour0); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glRasterPos3f(0,0,0); crystGLPrint(this->GetName()); } else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colourAtom); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glPolygonMode(GL_FRONT, GL_FILL); gluSphere(pQuadric,this->GetRadius()/3.,20,20); } glPopMatrix(); } else { REAL x0,y0,z0; x0=mXYZ(0); y0=mXYZ(1); z0=mXYZ(2); CrystMatrix_REAL xyzCoords ; xyzCoords=this->GetCrystal().GetSpaceGroup().GetAllSymmetrics(x0,y0,z0,false,false,true); int nbSymmetrics=xyzCoords.rows(); for(int i=0;i=xMin) && (x<=xMax)) && ((y>=yMin) && (y<=yMax)) && ((z>=zMin) && (z<=zMax)); REAL borderdist; if(isinside) borderdist=0; else { borderdist=0; if(xMin>x) borderdist+=(xMin-x)*aa*(xMin-x)*aa; if(yMin>y) borderdist+=(yMin-y)*bb*(yMin-y)*bb; if(zMin>z) borderdist+=(zMin-z)*cc*(zMin-z)*cc; if(xMaxfadeDistance) fout = 0; else fout*=(fadeDistance-borderdist)/fadeDistance*this->GetCrystal().GetDynPopCorr(this,0); } if(fout>0.01) { const GLfloat colourAtom [] = {r, g, b, f*fout}; this->GetCrystal().FractionalToOrthonormalCoords(x,y,z); glPushMatrix(); glTranslatef(x*en, y, z); if(displayNames) { if(fout>0.99) { glMaterialfv(GL_FRONT, GL_AMBIENT, colour0); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glRasterPos3f(0,0,0); crystGLPrint(this->GetName()); } } else { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, colourAtom); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glPolygonMode(GL_FRONT, GL_FILL); gluSphere(pQuadric,this->GetRadius()/3.,20,20); } glPopMatrix(); } } } } gluDeleteQuadric(pQuadric); VFN_DEBUG_MESSAGE("Atom::GLInitDisplayList():End",5) } #endif // OBJCRYST_GL bool Atom::IsDummy()const { if(0==mScattCompList(0).mpScattPow) return true; return false;} const ScatteringPower& Atom::GetScatteringPower()const { return *mpScattPowAtom;} void Atom::SetScatteringPower(const ScatteringPower &p) { if(mpScattPowAtom!=&p) { if(mpScattPowAtom!=0) mpScattPowAtom->DeRegisterClient(*this); mpScattPowAtom = &p; mScattCompList(0).mpScattPow=mpScattPowAtom; mClockScatterer.Click(); if(mpScattPowAtom!=0) mpScattPowAtom->RegisterClient(*this); } } void Atom::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { //One group for all translation parameters unsigned int posIndex=0; VFN_DEBUG_MESSAGE("Atom::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattTransl)) { if(posIndex==0) posIndex=first++; groupIndex(i)=posIndex; } else groupIndex(i)= first++; } } void Atom::InitRefParList() { mClockScatterer.Click(); VFN_DEBUG_MESSAGE("Atom::InitRefParList()",5) this->ResetParList(); //:TODO: Add thermic factors { RefinablePar tmp("x",&mXYZ(0),0,1.,gpRefParTypeScattTranslX, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("y",&mXYZ(1),0,1.,gpRefParTypeScattTranslY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("z",&mXYZ(2),0,1.,gpRefParTypeScattTranslZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } if(false==this->IsDummy()) { { RefinablePar tmp(this->GetName()+(string)"occup",&mOccupancy,0.01,1., gpRefParTypeScattOccup,REFPAR_DERIV_STEP_ABSOLUTE,true,true); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(.2); this->AddPar(tmp); } } } #ifdef __WX__CRYST__ WXCrystObjBasic* Atom::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXAtom(parent,this); return mpWXCrystObj; } #endif }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Atom.h000066400000000000000000000157261417150057700221300ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Atom.h * header file for the Atom scatterer * */ #ifndef _OBJCRYST_ATOM_H_ #define _OBJCRYST_ATOM_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/ObjCryst/Scatterer.h" //#include #include //#include //#include //#include //#include //#include //using namespace std; namespace ObjCryst { //###################################################################### // /// The basic atom scatterer, in a crystal. /// /// This class records the position of the atom, and has a pointer to its /// ScatteringPowerAtom. /// /// \note there can be 'Dummy' atoms, for which the used symbol is "X", /// and which have no scattering power (use with caution: dummy atoms /// are only supposed to be used within ZScatterer) //###################################################################### class Atom: public Scatterer { public: /// Default constructor. The Atom \e must be initialized thereafter /// using Atom::Init() Atom(); /** \brief Atom constructor * \param x,y,z : \e fractional coordinates of the atom * \param pow : the ScatteringPower associated to this atom. Must be allocated separately. * \param name : name of the atom ('Ta1','Sm2', 'Tungsten_1'...). * The name can have \e any format but spaces should be avoided. */ Atom( const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *pow); /** \brief Atom constructor * \param x,y,z : \e fractional coordinates of the atom * \param popu : the population of the atom (0.0->1.0) * This should take into account the multiplicity of the atom. For * an atom in group P2 and on the 2 axis, this should be set to 0.5, * \b unless you are using the dynamical occupancy correction (recommended * for global optimizations). See Crystal::CalcDynPopCorr() and * Crystal::mUseDynPopCorr * * \param pow : the ScatteringPower associated to this atom. Must be allocated separatly. * \param name : name of the atom ('Ta1','Sm2', 'Tungsten_1'...). * The name can have \e any format but spaces should be avoided (just a precaution) */ Atom( const REAL x, const REAL y, const REAL z,const string &name, const ScatteringPower *pow, const REAL popu); /// Copy constructor Atom(const Atom &old); virtual Atom* CreateCopy() const; /// Destructor... ~Atom(); virtual const string& GetClassName() const; /// virtual void operator=(const Atom & rhs); /** initialize the atom (used for arrays of atoms). * \param x,y,z : \e fractional coordinates of the atom * \param pow : the ScatteringPower associated to this atom. Must be allocated separately. * \param name : name of the atom ('Ta1','Sm2', 'Tungsten_1'...). */ void Init(const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *pow, const REAL popu=1); virtual int GetNbComponent() const; virtual const ScatteringComponentList& GetScatteringComponentList() const; virtual string GetComponentName(const int i) const; virtual void Print() const; /** \brief Returns the molar mass of the atom. * * Values are extracted from the 'atominfo' package, * which uses data from the CRC Handbook of Chemistry & Physics, 63rd & 70th editions * The Mass is actually extracted from the ScatteringPowerAtom. */ REAL GetMass() const; /** \brief Returns the radius (in Angstroems) of the atom. * * Values are extracted from the 'atominfo' package, * which uses data from the ICSD/CRYSTIN Manual * The Radius is extracted from the ScatteringPowerAtom. */ REAL GetRadius() const; /** \brief XMLOutput a description of the scatterer for POVRay * */ virtual ostream& POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const; #ifdef OBJCRYST_GL virtual void GLInitDisplayList(const bool noSymmetrics=false, const REAL xMin=-.1,const REAL xMax=1.1, const REAL yMin=-.1,const REAL yMax=1.1, const REAL zMin=-.1,const REAL zMax=1.1, const bool displayEnantiomer=false, const bool displayNames=false, const bool hideHydrogens=false, const REAL fadeDistance=0, const bool fullMoleculeInLimits=false)const; #endif // OBJCRYST_GL /// Is this a dummy atom ? (ie no ScatteringPower) /// Dummy atoms should not exist ! bool IsDummy()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); /// Get the ScatteringPowerAtom corresponding to this atom. const ScatteringPower& GetScatteringPower()const; /// Change the ScatteringPower for this atom void SetScatteringPower(const ScatteringPower &pow); virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; protected: private: /// Prepare refinable parameters for the scatterer object virtual void InitRefParList(); /// The list of scattering components. mutable ScatteringComponentList mScattCompList; /// The ScatteringPowerAtom associated to that atom const ScatteringPower *mpScattPowAtom; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXAtom; #endif }; }//namespace Objcryst // do we need this ? #include "ObjCryst/ObjCryst/Crystal.h" #endif //_OBJCRYST_ATOM_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/CIF.cpp000066400000000000000000001511541417150057700221600ustar00rootroot00000000000000#include #include #include #include "cctbx/sgtbx/space_group.h" #include "cctbx/sgtbx/space_group_type.h" #include "cctbx/miller/sym_equiv.h" #include "cctbx/sgtbx/brick.h" #include "ObjCryst/ObjCryst/CIF.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/ObjCryst/PowderPattern.h" #include "ObjCryst/Quirks/Chronometer.h" #define POSSIBLY_UNUSED(expr) (void)(expr) using namespace std; namespace ObjCryst { CIFData::CIFAtom::CIFAtom(): mLabel(""),mSymbol(""),mOccupancy(1.0),mBiso(0.0) {} CIFData::CIFData() {} void CIFData::ExtractAll(const bool verbose) { (*fpObjCrystInformUser)("CIF: Extract Data..."); // :TODO: convert cartesian to fractional coordinates and vice-versa, if unit cell is known // :TODO: Take care of values listed as "." and "?" instead of a real value. this->ExtractName(verbose); this->ExtractUnitCell(verbose); this->ExtractSpacegroup(verbose); this->ExtractAtomicPositions(verbose); this->ExtractAnisotropicADPs(verbose); this->ExtractPowderPattern(verbose); this->ExtractSingleCrystalData(verbose); (*fpObjCrystInformUser)("CIF: Finished Extracting Data..."); } void CIFData::ExtractUnitCell(const bool verbose) { map::const_iterator positem; positem=mvItem.find("_cell_length_a"); if(positem!=mvItem.end()) { (*fpObjCrystInformUser)("CIF: Extract Unit Cell..."); mvLatticePar.resize(6); mvLatticePar[0]=CIFNumeric2REAL(positem->second); positem=mvItem.find("_cell_length_b"); if(positem!=mvItem.end()) mvLatticePar[1]=CIFNumeric2REAL(positem->second); positem=mvItem.find("_cell_length_c"); if(positem!=mvItem.end()) mvLatticePar[2]=CIFNumeric2REAL(positem->second); positem=mvItem.find("_cell_angle_alpha"); if(positem!=mvItem.end()) mvLatticePar[3]=CIFNumeric2REAL(positem->second); positem=mvItem.find("_cell_angle_beta"); if(positem!=mvItem.end()) mvLatticePar[4]=CIFNumeric2REAL(positem->second); positem=mvItem.find("_cell_angle_gamma"); if(positem!=mvItem.end()) mvLatticePar[5]=CIFNumeric2REAL(positem->second); if(verbose) cout<<"Found Lattice parameters:" <CalcMatrices(); } } void CIFData::ExtractSpacegroup(const bool verbose) { map::const_iterator positem; positem=mvItem.find("_space_group_IT_number"); if(positem!=mvItem.end()) { mSpacegroupNumberIT=positem->second;//CIFNumeric2Int() if(verbose) cout<<"Found spacegroup IT number:"<second;//CIFNumeric2Int() if(verbose) cout<<"Found spacegroup IT number (with OBSOLETE CIF #1.0 TAG):"<second; if(verbose) cout<<"Found spacegroup Hall symbol:"<second; if(verbose) cout<<"Found spacegroup Hall symbol (with OBSOLETE CIF #1.0 TAG):"<second; if(verbose) cout<<"Found spacegroup Hermann-Mauguin symbol:"<second; if(verbose) cout<<"Found spacegroup Hall Hermann-Mauguin (with OBSOLETE CIF #1.0 TAG):"<,map > >::const_iterator loop=mvLoop.begin(); loop!=mvLoop.end();++loop) { if(mvSymmetry_equiv_pos_as_xyz.size()>0) break;// only extract ONE list of symmetry strings map >::const_iterator pos; pos=loop->second.find("_symmetry_equiv_pos_as_xyz"); if(pos!=loop->second.end()) { if(verbose) cout<<"Found list of _symmetry_equiv_pos_as_xyz:"<second.size();++i) { if(verbose) cout<<" "<second[i]<second[i]); } } } } void CIFData::ExtractName(const bool verbose) { map::const_iterator positem; positem=mvItem.find("_chemical_name_systematic"); if(positem!=mvItem.end()) { mName=positem->second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical name:"<second; if(verbose) cout<<"Found chemical formula:"<second; if(verbose) cout<<"Found chemical formula:"<second; if(verbose) cout<<"Found chemical formula:"<second; if(verbose) cout<<"Found chemical formula:"<::const_iterator positem; for(map,map > >::const_iterator loop=mvLoop.begin(); loop!=mvLoop.end();++loop) { if(mvAtom.size()>0) break;// only extract ONE list of atoms, preferably fractional coordinates map >::const_iterator posx,posy,posz,poslabel,possymbol,posoccup,posadp; posx=loop->second.find("_atom_site_fract_x"); posy=loop->second.find("_atom_site_fract_y"); posz=loop->second.find("_atom_site_fract_z"); unsigned int nb = 0; if( (posx!=loop->second.end()) && (posy!=loop->second.end()) && (posz!=loop->second.end())) { nb=posx->second.size(); mvAtom.resize(nb); for(unsigned int i=0;isecond[i]); mvAtom[i].mCoordFrac[1]=CIFNumeric2REAL(posy->second[i]); mvAtom[i].mCoordFrac[2]=CIFNumeric2REAL(posz->second[i]); } this->Fractional2CartesianCoord(); } else { posx=loop->second.find("_atom_site_Cartn_x"); posy=loop->second.find("_atom_site_Cartn_y"); posz=loop->second.find("_atom_site_Cartn_z"); if( (posx!=loop->second.end()) && (posy!=loop->second.end()) && (posz!=loop->second.end())) { nb=posx->second.size(); mvAtom.resize(nb); for(unsigned int i=0;isecond[i]); mvAtom[i].mCoordCart[1]=CIFNumeric2REAL(posy->second[i]); mvAtom[i].mCoordCart[2]=CIFNumeric2REAL(posz->second[i]); } this->Cartesian2FractionalCoord(); } } if(mvAtom.size()>0) {// Got the atoms, get names, symbols and adps (*fpObjCrystInformUser)("CIF: Extract Atoms..."); possymbol=loop->second.find("_atom_site_type_symbol"); if(possymbol!=loop->second.end()) for(unsigned int i=0;isecond[i]; poslabel=loop->second.find("_atom_site_label"); if(poslabel!=loop->second.end()) for(unsigned int i=0;isecond[i]; if(possymbol==loop->second.end()) {// There was no symbol, use the labels to guess it int nbc=0; if(mvAtom[i].mLabel.size()==1) if(isalpha(mvAtom[i].mLabel[0])) nbc=1; if(mvAtom[i].mLabel.size()>=2) { if(isalpha(mvAtom[i].mLabel[0]) && isalpha(mvAtom[i].mLabel[1])) nbc=2; else if(isalpha(mvAtom[i].mLabel[0])) nbc=1; } if(nbc>0) mvAtom[i].mSymbol=mvAtom[i].mLabel.substr(0,nbc); else mvAtom[i].mSymbol="H";//Something wen wrong, no symbol ! } } // Occupancy ? posoccup=loop->second.find("_atom_site_occupancy"); if(posoccup!=loop->second.end()) for(unsigned int i=0;isecond[i]); // ADPs - Record ani, ovl or mpl as iso. REAL mult = 1.0; posadp=loop->second.find("_atom_site_B_iso_or_equiv"); if(posadp==loop->second.end()) { mult = 8 * M_PI * M_PI; posadp=loop->second.find("_atom_site_U_iso_or_equiv"); } if(posadp!=loop->second.end()) for(unsigned int i=0;isecond[i]); // Now be somewhat verbose if(verbose) { cout << "Found "<0) { cout<<" , Fractional: "; for(unsigned int j=0;j0) { cout<<" , Cartesian: "; for(unsigned int j=0;jsecond.find("_atom_site_aniso_label"); // Move to the next loop if we can't find it here. if (anisolabels == loop->second.end()) continue; if(verbose) cout << "Found labels!" << endl; // We have a list of labels. Position the iterators for each of the // adps. for (int idx = 0; idx < 6; ++idx) { EntryIter& betaiter = *betaiters[idx]; betaiter = loop->second.find(bijlabels[idx]); mult[idx] = 1.0; if(betaiter == loop->second.end()) { betaiter = loop->second.find(uijlabels[idx]); mult[idx] = utob; } if(betaiter == loop->second.end()) mult[idx] = 0.0; } // Check that we have values. If not, then we can get out of here. bool havedata = false; for (int i = 0; i < 6; ++i) { if( mult[i] != 0 ) havedata = true; } if (!havedata) return; // Now loop over the labels, find the corresponding CIFAtom, and fill in // its information. size_t nb = anisolabels->second.size(); if(verbose) cout << "Have " << nb << " labels." << endl; for (size_t i = 0; i < nb; ++i) { string label = anisolabels->second[i]; if(verbose) cout << label << endl; // See if we have a CIFAtom with this label. If so, initialize the mBeta // vector. vector::iterator atom = mvAtom.begin(); for (; atom != mvAtom.end(); ++atom) { if (atom->mLabel == label) { atom->mBeta.resize(6, 0.0); break; } } // If we didn't find the mvAtom, then we should move on to the next // label. if (atom == mvAtom.end()) continue; // Fill in what we've got, one entry at a time. for (int idx=0; idx<6; ++idx) { if (mult[idx] == 0) { if(verbose) cout << "skipping index " << idx << endl; continue; } EntryIter& betaiter = *betaiters[idx]; if (betaiter->second.size() <= i) continue; double beta = CIFNumeric2REAL(betaiter->second[i]); atom->mBeta[idx] = mult[idx] * beta; if(verbose) cout << "mBeta " << idx << " " << atom->mBeta[idx] << endl; } } } return; } /// This is the default wavelength - whenever a "_diffrn_radiation_wavelength" or /// "_pd_proc_wavelength"entry is found, /// it is used as a new value for the default wavelength. Since the powder CIFs do not /// include the wavelength, this could be useful if the crystal structure CIF (including /// the wavelength) is parsed right before the powder pattern one. static REAL defaultWavelength=1.0; void CIFData::ExtractPowderPattern(const bool verbose) { map::const_iterator positem; positem=mvItem.find("_diffrn_radiation_wavelength"); if(positem==mvItem.end()) positem=mvItem.find("_pd_proc_wavelength"); if(positem!=mvItem.end()) { mWavelength=CIFNumeric2REAL(positem->second); defaultWavelength=mWavelength; if(verbose) cout<<"Found wavelength:"<,map > >::const_iterator loop=mvLoop.begin(); loop!=mvLoop.end();++loop) { mDataType=WAVELENGTH_MONOCHROMATIC; map >::const_iterator pos_x,pos_iobs,pos_weight,pos_mon,pos_wavelength; pos_wavelength=loop->second.find("_diffrn_radiation_wavelength"); if(pos_wavelength!=loop->second.end()) { if(verbose) cout<<"Found wavelength (in loop):"<second[0]; mWavelength=CIFNumeric2REAL(pos_wavelength->second[0]); defaultWavelength=mWavelength; if(verbose) cout<<" -> "<second.find("_pd_meas_counts_total"); if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_meas_intensity_total"); if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_proc_intensity_total"); if(pos_iobs==loop->second.end()) pos_iobs=loop->second.find("_pd_proc_intensity_net"); if(pos_iobs==loop->second.end()) continue;//no observed powder data found pos_weight=loop->second.find("_pd_proc_ls_weight"); pos_x=loop->second.find("_pd_proc_2theta_corrected"); if(pos_x==loop->second.end()) pos_x=loop->second.find("_pd_meas_angle_2theta"); if(pos_x==loop->second.end()) pos_x=loop->second.find("_pd_meas_2theta_scan"); if(pos_x==loop->second.end()) { pos_x=loop->second.find("_pd_meas_time_of_flight"); if(pos_x!=loop->second.end()) mDataType=WAVELENGTH_TOF; } bool x_fixed_step=false; REAL xmin = 0, xmax = 0, xinc = 0; POSSIBLY_UNUSED(xmax); if(pos_x==loop->second.end()) { map::const_iterator pos_min,pos_max,pos_inc; pos_min=mvItem.find("_pd_proc_2theta_range_min"); if(pos_min==mvItem.end()) pos_min=mvItem.find("_pd_meas_2theta_range_min"); pos_max=mvItem.find("_pd_proc_2theta_range_max"); if(pos_max==mvItem.end()) pos_max=mvItem.find("_pd_meas_2theta_range_max"); pos_inc=mvItem.find("_pd_proc_2theta_range_inc"); if(pos_inc==mvItem.end()) pos_inc=mvItem.find("_pd_meas_2theta_range_inc"); if((pos_min!=mvItem.end()) && (pos_max!=mvItem.end()) && (pos_inc!=mvItem.end()) ) { x_fixed_step=true; xmin=CIFNumeric2REAL(pos_min->second); xmax=CIFNumeric2REAL(pos_max->second); xinc=CIFNumeric2REAL(pos_inc->second); } } pos_mon=loop->second.find("_pd_meas_intensity_monitor"); if(pos_mon==loop->second.end()) pos_mon=loop->second.find("_pd_meas_step_count_time"); if( (pos_iobs!=loop->second.end()) && ( (pos_x!=loop->second.end()) || (x_fixed_step)) ) {// Found powder data ! const long nb=pos_iobs->second.size(); if(verbose) cout<<"Found powder data, with "<second[i]); if(x_fixed_step) mPowderPatternX[i]=(xmin+i*xinc)*mult; else mPowderPatternX[i]=CIFNumeric2REAL(pos_x->second[i])*mult; // :TODO: use esd on observed intensity, if available. if(pos_weight!=loop->second.end()) { mPowderPatternSigma[i]=CIFNumeric2REAL(pos_weight->second[i]); if(mPowderPatternSigma[i]>0) mPowderPatternSigma[i]=1/sqrt(fabs(mPowderPatternSigma[i])); else mPowderPatternSigma[i]=sqrt(fabs(mPowderPatternObs[i])); // :KLUDGE: ? } else mPowderPatternSigma[i]=sqrt(fabs(mPowderPatternObs[i])); if(pos_mon!=loop->second.end()) {//VCT or monitor const REAL mon=CIFNumeric2REAL(pos_mon->second[i]); if(mon>0) { mPowderPatternObs[i]/=mon; mPowderPatternSigma[i]/=sqrt(mon); } } //if((i<10) && verbose) cout<::const_iterator positem; positem=mvItem.find("_diffrn_radiation_wavelength"); if(positem==mvItem.end()) positem=mvItem.find("_pd_proc_wavelength"); if(positem!=mvItem.end()) { mWavelength=CIFNumeric2REAL(positem->second); defaultWavelength=mWavelength; if(verbose) cout<<"Found wavelength:"<,map > >::const_iterator loop=mvLoop.begin(); loop!=mvLoop.end();++loop) { mDataType=WAVELENGTH_MONOCHROMATIC; map >::const_iterator pos_h,pos_k,pos_l,pos_iobs,pos_sigma,pos_wavelength; pos_wavelength=loop->second.find("_diffrn_radiation_wavelength"); if(pos_wavelength!=loop->second.end()) { if(verbose) cout<<"Found wavelength (in loop):"<second[0]; mWavelength=CIFNumeric2REAL(pos_wavelength->second[0]); defaultWavelength=mWavelength; if(verbose) cout<<" -> "<second.find("_refln_F_squared_meas"); if(pos_iobs==loop->second.end()) continue;//no observed powder data found pos_sigma=loop->second.find("_refln_F_squared_sigma"); pos_h=loop->second.find("_refln_index_h"); pos_k=loop->second.find("_refln_index_k"); pos_l=loop->second.find("_refln_index_l"); if( (pos_iobs!=loop->second.end()) && (pos_h!=loop->second.end()) && (pos_k!=loop->second.end()) && (pos_l!=loop->second.end())) {// Found single crystal data ! const long nb=pos_iobs->second.size(); if(verbose) cout<<"Found single crystal data, with "<second[i]); mH(i)=CIFNumeric2Int(pos_h->second[i]); mK(i)=CIFNumeric2Int(pos_k->second[i]); mL(i)=CIFNumeric2Int(pos_l->second[i]); if(pos_sigma!=loop->second.end()) mSigma(i)=CIFNumeric2REAL(pos_sigma->second[i]); else mSigma(i)=sqrt(fabs(abs(mIobs(i)))); } } } } void CIFData::CalcMatrices(const bool verbose) { if(mvLatticePar.size()==0) return;//:TODO: throw error REAL a,b,c,alpha,beta,gamma;//direct space parameters REAL aa,bb,cc,alphaa,betaa,gammaa;//reciprocal space parameters POSSIBLY_UNUSED(aa); POSSIBLY_UNUSED(bb); POSSIBLY_UNUSED(betaa); POSSIBLY_UNUSED(gammaa); REAL v;//volume of the unit cell a=mvLatticePar[0]; b=mvLatticePar[1]; c=mvLatticePar[2]; alpha=mvLatticePar[3]; beta=mvLatticePar[4]; gamma=mvLatticePar[5]; v=sqrt(fabs(1-cos(alpha)*cos(alpha)-cos(beta)*cos(beta)-cos(gamma)*cos(gamma) +2*cos(alpha)*cos(beta)*cos(gamma))); aa=sin(alpha)/a/v; bb=sin(beta )/b/v; cc=sin(gamma)/c/v; alphaa=acos( (cos(beta )*cos(gamma)-cos(alpha))/sin(beta )/sin(gamma) ); betaa =acos( (cos(alpha)*cos(gamma)-cos(beta ))/sin(alpha)/sin(gamma) ); gammaa=acos( (cos(alpha)*cos(beta )-cos(gamma))/sin(alpha)/sin(beta ) ); mOrthMatrix[0][0]=a; mOrthMatrix[0][1]=b*cos(gamma); mOrthMatrix[0][2]=c*cos(beta); mOrthMatrix[1][0]=0; mOrthMatrix[1][1]=b*sin(gamma); mOrthMatrix[1][2]=-c*sin(beta)*cos(alphaa); mOrthMatrix[2][0]=0; mOrthMatrix[2][1]=0; mOrthMatrix[2][2]=1/cc; // Invert upper triangular matrix REAL cm[3][3]; cm[0][0]=mOrthMatrix[0][0]; cm[0][1]=mOrthMatrix[0][1]; cm[0][2]=mOrthMatrix[0][2]; cm[1][0]=mOrthMatrix[1][0]; cm[1][1]=mOrthMatrix[1][1]; cm[1][2]=mOrthMatrix[1][2]; cm[2][0]=mOrthMatrix[2][0]; cm[2][1]=mOrthMatrix[2][1]; cm[2][2]=mOrthMatrix[2][2]; for(long i=0;i<3;i++) for(long j=0;j<3;j++) if(i==j) mOrthMatrixInvert[i][j]=1; else mOrthMatrixInvert[i][j]=0; for(long i=0;i<3;i++) { REAL a; for(long j=i-1;j>=0;j--) { a=cm[j][i]/cm[i][i]; for(long k=0;k<3;k++) mOrthMatrixInvert[j][k] -= mOrthMatrixInvert[i][k]*a; for(long k=0;k<3;k++) cm[j][k] -= cm[i][k]*a; } a=cm[i][i]; for(long k=0;k<3;k++) mOrthMatrixInvert[i][k] /= a; for(long k=0;k<3;k++) cm[i][k] /= a; } if(verbose) { cout <<"Fractional2Cartesian matrix:"<::iterator pos=mvAtom.begin();pos!=mvAtom.end();++pos) { pos->mCoordFrac.resize(3); pos->mCoordFrac[0]=pos->mCoordCart.at(0); pos->mCoordFrac[1]=pos->mCoordCart.at(1); pos->mCoordFrac[2]=pos->mCoordCart.at(2); c2f(pos->mCoordFrac[0],pos->mCoordFrac[1],pos->mCoordFrac[2]); } } void CIFData::Fractional2CartesianCoord() { for(vector::iterator pos=mvAtom.begin();pos!=mvAtom.end();++pos) { pos->mCoordCart.resize(3); pos->mCoordCart[0]=pos->mCoordFrac.at(0); pos->mCoordCart[1]=pos->mCoordFrac.at(1); pos->mCoordCart[2]=pos->mCoordFrac.at(2); f2c(pos->mCoordCart[0],pos->mCoordCart[1],pos->mCoordCart[2]); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// CIF::CIF(istream &is, const bool interpret,const bool verbose) { string s; (*fpObjCrystInformUser)("CIF: Opening CIF"); Chronometer chrono; chrono.start(); //Copy to an iostream so that we can put back characters if necessary stringstream in; char c; while(is.get(c))in.put(c); const float t0read=chrono.seconds(); s=(boost::format("CIF: Parsing CIF (reading dt=%5.3fs)")%t0read).str(); (*fpObjCrystInformUser)(s); this->Parse(in); const float t1parse=chrono.seconds(); s=(boost::format("CIF: Finished Parsing, Extracting...(parsing dt=%5.3fs)") % (t1parse-t0read)).str(); (*fpObjCrystInformUser)(s); // Extract structure from blocks if(interpret) for(map::iterator posd=mvData.begin();posd!=mvData.end();++posd) posd->second.ExtractAll(verbose); const float t2interpret=chrono.seconds(); s=(boost::format("CIF: Finished Import...(interpret dt=%5.3fs, total CIF import=%5.3fs)")%(t2interpret-t1parse)%t2interpret).str(); (*fpObjCrystInformUser)(s); } bool iseol(const char c) { return ((c=='\n')||(c=='\r'));} std::string trimString(const std::string &s) { const size_t i0 = s.find_first_not_of(" \t\r\n"); if (i0 == std::string::npos) return ""; const size_t i1 = s.find_last_not_of(" \t\r\n"); return s.substr(i0, i1-i0+1); } /// Read one value, whether it is numeric, string or text string CIFReadValue(stringstream &in,char &lastc) { bool vv=false;//very verbose ? string value; while(!isgraph(in.peek())) in.get(lastc); while(in.peek()=='#') {//discard these comments for now string tmp; getline(in,tmp); lastc='\r'; while(!isgraph(in.peek())) in.get(lastc); } if(in.peek()==';') {//SemiColonTextField bool warning=!iseol(lastc); if(warning) cout<<"WARNING: Trying to read a SemiColonTextField but last char is not an end-of-line char !"<>value; if(vv) cout<<"NormalValue:"<>tag; // Convert all dots to underscores to cover much of DDL2 with this DDL1 parser. for (string::size_type pos = tag.find('.'); pos != string::npos; pos = tag.find('.', ++ pos)) tag.replace(pos, 1, 1, '_'); value=CIFReadValue(in,lastc); if(value==string("?")) continue;//useless mvData[block].mvItem[ci_string(tag.c_str())]=value; if(vv)cout<<"New Tag:"<>tmp; block=tmp.substr(5); if(vv) cout<"< tit; string tmp; in>>tmp; //should be loop_ if(vv) cout<<"LOOP : "<>tmp; // Convert all dots to underscores to cover much of DDL2 with this DDL1 parser. for (string::size_type pos = tmp.find('.'); pos != string::npos; pos = tmp.find('.', ++ pos)) tmp.replace(pos, 1, 1, '_'); tit.push_back(ci_string(tmp.c_str())); if(vv) cout<<" , "< > lp; while(true) { while(!isgraph(in.peek()) && !in.eof()) in.get(lastc); if(in.eof()) break; if(vv) cout<<"LOOP VALUES...: "<<(char)in.peek()<<" "<>tmp; if(vv) cout<<"WHATNEXT? "<=5) if(ci_string(tmp.substr(0,5).c_str())=="data_") {//go back and continue if(vv) cout< stit; for(unsigned int i=0;i>v; return v; } int CIFNumeric2Int(const string &s) { if((s==".") || (s=="?")) return 0; // Use stream rather than sscanf to rely on C++ locale to read C-locale values int v=0; stringstream ss(s); ss.imbue(std::locale::classic()); ss>>v; return v; } Crystal* CreateCrystalFromCIF(CIF &cif,bool verbose,bool checkSymAsXYZ) { return CreateCrystalFromCIF(cif,verbose,checkSymAsXYZ,false,false); } Crystal* CreateCrystalFromCIF(CIF &cif,const bool verbose,const bool checkSymAsXYZ, const bool oneScatteringPowerPerElement, const bool connectAtoms, Crystal *pCryst) { (*fpObjCrystInformUser)("CIF: Opening CIF"); Chronometer chrono; chrono.start(); // If oneScatteringPowerPerElement==true, we hold this to compute the average Biso per element std::map > vElementBiso; bool import_multiple = true; if(pCryst!=NULL) import_multiple = false; bool crystal_found = false; for(map::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos) if(pos->second.mvLatticePar.size()==6) { // If no atoms are listed and we already have a crystal structure defined, //asssume we don't want this one - e.g. like some IuCr journals single crystal //data cif files including cell parameters if((pos->second.mvAtom.size()==0) && (gCrystalRegistry.GetNb()>0)) continue; // Use unambigous Hall symbol if present, otherwise try HM symbol or spg number string spg; if(pos->second.mSpacegroupSymbolHall!="") try { tmp_C_Numeric_locale tmploc; cctbx::sgtbx::space_group cctbxspg(pos->second.mSpacegroupSymbolHall); cctbxspg.t_den(); cctbxspg.n_smx(); cctbxspg.n_ltr(); cctbxspg.type(); cctbxspg.type().number(); cctbxspg.type().hall_symbol(); cctbxspg.type().lookup_symbol(); cctbxspg.match_tabulated_settings().extension(); cctbxspg.match_tabulated_settings().hermann_mauguin(); cctbxspg.type().universal_hermann_mauguin_symbol(); cctbx::sgtbx::brick b(cctbxspg.type()); spg=pos->second.mSpacegroupSymbolHall; } catch(exception) { VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret Hall symbol:"<second.mSpacegroupSymbolHall, 10) } if((spg=="") && (pos->second.mSpacegroupHermannMauguin!="")) try { tmp_C_Numeric_locale tmploc; cctbx::sgtbx::space_group cctbxspg(cctbx::sgtbx::space_group_symbols(pos->second.mSpacegroupHermannMauguin)); cctbxspg.t_den(); cctbxspg.n_smx(); cctbxspg.n_ltr(); cctbxspg.type(); cctbxspg.type().number(); cctbxspg.type().hall_symbol(); cctbxspg.type().lookup_symbol(); cctbxspg.type().universal_hermann_mauguin_symbol(); cctbxspg.match_tabulated_settings().extension(); cctbxspg.match_tabulated_settings().hermann_mauguin(); cctbx::sgtbx::brick b(cctbxspg.type()); spg=pos->second.mSpacegroupHermannMauguin; } catch(exception) { VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret Hermann-Mauguin symbol:"<second.mSpacegroupHermannMauguin, 10) } if((spg=="") && (pos->second.mSpacegroupNumberIT!="")) try { tmp_C_Numeric_locale tmploc; cctbx::sgtbx::space_group cctbxspg(cctbx::sgtbx::space_group_symbols(pos->second.mSpacegroupNumberIT)); cctbxspg.t_den(); cctbxspg.n_smx(); cctbxspg.n_ltr(); cctbxspg.type(); cctbxspg.type().number(); cctbxspg.type().hall_symbol(); cctbxspg.type().lookup_symbol(); cctbxspg.type().universal_hermann_mauguin_symbol(); cctbxspg.match_tabulated_settings().extension(); cctbxspg.match_tabulated_settings().hermann_mauguin(); cctbx::sgtbx::brick b(cctbxspg.type()); spg=pos->second.mSpacegroupNumberIT; } catch(exception) { VFN_DEBUG_MESSAGE("CreateCrystalFromCIF(): could not interpret spacegroup number (!) :"<second.mSpacegroupNumberIT, 10) } if(spg=="") spg="P1"; if(verbose) cout<<"Create crystal with spacegroup: "<second.mSpacegroupHermannMauguin <<" / "<second.mSpacegroupSymbolHall <<" / "<second.mSpacegroupNumberIT <<"-> "<second.mSpacegroupSymbolHall=="") &&(pos->second.mvSymmetry_equiv_pos_as_xyz.size()>0) &&(pos->second.mSpacegroupHermannMauguin!="") &&checkSymAsXYZ) {// Could not use a Hall symbol, but we have a list of symmetry_equiv_pos_as_xyz, // so check we have used the best possible origin tmp_C_Numeric_locale tmploc; static vector origin_list; if(origin_list.size()==0) {//ugly ? origin_list.resize(5); origin_list[0]=""; origin_list[1]=":1"; origin_list[2]=":2"; origin_list[3]=":R"; origin_list[4]=":H"; } // If we do not have an HM symbol, then use the one generated by cctbx (normally from spg number) string hmorig=pos->second.mSpacegroupHermannMauguin; if(hmorig=="") hmorig=pCryst->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin(); if(verbose) cout<<" Symmetry checking using symmetry_equiv_pos_as_xyz:"<::const_iterator posOrig=origin_list.begin();posOrig!=origin_list.end();++posOrig) { // The origin extension may not make sense, so we need to watch for exception try { pCryst->GetSpaceGroup().ChangeSpaceGroup(hmorig+*posOrig); } catch(invalid_argument) { continue; } // If the symbol is the same as before, the origin probably was not understood - no need to test if((posOrig!=origin_list.begin())&&(pCryst->GetSpaceGroup().GetName()==bestsymbol)) continue; unsigned int nbSymSpg=pCryst->GetSpaceGroup().GetCCTbxSpg().all_ops().size(); unsigned int nbSymCommon=0; try { for(unsigned int i=0;i::const_iterator posSymCIF=pos->second.mvSymmetry_equiv_pos_as_xyz.begin(); posSymCIF!=pos->second.mvSymmetry_equiv_pos_as_xyz.end();++posSymCIF) { cctbx::sgtbx::rt_mx mx1(*posSymCIF); cctbx::sgtbx::rt_mx mx2(pCryst->GetSpaceGroup().GetCCTbxSpg().all_ops()[i]); mx1.mod_positive_in_place(); mx2.mod_positive_in_place(); if(mx1==mx2) { nbSymCommon++; break; } } } if(verbose) cout<<" Trying: "<GetSpaceGroup().GetName() <<" nbsym:"<second.mvSymmetry_equiv_pos_as_xyz.size()<<"(CIF)" <<",common:"<second.mvSymmetry_equiv_pos_as_xyz.size())*nbSymCommon)) { bestscore=(nbSymSpg==pos->second.mvSymmetry_equiv_pos_as_xyz.size())*nbSymCommon; bestsymbol=pCryst->GetSpaceGroup().GetName(); } } catch(cctbx::error) { cout<<"WOOPS: cctbx error ! Wrong symmetry_equiv_pos_as_xyz strings ?"<GetSpaceGroup().ChangeSpaceGroup(bestsymbol); } // Try to set name from CIF. If that fails, the computed formula will be used at the end if(pos->second.mName!="") pCryst->SetName(pos->second.mName); else if(pos->second.mFormula!="") pCryst->SetName(pos->second.mFormula); const float t1=chrono.seconds(); (*fpObjCrystInformUser)((boost::format("CIF: Create Crystal:%s(%s)(dt=%6.3fs)")%pCryst->GetName() % pCryst->GetSpaceGroup().GetName() % t1).str()); bool doInformUserAllAtoms=true; if(pos->second.mvAtom.size()>30) doInformUserAllAtoms = false; unsigned int ctatom=0; for(vector::const_iterator posat=pos->second.mvAtom.begin();posat!=pos->second.mvAtom.end();++posat) { if( (posat->mLabel==".") || (posat->mSymbol==".") || (posat->mLabel.find("dummy")!=std::string::npos) || (posat->mSymbol.find("dummy")!=std::string::npos) ) { if(doInformUserAllAtoms) (*fpObjCrystInformUser)("CIF: Ignoring DUMMY Atom:"+posat->mLabel+"(symbol="+posat->mSymbol+")"); continue; } ctatom++; //const float t20=chrono.seconds(); // Try to find an existing scattering power with the same properties, or create a new one ScatteringPower* sp=NULL; if(oneScatteringPowerPerElement) { for(unsigned int i=0;iGetScatteringPowerRegistry().GetNb();++i) { if(pCryst->GetScatteringPowerRegistry().GetObj(i).GetSymbol()!=posat->mSymbol) continue; vElementBiso[&(pCryst->GetScatteringPowerRegistry().GetObj(i))].first+=posat->mBiso; vElementBiso[&(pCryst->GetScatteringPowerRegistry().GetObj(i))].second+=1; sp=&(pCryst->GetScatteringPowerRegistry().GetObj(i)); break; } if(sp==NULL) { if(verbose) cout<<"Scattering power "<mSymbol<<" not found, creating it..."<mSymbol,posat->mSymbol); // Always extract isotropic DP, even with ADPs present // :TODO: if only ADP are listed, calculate isotropic DP vElementBiso[sp].first+=posat->mBiso; vElementBiso[sp].second=1; pCryst->AddScatteringPower(sp); //const float t21=chrono.seconds(); //(*fpObjCrystInformUser)((boost::format("CIF: Add scattering power: %s (dt=%6.3fsCrystal creation=%6.3fs total)")% posat->mSymbol % (t21-t20) % t21).str()); } } else { #if 0 for(unsigned int i=0;iGetScatteringPowerRegistry().GetNb();++i) { if(pCryst->GetScatteringPowerRegistry().GetObj(i).GetSymbol()!=posat->mSymbol) continue; if(posat->mBeta.size() == 6) { if( (pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(0)!=posat->mBeta[0]) ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(1)!=posat->mBeta[1]) ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(2)!=posat->mBeta[2]) ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(3)!=posat->mBeta[3]) ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(4)!=posat->mBeta[4]) ||(pCryst->GetScatteringPowerRegistry().GetObj(i).GetBij(5)!=posat->mBeta[5])) continue; } else if(posat->mBiso!=pCryst->GetScatteringPowerRegistry().GetObj(i).GetBiso()) continue; sp=&(pCryst->GetScatteringPowerRegistry().GetObj(i)); break; } if(sp==NULL) #endif { if(verbose) cout<<"Creating new scattering power for:"<mLabel<mLabel,posat->mSymbol); // Always extract isotropic DP, even with ADPs present // :TODO: if only ADP are listed, calculate isotropic DP sp->SetBiso(posat->mBiso); // ADPs ? if(posat->mBeta.size() == 6) { for (int idx=0; idx<6; ++idx) sp->SetBij(idx, posat->mBeta[idx]); } pCryst->AddScatteringPower(sp); //const float t21=chrono.seconds(); //(*fpObjCrystInformUser)((boost::format("CIF: Add scattering power: %s (dt=%6.3fsCrystal creation=%6.3fs total)") % posat->mLabel % (t21-t20) % t21).str()); } } // (*fpObjCrystInformUser)("CIF: Add Atom:"+posat->mLabel+"("+sp->GetName()+")"); pCryst->AddScatterer(new Atom(posat->mCoordFrac[0],posat->mCoordFrac[1],posat->mCoordFrac[2], posat->mLabel,sp,posat->mOccupancy)); const float t22=chrono.seconds(); if(doInformUserAllAtoms) (*fpObjCrystInformUser)((boost::format("CIF: new Atom: %s (%s) (Crystal creation=%6.3fs total)") % posat->mLabel % sp->GetName() % t22).str()); else if (ctatom%20 == 0)(*fpObjCrystInformUser)((boost::format("CIF: imported %u atoms (Crystal creation=%6.3fs total)") % ctatom % t22).str()); } if(oneScatteringPowerPerElement) { for(std::map >::iterator pos=vElementBiso.begin();pos!=vElementBiso.end();++pos) pos->first->SetBiso(pos->second.first/pos->second.second); } (*fpObjCrystInformUser)((boost::format("CIF: Finished importing %u atoms (Crystal creation=%6.3fs total)") % ctatom % chrono.seconds()).str()); if(connectAtoms) { (*fpObjCrystInformUser)("CIF: connecting atoms"); pCryst->ConnectAtoms(); unsigned int ctat=0; unsigned int ctmol=0; for(int i=0;iGetNbScatterer();i++) { if(pCryst->GetScatt(i).GetClassName()=="Atom") ctat +=1; else if(pCryst->GetScatt(i).GetClassName()=="Molecule") ctmol +=1; } (*fpObjCrystInformUser)((boost::format("CIF: finished connecting atoms (%u isolated atoms, %u molecules) (Crystal creation=%6.3fs total)") % ctat % ctmol % chrono.seconds()).str()); } if(pCryst->GetName()=="") pCryst->SetName(pCryst->GetFormula()); if(!import_multiple) return pCryst; } if(!crystal_found) throw ObjCrystException("CreateCrystalFromCIF: no structure found"); return pCryst; } PowderPattern* CreatePowderPatternFromCIF(CIF &cif) { PowderPattern* pPow=NULL; for(map::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos) { if(pos->second.mPowderPatternObs.size()>10) { pPow=new PowderPattern(); pPow->ImportPowderPatternCIF(cif); (*fpObjCrystInformUser)((boost::format("CIF: Imported POWDER PATTERN, with %d points") % pPow->GetNbPoint()).str()); } } return pPow; } DiffractionDataSingleCrystal* CreateSingleCrystalDataFromCIF(CIF &cif, Crystal *pcryst) { DiffractionDataSingleCrystal* pData=NULL; std::string name(""); for(map::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos) { if(pos->second.mH.numElements()>0) { (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data")).str()); if(pcryst==0) { if(gCrystalRegistry.GetNb()>0) { // Use last Crystal created pcryst=&(gCrystalRegistry.GetObj(gCrystalRegistry.GetNb()-1)); (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data: using last Crystal structure as corresponding crystal [%s]") % pcryst->GetName().c_str()).str()); name = pcryst->GetName(); } else { pcryst=new Crystal; pcryst->SetName("Crystal data for Single Crystal Diffraction data imported from CIF"); (*fpObjCrystInformUser)((boost::format("CIF: Importing SINGLE CRYSTAL DIFFRACTION data: creating new empty Crystal structure")).str()); } } pData=new DiffractionDataSingleCrystal(*pcryst); pData->SetHklIobs(pos->second.mH,pos->second.mK,pos->second.mL,pos->second.mIobs,pos->second.mSigma); if(pData->GetName()=="") pData->SetName(name); (*fpObjCrystInformUser)((boost::format("CIF: Imported SINGLE CRYSTAL DIFFRACTION data, with %d reflections") % pData->GetNbRefl()).str()); } } return pData; } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/CIF.h000066400000000000000000000261561417150057700216300ustar00rootroot00000000000000#ifndef _OBJCRYST_CIF_H #define _OBJCRYST_CIF_H #include #include #include #include #include #include #include #include "ObjCryst/Quirks/ci_string.h" namespace ObjCryst {// Forward declaration class CIF; } #include "ObjCryst/ObjCryst/PowderPattern.h" // For CreatePowderPatternFromCIF only. #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" // For CreateSingleCrystalDataFromCIF only. #include "ObjCryst/ObjCryst/Crystal.h" // For CreateCrystalFromCIF only. #include "ObjCryst/ObjCryst/General.h" // TO identify wavelength type in CIFData::ExtractPowderPattern. namespace ObjCryst { /// Convert one CIF value to a floating-point value /// Return 0 if no value can be converted (e.g. if '.' or '?' is encountered) REAL CIFNumeric2REAL(const std::string &s); /// Convert one CIF value to a floating-point value /// Return 0 if no value can be converted (e.g. if '.' or '?' is encountered) int CIFNumeric2Int(const std::string &s); /** The CIFData class holds all the information from a \e single data_ block from a cif file. * * It is a placeholder for all comments, item and loop data, as raw strings copied from * a cif file. * * It is also used to interpret this data to extract parts of the cif data, i.e. * only part of the core cif dictionnary are recognized. CIF tags currently recognized * include ("tag1 > tag2" means tag1 is preferred to tag2 when extracting the info, only one is reported): * - crystal name: _chemical_name_systematic > _chemical_name_mineral > _chemical_name_structure_type > _chemical_name_common * - crystal formula: _chemical_formula_analytical > _chemical_formula_structural > _chemical_formula_iupac > _chemical_formula_moiety * - unit cell: _cell_length_{a,b,c} ; _cell_angle_{alpha,beta,gamma} * - spacegroup number: _space_group_IT_number > _symmetry_Int_Tables_number * - spacegroup Hall symbol: _space_group_name_Hall > _symmetry_space_group_name_Hall * - spacegroup Hermann-Mauguin symbol:_space_group_name_H-M_alt > _symmetry_space_group_name_H-M * - atom coordinates: _atom_site_fract_{x} ; _atom_site_Cartn_{x,y,z} * - atom occupancy: _atom_site_occupancy * - atom label & symbol: _atom_site_type_symbol ; _atom_site_label * - atom adps: _atom_site_aniso_{U,B}_{11,22,33,12,13,23} > _atom_site_{U,B}_iso_or_equiv * * * Cartesian coordinates are stored in Angstroems, angles in radians. * * To import PowderPattern data, the following tags are used: * - observed intensity: _pd_meas_counts_total > _pd_meas_intensity_total > _pd_proc_intensity_total > _pd_proc_intensity_net * - uncertainty on intensity: deducted from _pd_proc_ls_weight or square root of intensity * - coordinates: _pd_proc_2theta_corrected > _pd_meas_angle_2theta > _pd_meas_time_of_flight > _pd_proc_2theta_range_{min,max,inc} * - intensity normalizer (optional): _pd_meas_intensity_monitor > _pd_meas_step_count_time * * If another data field is needed, it is possible to directly access the string data * (CIFData::mvComment , CIFData::mvItem and CIFData::mvLoop) to search for the correct tags. */ class CIFData { public: CIFData(); /// Extract lattice parameters, spacegroup (symbol or number), atomic positions, /// chemical name and formula if available. /// All other data is ignored void ExtractAll(const bool verbose=false); /// Extract name & formula for the crystal void ExtractName(const bool verbose=false); /// Extract unit cell void ExtractUnitCell(const bool verbose=false); /// Extract spacegroup number or symbol void ExtractSpacegroup(const bool verbose=false); /// Extract all atomic positions. Will generate cartesian from fractional /// coordinates or vice-versa if only cartesian coordinates are available. void ExtractAtomicPositions(const bool verbose=false); /// Extract anisotropic atomic displacement parameters. Isotropic ADPs // may be extracted in ExtractAtomicPositions. This takes prescedent. void ExtractAnisotropicADPs(const bool verbose=false); /// Extract Powder Diffraction data, with Iobs, sigma(Iobs) and either 2theta /// or time-of-flight position. void ExtractPowderPattern(const bool verbose=false); /// Extract single crystal data, with Iobs, sigma(Iobs) and h,k,l void ExtractSingleCrystalData(const bool verbose=false); /// Generate fractional coordinates from cartesian ones for all atoms /// CIFData::CalcMatrices() must be called first void Cartesian2FractionalCoord(); /// Generate cartesian coordinates from fractional ones for all atoms /// CIFData::CalcMatrices() must be called first void Fractional2CartesianCoord(); /// Convert from fractional to cartesian coordinates /// CIFData::CalcMatrices() must be called first void f2c(REAL &x,REAL &y, REAL &z); /// Convert from cartesia to fractional coordinates /// CIFData::CalcMatrices() must be called first void c2f(REAL &x,REAL &y, REAL &z); /// Calculate real space transformation matrices /// requires unit cell parameters void CalcMatrices(const bool verbose=false); /// Comments from CIF file, in the order they were read std::list mvComment; /// Individual CIF items std::map mvItem; /// CIF Loop data std::map,std::map > > mvLoop; /// Lattice parameters, in ansgtroem and degrees - vector size is 0 if no /// parameters have been obtained yet. std::vector mvLatticePar; /// Spacegroup number from International Tables (_space_group_IT_number), or -1. std::string mSpacegroupNumberIT; /// Spacegroup Hall symbol (or empty string) (_space_group_name_Hall) std::string mSpacegroupSymbolHall; /// Spacegroup Hermann-Mauguin symbol (or empty string) (_space_group_name_H-M_alt) std::string mSpacegroupHermannMauguin; /// Map of _symmetry_equiv_pos_as_xyz strings std::set mvSymmetry_equiv_pos_as_xyz; /// Crystal name. Or empty string if none is available. std::string mName; /// Formula. Or empty string if none is available. std::string mFormula; /// Atom record struct CIFAtom { CIFAtom(); /// Label of the atom, or empty string (_atom_site_label). std::string mLabel; /// Symbol of the atom, or empty string (_atom_type_symbol or _atom_site_type_symbol). std::string mSymbol; /// Fractionnal coordinates (_atom_site_fract_{x,y,z}) or empty vector. std::vector mCoordFrac; /// Cartesian coordinates in Angstroem (_atom_site_Cartn_{x,y,z}) or empty vector. /// Transformation to fractionnal coordinates currently assumes /// "a parallel to x; b in the plane of y and z" (see _atom_sites_Cartn_transform_axes) std::vector mCoordCart; /// Site occupancy, or -1 REAL mOccupancy; /// ADP tensor std::vector mBeta; /// Biso REAL mBiso; }; /// Atoms, if any are found std::vector mvAtom; /// Fractionnal2Cartesian matrix REAL mOrthMatrix[3][3]; /// Cartesian2Fractionnal matrix REAL mOrthMatrixInvert[3][3]; /// Powder pattern data std::vector mPowderPatternObs,mPowderPatternX,mPowderPatternSigma; /// Single crystal data CrystVector_long mH,mK,mL; /// Single crystal data CrystVector_REAL mIobs,mSigma; /// Is this X-Ray 2theta, time-of-flight ? WavelengthType mDataType; /// Wavelength REAL mWavelength; }; /** Main CIF class - parses the stream and separates data blocks, comments, items, loops. * All values are stored as string, and Each CIF block is stored in a separate CIFData object. * No interpretaion is made here - this must be done from all CIFData objects. */ class CIF { public: /// Creates the CIF object from a stream /// /// \param interpret: if true, interpret all data blocks. See CIFData::ExtractAll() CIF(std::istream &in, const bool interpret=true,const bool verbose=false); //private: /// Separate the file in data blocks and parse them to sort tags, loops and comments. /// All is stored in the original strings. void Parse(std::stringstream &in); /// The data blocks, after parsing. The key is the name of the data block std::map mvData; /// Global comments, outside and data block std::list mvComment; }; // Forward declarations class Crystal; class PowderPattern; /** Extract Crystal object(s) from a CIF, if possible. * Returns a null pointer if no crystal structure could be extracted * (the minimum data is the unit cell parameters). * * \param checkSymAsXYZ: if true, and the CIF file does not have a Hall symbol * but has a list of symmetry_equiv_pos_as_xyz, check we have the correct * setting by trying different ones using cctbx */ Crystal* CreateCrystalFromCIF(CIF &cif,const bool verbose=true,const bool checkSymAsXYZ=true); /** Extract Crystal object(s) from a CIF, if possible. * Returns a null pointer if no crystal structure could be extracted * (the minimum data is the unit cell parameters). * * \param checkSymAsXYZ: if true, and the CIF file does not have a Hall symbol * but has a list of symmetry_equiv_pos_as_xyz, check we have the correct * setting by trying different ones using cctbx * \param oneScatteringPowerPerElement: if false (the default), then there will be as many * ScatteringPowerAtom created as there are different elements. If true, * only one will be created per element, avoiding a large number of scattering powers * e.g. when importing CIFs obtained from single crystal data refinement. * \param connectAtoms: if true, call Crystal::ConnectAtoms to try to create as many Molecules * as possible from the list of imported atoms. * \param pcryst: a pointer to an existing Crystal can be given. In this case, * only the first Crystal structure found is imported from the CIF. The given * Crystal is assumed to be empty. * \warning The behaviour of oneScatteringPowerPerElement has changed [2016/11/11]: * when set to false, it will return one scattering power per atom, where as prior to this * change, scattering powers where identical for identical Debye-Waller factors. */ Crystal* CreateCrystalFromCIF(CIF &cif,const bool verbose,const bool checkSymAsXYZ, const bool oneScatteringPowerPerElement, const bool connectAtoms, Crystal *pcryst=NULL); /// Create PowderPattern object(s) from a CIF, if possible. /// Returns a null pointer if no pattern could be extracted. /// No components (background, crystal data) are created. PowderPattern* CreatePowderPatternFromCIF(CIF &cif); /// Create DiffractionDataSingleCrystal object(s) from a CIF, if possible. /// Returns a null pointer if no data could be extracted. /// A Crystal object must be supplied - if none is given, the last Crystal /// object will be used. If no Cyrstal data exists, a new one will be created. DiffractionDataSingleCrystal* CreateSingleCrystalDataFromCIF(CIF &cif, Crystal *pryst=0); } #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Colours.h000066400000000000000000000260011417150057700226420ustar00rootroot00000000000000/* Colour definitions from POVRay (http://www.povray.org) */ #ifndef __OBJCRYST_COULOURS_H #define __OBJCRYST_COULOURS_H struct POVRayColours { const char *mName; REAL mRGB[3]; }; /** Colours from POVRay (first part) and Jmol *(converted to floats from jmol_constants.java) */ const POVRayColours gPOVRayColours[]= { {"Red", { 1, 0, 0}}, {"Green", { 0, 1, 0}}, {"Blue", { 0, 0, 1}}, {"Yellow", { 1, 1, 0}}, {"Cyan", { 0, 1, 1}}, {"Magenta", { 1, 0, 1}}, {"Clear", { 1, 1, 1}}, {"White", { 1, 1, 1}}, {"Black", { 0, 0, 0}}, {"Gray05", { 0.05, 0.05, 0.05}}, {"Gray10", { .10, .10, .10}}, {"Gray15", { 0.15, 0.15, 0.15}}, {"Gray20", { 0.20, 0.20, 0.20}}, {"Gray25", { 0.25, 0.25, 0.25}}, {"Gray30", { 0.30, 0.30, 0.30}}, {"Gray35", { 0.35, 0.35, 0.35}}, {"Gray40", { 0.40, 0.40, 0.40}}, {"Gray45", { 0.45, 0.45, 0.45}}, {"Gray50", { 0.50, 0.50, 0.50}}, {"Gray55", { 0.55, 0.55, 0.55}}, {"Gray60", { 0.60, 0.60, 0.60}}, {"Gray65", { 0.65, 0.65, 0.65}}, {"Gray70", { 0.70, 0.70, 0.70}}, {"Gray75", { 0.75, 0.75, 0.75}}, {"Gray80", { 0.80, 0.80, 0.80}}, {"Gray85", { 0.85, 0.85, 0.85}}, {"Gray90", { 0.90, 0.90, 0.90}}, {"Gray95", { 0.95, 0.95, 0.95}}, {"DimGray", { 0.329412 , 0.329412 , 0.329412}}, {"DimGrey", { 0.329412 , 0.329412 , 0.329412}}, {"Gray", { 0.752941 , 0.752941 , 0.752941}}, {"Grey", { 0.752941 , 0.752941 , 0.752941}}, {"LightGray", { 0.658824 , 0.658824 , 0.658824}}, {"LightGrey", { 0.658824 , 0.658824 , 0.658824}}, {"VLightGray", { 0.80 , 0.80 , 0.80}}, {"VLightGrey", { 0.80 , 0.80 , 0.80}}, {"Aquamarine", { 0.439216 , 0.858824 , 0.576471}}, {"BlueViolet", { 0.62352 , 0.372549 , 0.623529}}, {"Brown", { 0.647059 , 0.164706 , 0.164706}}, {"CadetBlue", { 0.372549 , 0.623529 , 0.623529}}, {"Coral", { 1.0 , 0.498039 , 0.0}}, {"CornflowerBlue", { 0.258824 , 0.258824 , 0.435294}}, {"DarkGreen", { 0.184314 , 0.309804 , 0.184314}}, {"DarkOliveGreen", { 0.309804 , 0.309804 , 0.184314}}, {"DarkOrchid", { 0.6 , 0.196078 , 0.8}}, {"DarkSlateBlue", { 0.119608 , 0.137255 , 0.556863}}, {"DarkSlateGray", { 0.184314 , 0.309804 , 0.309804}}, {"DarkSlateGrey", { 0.184314 , 0.309804 , 0.309804}}, {"DarkTurquoise", { 0.439216 , 0.576471 , 0.858824}}, {"Firebrick", { 0.556863 , 0.137255 , 0.137255}}, {"ForestGreen", { 0.137255 , 0.556863 , 0.137255}}, {"Gold", { 0.8 , 0.498039 , 0.196078}}, {"Goldenrod", { 0.858824 , 0.858824 , 0.439216}}, {"GreenYellow", { 0.576471 , 0.858824 , 0.439216}}, {"IndianRed", { 0.309804 , 0.184314 , 0.184314}}, {"Khaki", { 0.623529 , 0.623529 , 0.372549}}, {"LightBlue", { 0.74902 , 0.847059 , 0.847059}}, {"LightSteelBlue", { 0.560784 , 0.560784 , 0.737255}}, {"LimeGreen", { 0.196078 , 0.8 , 0.196078}}, {"Maroon", { 0.556863 , 0.137255 , 0.419608}}, {"MediumAquamarine", { 0.196078 , 0.8 , 0.6}}, {"MediumBlue", { 0.196078 , 0.196078 , 0.8}}, {"MediumForestGreen", { 0.419608 , 0.556863 , 0.137255}}, {"MediumGoldenrod", { 0.917647 , 0.917647 , 0.678431}}, {"MediumOrchid", { 0.576471 , 0.439216 , 0.858824}}, {"MediumSeaGreen", { 0.258824 , 0.435294 , 0.258824}}, {"MediumSlateBlue", { 0.498039 , 1.0}}, {"MediumSpringGreen", { 0.498039 , 1.0}}, {"MediumTurquoise", { 0.439216 , 0.858824 , 0.858824}}, {"MediumVioletRed", { 0.858824 , 0.439216 , 0.576471}}, {"MidnightBlue", { 0.184314 , 0.184314 , 0.309804}}, {"Navy", { 0.137255 , 0.137255 , 0.556863}}, {"NavyBlue", { 0.137255 , 0.137255 , 0.556863}}, {"Orange", { 1 , 0.5 , 0.0}}, {"OrangeRed", { 1.0 , 0.25}}, {"Orchid", { 0.858824 , 0.439216 , 0.858824}}, {"PaleGreen", { 0.560784 , 0.737255 , 0.560784}}, {"Pink", { 0.737255 , 0.560784 , 0.560784}}, {"Plum", { 0.917647 , 0.678431 , 0.917647}}, {"Salmon", { 0.435294 , 0.258824 , 0.258824}}, {"SeaGreen", { 0.137255 , 0.556863 , 0.419608}}, {"Sienna", { 0.556863 , 0.419608 , 0.137255}}, {"SkyBlue", { 0.196078 , 0.6 , 0.8}}, {"SlateBlue", { 0., 0.498039 , 1.0}}, {"SpringGreen", {0. , 1.0 , 0.498039}}, {"SteelBlue", { 0.137255 , 0.419608 , 0.556863}}, {"Tan", { 0.858824 , 0.576471 , 0.439216}}, {"Thistle", { 0.847059 , 0.74902 , 0.847059}}, {"Turquoise", { 0.678431 , 0.917647 , 0.917647}}, {"Violet", { 0.309804 , 0.184314 , 0.309804}}, {"VioletRed", { 0.8 , 0.196078 , 0.6}}, {"Wheat", { 0.847059 , 0.847059 , 0.74902}}, {"YellowGreen", { 0.6 , 0.8 , 0.196078}}, {"SummerSky", { 0.22 , 0.69 , 0.87}}, {"RichBlue", { 0.35 , 0.35 , 0.67}}, {"Brass", { 0.71 , 0.65 , 0.26}}, {"Copper", { 0.72 , 0.45 , 0.20}}, {"Bronze", { 0.55 , 0.47 , 0.14}}, {"Bronze2", { 0.65 , 0.49 , 0.24}}, {"Silver", { 0.90 , 0.91 , 0.98}}, {"BrightGold", { 0.85 , 0.85 , 0.10}}, {"OldGold", { 0.81 , 0.71 , 0.23}}, {"Feldspar", { 0.82 , 0.57 , 0.46}}, {"Quartz", { 0.85 , 0.85 , 0.95}}, {"Mica", { 0, 0, 0}}, {"NeonPink", { 1.00 , 0.43 , 0.78}}, {"DarkPurple", { 0.53 , 0.12 , 0.47}}, {"NeonBlue", { 0.30 , 0.30 , 1.00}}, {"CoolCopper", { 0.85 , 0.53 , 0.10}}, {"MandarinOrange", { 0.89 , 0.47 , 0.20}}, {"LightWood", { 0.91 , 0.76 , 0.65}}, {"MediumWood", { 0.65 , 0.50 , 0.39}}, {"DarkWood", { 0.52 , 0.37 , 0.26}}, {"SpicyPink", { 1.00 , 0.11 , 0.68}}, {"SemiSweetChoc", { 0.42 , 0.26 , 0.15}}, {"BakersChoc", { 0.36 , 0.20 , 0.09}}, {"Flesh", { 0.96 , 0.80 , 0.69}}, {"NewTan", { 0.92 , 0.78 , 0.62}}, {"NewMidnightBlue", { 0.00 , 0.00 , 0.61}}, {"VeryDarkBrown", { 0.35 , 0.16 , 0.14}}, {"DarkBrown", { 0.36 , 0.25 , 0.20}}, {"DarkTan", { 0.59 , 0.41 , 0.31}}, {"GreenCopper", { 0.32 , 0.49 , 0.46}}, {"DkGreenCopper", { 0.29 , 0.46 , 0.43}}, {"DustyRose", { 0.52 , 0.39 , 0.39}}, {"HuntersGreen", { 0.13 , 0.37 , 0.31}}, {"Scarlet", { 0.55 , 0.09 , 0.09}}, {"Med_Purple", { 0.73 , 0.16 , 0.96}}, {"Light_Purple", { 0.87 , 0.58 , 0.98}}, {"Very_Light_Purple", { 0.94 , 0.81 , 0.99}}, {"H", {1.000, 1.000, 1.000}}, //Z= 1 {"He", {0.851, 1.000, 1.000}}, //Z= 2 {"Li", {0.800, 0.502, 1.000}}, //Z= 3 {"Be", {0.761, 1.000, 0.000}}, //Z= 4 {"B", {1.000, 0.710, 0.710}}, //Z= 5 {"C", {0.565, 0.565, 0.565}}, //Z= 6 {"N", {0.188, 0.314, 0.973}}, //Z= 7 {"O", {1.000, 0.051, 0.051}}, //Z= 8 {"F", {0.565, 0.878, 0.314}}, //Z= 9 {"Ne", {0.702, 0.890, 0.961}}, //Z= 10 {"Na", {0.671, 0.361, 0.949}}, //Z= 11 {"Mg", {0.541, 1.000, 0.000}}, //Z= 12 {"Al", {0.749, 0.651, 0.651}}, //Z= 13 {"Si", {0.941, 0.784, 0.627}}, //Z= 14 {"P", {1.000, 0.502, 0.000}}, //Z= 15 {"S", {1.000, 1.000, 0.188}}, //Z= 16 {"Cl", {0.122, 0.941, 0.122}}, //Z= 17 {"Ar", {0.502, 0.820, 0.890}}, //Z= 18 {"K", {0.561, 0.251, 0.831}}, //Z= 19 {"Ca", {0.239, 1.000, 0.000}}, //Z= 20 {"Sc", {0.902, 0.902, 0.902}}, //Z= 21 {"Ti", {0.749, 0.761, 0.780}}, //Z= 22 {"V", {0.651, 0.651, 0.671}}, //Z= 23 {"Cr", {0.541, 0.600, 0.780}}, //Z= 24 {"Mn", {0.612, 0.478, 0.780}}, //Z= 25 {"Fe", {0.878, 0.400, 0.200}}, //Z= 26 {"Co", {0.941, 0.565, 0.627}}, //Z= 27 {"Ni", {0.314, 0.816, 0.314}}, //Z= 28 {"Cu", {0.784, 0.502, 0.200}}, //Z= 29 {"Zn", {0.490, 0.502, 0.690}}, //Z= 30 {"Ga", {0.761, 0.561, 0.561}}, //Z= 31 {"Ge", {0.400, 0.561, 0.561}}, //Z= 32 {"As", {0.741, 0.502, 0.890}}, //Z= 33 {"Se", {1.000, 0.631, 0.000}}, //Z= 34 {"Br", {0.651, 0.161, 0.161}}, //Z= 35 {"Kr", {0.361, 0.722, 0.820}}, //Z= 36 {"Rb", {0.439, 0.180, 0.690}}, //Z= 37 {"Sr", {0.000, 1.000, 0.000}}, //Z= 38 {"Y", {0.580, 1.000, 1.000}}, //Z= 39 {"Zr", {0.580, 0.878, 0.878}}, //Z= 40 {"Nb", {0.451, 0.761, 0.788}}, //Z= 41 {"Mo", {0.329, 0.710, 0.710}}, //Z= 42 {"Tc", {0.231, 0.620, 0.620}}, //Z= 43 {"Ru", {0.141, 0.561, 0.561}}, //Z= 44 {"Rh", {0.039, 0.490, 0.549}}, //Z= 45 {"Pd", {0.000, 0.412, 0.522}}, //Z= 46 {"Ag", {0.753, 0.753, 0.753}}, //Z= 47 {"Cd", {1.000, 0.851, 0.561}}, //Z= 48 {"In", {0.651, 0.459, 0.451}}, //Z= 49 {"Sn", {0.400, 0.502, 0.502}}, //Z= 50 {"Sb", {0.620, 0.388, 0.710}}, //Z= 51 {"Te", {0.831, 0.478, 0.000}}, //Z= 52 {"I", {0.580, 0.000, 0.580}}, //Z= 53 {"Xe", {0.259, 0.620, 0.690}}, //Z= 54 {"Cs", {0.341, 0.090, 0.561}}, //Z= 55 {"Ba", {0.000, 0.788, 0.000}}, //Z= 56 {"La", {0.439, 0.831, 1.000}}, //Z= 57 {"Ce", {1.000, 1.000, 0.780}}, //Z= 58 {"Pr", {0.851, 1.000, 0.780}}, //Z= 59 {"Nd", {0.780, 1.000, 0.780}}, //Z= 60 {"Pm", {0.639, 1.000, 0.780}}, //Z= 61 {"Sm", {0.561, 1.000, 0.780}}, //Z= 62 {"Eu", {0.380, 1.000, 0.780}}, //Z= 63 {"Gd", {0.271, 1.000, 0.780}}, //Z= 64 {"Tb", {0.188, 1.000, 0.780}}, //Z= 65 {"Dy", {0.122, 1.000, 0.780}}, //Z= 66 {"Ho", {0.000, 1.000, 0.612}}, //Z= 67 {"Er", {0.000, 0.902, 0.459}}, //Z= 68 {"Tm", {0.000, 0.831, 0.322}}, //Z= 69 {"Yb", {0.000, 0.749, 0.220}}, //Z= 70 {"Lu", {0.000, 0.671, 0.141}}, //Z= 71 {"Hf", {0.302, 0.761, 1.000}}, //Z= 72 {"Ta", {0.302, 0.651, 1.000}}, //Z= 73 {"W", {0.129, 0.580, 0.839}}, //Z= 74 {"Re", {0.149, 0.490, 0.671}}, //Z= 75 {"Os", {0.149, 0.400, 0.588}}, //Z= 76 {"Ir", {0.090, 0.329, 0.529}}, //Z= 77 {"Pt", {0.816, 0.816, 0.878}}, //Z= 78 {"Au", {1.000, 0.820, 0.137}}, //Z= 79 {"Hg", {0.722, 0.722, 0.816}}, //Z= 80 {"Tl", {0.651, 0.329, 0.302}}, //Z= 81 {"Pb", {0.341, 0.349, 0.380}}, //Z= 82 {"Bi", {0.620, 0.310, 0.710}}, //Z= 83 {"Po", {0.671, 0.361, 0.000}}, //Z= 84 {"At", {0.459, 0.310, 0.271}}, //Z= 85 {"Rn", {0.259, 0.510, 0.588}}, //Z= 86 {"Fr", {0.259, 0.000, 0.400}}, //Z= 87 {"Ra", {0.000, 0.490, 0.000}}, //Z= 88 {"Ac", {0.439, 0.671, 0.980}}, //Z= 89 {"Th", {0.000, 0.729, 1.000}}, //Z= 90 {"Pa", {0.000, 0.631, 1.000}}, //Z= 91 {"U", {0.000, 0.561, 1.000}}, //Z= 92 {"Np", {0.000, 0.502, 1.000}}, //Z= 93 {"Pu", {0.000, 0.420, 1.000}}, //Z= 94 {"Am", {0.329, 0.361, 0.949}}, //Z= 95 {"Cm", {0.471, 0.361, 0.890}}, //Z= 96 {"Bk", {0.541, 0.310, 0.890}}, //Z= 97 {"Cf", {0.631, 0.212, 0.831}}, //Z= 98 {"Es", {0.702, 0.122, 0.831}}, //Z= 99 {"Fm", {0.702, 0.122, 0.729}}, //Z=100 {"Md", {0.702, 0.051, 0.651}}, //Z=101 {"No", {0.741, 0.051, 0.529}}, //Z=102 {"Lr", {0.780, 0.000, 0.400}}, //Z=103 {"Rf", {0.800, 0.000, 0.349}}, //Z=104 {"Db", {0.820, 0.000, 0.310}}, //Z=105 {"Sg", {0.851, 0.000, 0.271}}, //Z=106 {"Bh", {0.878, 0.000, 0.220}}, //Z=107 {"Hs", {0.902, 0.000, 0.180}}, //Z=108 {"Mt", {0.922, 0.000, 0.149}}, //Z=109 {"",{0. , 0. , 0.}}, }; #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Crystal.cpp000066400000000000000000002507351417150057700232050ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file LibCryst++ Crystal class * */ #include #include #include #include #include #include "cctbx/sgtbx/space_group.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Molecule.h" #include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs.. #include "ObjCryst/Quirks/VFNDebug.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxCrystal.h" #endif #include #include namespace ObjCryst { const RefParType *gpRefParTypeCrystal=0; long NiftyStaticGlobalObjectsInitializer_Crystal::mCount=0; //////////////////////////////////////////////////////////////////////// // // CRYSTAL : the crystal (Unit cell, spaceGroup, scatterers) // //////////////////////////////////////////////////////////////////////// ObjRegistry gCrystalRegistry("List of all Crystals"); Crystal::Crystal(): mScattererRegistry("List of Crystal Scatterers"), mBumpMergeCost(0.0),mBumpMergeScale(1.0), mDistTableMaxDistance(1.0), mScatteringPowerRegistry("List of Crystal ScatteringPowers"), mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1) { VFN_DEBUG_MESSAGE("Crystal::Crystal()",10) this->InitOptions(); this->Init(10,11,12,M_PI/2+.1,M_PI/2+.2,M_PI/2+.3,"P 1",""); gCrystalRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mLatticeClock); mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock()); mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock()); } Crystal::Crystal(const REAL a, const REAL b, const REAL c, const string &SpaceGroupId): mScattererRegistry("List of Crystal Scatterers"), mBumpMergeCost(0.0),mBumpMergeScale(1.0), mDistTableMaxDistance(1.0), mScatteringPowerRegistry("List of Crystal ScatteringPowers"), mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1) { VFN_DEBUG_MESSAGE("Crystal::Crystal(a,b,c,Sg)",10) this->Init(a,b,c,M_PI/2,M_PI/2,M_PI/2,SpaceGroupId,""); this->InitOptions(); gCrystalRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mLatticeClock); mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock()); mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock()); } Crystal::Crystal(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId): mScattererRegistry("List of Crystal Scatterers"), mBumpMergeCost(0.0),mBumpMergeScale(1.0), mDistTableMaxDistance(1.0), mScatteringPowerRegistry("List of Crystal ScatteringPowers"), mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1) { VFN_DEBUG_MESSAGE("Crystal::Crystal(a,b,c,alpha,beta,gamma,Sg)",10) this->Init(a,b,c,alpha,beta,gamma,SpaceGroupId,""); this->InitOptions(); gCrystalRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mLatticeClock); mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock()); mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock()); } Crystal::Crystal(const Crystal &old): mScattererRegistry("List of Crystal Scatterers"), mBumpMergeCost(0.0),mBumpMergeScale(1.0), mDistTableMaxDistance(1.0), mScatteringPowerRegistry("List of Crystal ScatteringPowers"), mBondValenceCost(0.0),mBondValenceCostScale(1.0),mDeleteSubObjInDestructor(1) { VFN_DEBUG_MESSAGE("Crystal::Crystal()",10) // Only create a default crystal, then copy old using XML this->InitOptions(); this->Init(10,11,12,M_PI/2+.1,M_PI/2+.2,M_PI/2+.3,"P 1",""); gCrystalRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mLatticeClock); mClockMaster.AddChild(this->mScattererRegistry.GetRegistryClock()); mClockMaster.AddChild(this->mScatteringPowerRegistry.GetRegistryClock()); stringstream sst; old.XMLOutput(sst); XMLCrystTag tag(sst); this->XMLInput(sst,tag); } Crystal::~Crystal() { VFN_DEBUG_ENTRY("Crystal::~Crystal()",5) for(long i=0;iRemoveSubRefObj(mScattererRegistry.GetObj(i)); mScattererRegistry.GetObj(i).DeRegisterClient(*this); } if( mDeleteSubObjInDestructor ) { mScattererRegistry.DeleteAll(); } else { mScattererRegistry.DeRegisterAll(); } for(long i=0;iRemoveSubRefObj(mScatteringPowerRegistry.GetObj(i)); mScatteringPowerRegistry.GetObj(i).DeRegisterClient(*this); // :TODO: check if it is not used by another Crystal (forbidden!) } if( mDeleteSubObjInDestructor ) { mScatteringPowerRegistry.DeleteAll(); } else { mScatteringPowerRegistry.DeRegisterAll(); } gCrystalRegistry.DeRegister(*this); gTopRefinableObjRegistry.DeRegister(*this); VFN_DEBUG_EXIT("Crystal::~Crystal()",5) } const string& Crystal::GetClassName() const { const static string className="Crystal"; return className; } void Crystal::AddScatterer(Scatterer *scatt) { VFN_DEBUG_ENTRY("Crystal::AddScatterer(&scatt)",5) mScattererRegistry.Register(*scatt); scatt->RegisterClient(*this); this->AddSubRefObj(*scatt); scatt->SetCrystal(*this); mClockScattererList.Click(); VFN_DEBUG_EXIT("Crystal::AddScatterer(&scatt):Finished",5) } void Crystal::RemoveScatterer(Scatterer *scatt, const bool del) { VFN_DEBUG_MESSAGE("Crystal::RemoveScatterer(&scatt)",5) mScattererRegistry.DeRegister(*scatt); scatt->DeRegisterClient(*this); this->RemoveSubRefObj(*scatt); if(del) delete scatt; mClockScattererList.Click(); VFN_DEBUG_MESSAGE("Crystal::RemoveScatterer(&scatt):Finished",5) } long Crystal::GetNbScatterer()const {return mScattererRegistry.GetNb();} Scatterer& Crystal::GetScatt(const string &scattName) { return mScattererRegistry.GetObj(scattName); } const Scatterer& Crystal::GetScatt(const string &scattName) const { return mScattererRegistry.GetObj(scattName); } Scatterer& Crystal::GetScatt(const long scattIndex) { return mScattererRegistry.GetObj(scattIndex); } const Scatterer& Crystal::GetScatt(const long scattIndex) const { return mScattererRegistry.GetObj(scattIndex); } ObjRegistry& Crystal::GetScattererRegistry() {return mScattererRegistry;} const ObjRegistry& Crystal::GetScattererRegistry() const {return mScattererRegistry;} ObjRegistry& Crystal::GetScatteringPowerRegistry() {return mScatteringPowerRegistry;} const ObjRegistry& Crystal::GetScatteringPowerRegistry() const {return mScatteringPowerRegistry;} void Crystal::AddScatteringPower(ScatteringPower *scattPow) { mScatteringPowerRegistry.Register(*scattPow); scattPow->RegisterClient(*this);//:TODO: Should register as (unique) 'owner'. this->AddSubRefObj(*scattPow); mClockMaster.AddChild(scattPow->GetClockMaster()); mClockMaster.AddChild(scattPow->GetMaximumLikelihoodParClock()); mMasterClockScatteringPower.AddChild(scattPow->GetClockMaster()); } void Crystal::RemoveScatteringPower(ScatteringPower *scattPow, const bool del) { VFN_DEBUG_ENTRY("Crystal::RemoveScatteringPower()",2) mScatteringPowerRegistry.DeRegister(*scattPow); this->RemoveSubRefObj(*scattPow); mClockMaster.RemoveChild(scattPow->GetClockMaster()); mClockMaster.RemoveChild(scattPow->GetMaximumLikelihoodParClock()); mMasterClockScatteringPower.RemoveChild(scattPow->GetClockMaster()); if(del) delete scattPow; for(Crystal::VBumpMergePar::iterator pos=mvBumpMergePar.begin();pos!=mvBumpMergePar.end();) { if((pos->first.first==scattPow)||(pos->first.second==scattPow)) { mvBumpMergePar.erase(pos++); mBumpMergeParClock.Click(); } else ++pos;// See Josuttis Std C++ Lib p.205 for safe method } for(map, REAL>::iterator pos=mvBondValenceRo.begin();pos!=mvBondValenceRo.end();) { if((pos->first.first==scattPow)||(pos->first.second==scattPow)) { mvBondValenceRo.erase(pos++); mBondValenceParClock.Click(); } else ++pos;// See Josuttis Std C++ Lib p.205 for safe method } VFN_DEBUG_EXIT("Crystal::RemoveScatteringPower()",2) } ScatteringPower& Crystal::GetScatteringPower(const string &name) { return mScatteringPowerRegistry.GetObj(name); } const ScatteringPower& Crystal::GetScatteringPower(const string &name)const { return mScatteringPowerRegistry.GetObj(name); } const RefinableObjClock& Crystal::GetMasterClockScatteringPower()const { return mMasterClockScatteringPower;} const ScatteringComponentList& Crystal::GetScatteringComponentList()const { if(mClockScattCompList>mClockMaster) return mScattCompList; bool update=false; if(mClockScattCompListGetClockLatticePar()) update=true; if(update==false) for(long i=0;iGetScatt(i).GetClockScatterer().Print(); if(mClockScattCompListGetScatt(i).GetClockScatterer()) {update=true;break;} } if(true==update) { VFN_DEBUG_MESSAGE("Crystal::GetScatteringComponentList()",2) TAU_PROFILE("Crystal::GetScatteringComponentList()","ScattCompList& ()",TAU_DEFAULT); mScattCompList.Reset(); for(long i=0;iGetScatt(i).GetScatteringComponentList().Print(); mScattCompList += this->GetScatt(i).GetScatteringComponentList(); } //:KLUDGE: this must be *before* calling CalcDynPopCorr() to avoid an infinite loop.. mClockScattCompList.Click(); if(1==mUseDynPopCorr.GetChoice()) this->CalcDynPopCorr(1.,.5); else this->ResetDynPopCorr(); VFN_DEBUG_MESSAGE("Crystal::GetScatteringComponentList():End",2) } #ifdef __DEBUG__ if(gVFNDebugMessageLevel<2) mScattCompList.Print(); #endif return mScattCompList; } const RefinableObjClock& Crystal::GetClockScattCompList()const { return mClockScattCompList; } void Crystal::Print(ostream &os)const { VFN_DEBUG_MESSAGE("Crystal::Print()",5) this->UnitCell::Print(os); this->GetScatteringComponentList(); this->CalcBondValenceSum(); os << "List of scattering components (atoms): " << mScattCompList.GetNbComponent() << endl ; long k=0; std::map::const_iterator posBV; for(int i=0;iPrint(); const ScatteringComponentList list=this->GetScatt(i).GetScatteringComponentList(); for(int j=0;jGetScatt(i).GetComponentName(j),16) << " at : " << FormatFloat(list(j).mX,7,4) << FormatFloat(list(j).mY,7,4) << FormatFloat(list(j).mZ,7,4) << ", Occup=" << FormatFloat(list(j).mOccupancy,6,4) << " * " << FormatFloat(mScattCompList(k).mDynPopCorr,6,4); // Check for dummy atoms if( NULL != list(j).mpScattPow ) { os << ", ScattPow:" << FormatString(list(j).mpScattPow->GetName(),16) << ", Biso=" << FormatFloat(list(j).mpScattPow->GetBiso()); } else { os << ", ScattPow: dummy"; } // Check for dummy atoms if( NULL != this->mScattCompList(k).mpScattPow ) { posBV=this->mvBondValenceCalc.find(k); if(posBV!=this->mvBondValenceCalc.end()) os <<": Valence="<second<<" (expected=" <mScattCompList(k).mpScattPow->GetFormalCharge()<<")"; } os << endl; k++; } } os < atom on a symetry plane / 2fold axis.."<< endl << " -> OR 2 atoms strictly overlapping)"<< endl <GetSpaceGroup().GetNbSymmetrics(); for(int i=0;iGetFormula() << endl << " Weight: "<< this->GetWeight()<< " g/mol" << endl; VFN_DEBUG_MESSAGE("Crystal::Print():End",5) } std::string Crystal::GetFormula() const { this->GetScatteringComponentList(); if(mScattCompList.GetNbComponent() == 0) return ""; std::map velts; for(unsigned int i=0; impScattPow == 0) continue; if(psi->mpScattPow->GetClassName().compare("ScatteringPowerAtom")!=0) continue; const ScatteringPowerAtom *pat=dynamic_cast(psi->mpScattPow); string p=pat->GetSymbol(); if(velts.count(p)==0) velts[p] = psi->mOccupancy * psi->mDynPopCorr ; else velts[p] += psi->mOccupancy * psi->mDynPopCorr; } stringstream s; s<::const_iterator pos=velts.begin();pos!=velts.end();++pos) { if(pos!=velts.begin()) s<<" "; float nb=pos->second; if(abs(round(nb)-nb)<0.005) { if(int(round(nb))==1) s<first; else s<first<first<GetScatteringComponentList(); if(mScattCompList.GetNbComponent() == 0) return 0; REAL w=0; for(unsigned int i=0; impScattPow == 0) continue; if(psi->mpScattPow->GetClassName().compare("ScatteringPowerAtom")!=0) continue; const ScatteringPowerAtom *pat=dynamic_cast(psi->mpScattPow); w += pat->GetAtomicWeight() * psi->mOccupancy * psi->mDynPopCorr ; } return w; } CrystMatrix_REAL Crystal::GetMinDistanceTable(const REAL minDistance) const { VFN_DEBUG_MESSAGE("Crystal::MinDistanceTable()",5) this->CalcDistTable(true); const long nbComponent=mScattCompList.GetNbComponent(); CrystMatrix_REAL minDistTable(nbComponent,nbComponent); REAL dist; REAL tmp; REAL min=minDistance*minDistance; if(minDistance<0) min = -1.;// no min distance minDistTable=10000.; for(int i=0;iGetMinDistanceTable(minDistance); VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable():0",5) os << "Table of minimal distances between all components (atoms)"<GetScatt(i).GetNbComponent();j++) os << FormatString(this->GetScatt(i).GetComponentName(j),7); } os << endl; long l=0; const long nbComponent=mScattCompList.GetNbComponent(); for(long i=0;iGetScatt(i).GetNbComponent();j++) { VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable()2:Scatt,comp:"<GetScatt(i).GetComponentName(j),14); for(long k=0;k0) os << FormatFloat(minDistTable(l,k),6,3) ; else os<<" >10 "; } os << endl; l++; } VFN_DEBUG_MESSAGE("Crystal::PrintMinDistanceTable():End",3) } ostream& Crystal::POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const { VFN_DEBUG_MESSAGE("Crystal::POVRayDescription(os,bool)",5) os <<"/////////////////////// MACROS////////////////////"<,atomr"<,"<,"<FractionalToOrthonormalCoords(x,y,z); os << " //box{ <0,0,0>, <"<< x << "," << y << "," << z << ">" <}" << endl; os << " // hollow" << endl; os << " //}" <FractionalToOrthonormalCoords(x0,y0,z0);\ this->FractionalToOrthonormalCoords(x1,y1,z1);\ os << " ObjCrystBond("\ <,1.0,1.0)"<;"<< endl; } os << "// Bond colours"<;"<< endl << " #declare colour_nonfreebond= rgb <0.3,0.3,0.3>;"<< endl; os<GetScatt(i).POVRayDescription(os,options) ; return os; } #ifdef OBJCRYST_GL void Crystal::GLInitDisplayList(const bool onlyIndependentAtoms, const REAL xMin,const REAL xMax, const REAL yMin,const REAL yMax, const REAL zMin,const REAL zMax, const bool displayNames, const bool hideHydrogens, const REAL fadeDistance, const bool fullMoleculeInLimits)const { VFN_DEBUG_ENTRY("Crystal::GLInitDisplayList()",5) REAL en=1;// if -1, display enantiomeric structure if(mDisplayEnantiomer.GetChoice()==1) en=-1; //Center of displayed unit REAL xc=(xMin+xMax)/2.; REAL yc=(yMin+yMax)/2.; REAL zc=(zMin+zMax)/2.; if(false==displayNames) { //Describe Unit Cell REAL x111= 1.; REAL y111= 1.; REAL z111= 1.; this->FractionalToOrthonormalCoords(x111,y111,z111); REAL x110= 1.; REAL y110= 1.; REAL z110= 0.; this->FractionalToOrthonormalCoords(x110,y110,z110); REAL x101= 1.; REAL y101= 0.; REAL z101= 1.; this->FractionalToOrthonormalCoords(x101,y101,z101); REAL x100= 1.; REAL y100= 0.; REAL z100= 0.; this->FractionalToOrthonormalCoords(x100,y100,z100); REAL x011= 0.; REAL y011= 1.; REAL z011= 1.; this->FractionalToOrthonormalCoords(x011,y011,z011); REAL x010= 0.; REAL y010= 1.; REAL z010= 0.; this->FractionalToOrthonormalCoords(x010,y010,z010); REAL x001= 0.; REAL y001= 0.; REAL z001= 1.; this->FractionalToOrthonormalCoords(x001,y001,z001); REAL x000= 0.; REAL y000= 0.; REAL z000= 0.; this->FractionalToOrthonormalCoords(x000,y000,z000); REAL xM= 0.5; REAL yM= 0.5; REAL zM= 0.5; this->FractionalToOrthonormalCoords(xM,yM,zM); xM*=2;yM*=2;zM*=2; glPushMatrix(); //Add Axis & axis names const GLfloat colour0 [] = {0.00, 0.00, 0.00, 0.00}; const GLfloat colour1 [] = {0.50, 0.50, 0.50, 1.00}; const GLfloat colour2 [] = {1.00, 1.00, 1.00, 1.00}; glMaterialfv(GL_FRONT, GL_AMBIENT, colour1); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour1); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); REAL x,y,z; x=1.2-xc;y=-yc;z=-zc; this->FractionalToOrthonormalCoords(x,y,z); glRasterPos3f(en*x,y,z); crystGLPrint("a"); x=-xc;y=1.2-yc;z=-zc; this->FractionalToOrthonormalCoords(x,y,z); glRasterPos3f(en*x,y,z); crystGLPrint("b"); x=-xc;y=-yc;z=1.2-zc; this->FractionalToOrthonormalCoords(x,y,z); glRasterPos3f(en*x,y,z); crystGLPrint("c"); // Cell glMaterialfv(GL_FRONT, GL_AMBIENT, colour1); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour1); glMaterialfv(GL_FRONT, GL_SPECULAR, colour1); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); this->FractionalToOrthonormalCoords(xc,yc,zc); glTranslatef(-xc*en, -yc, -zc); glBegin(GL_LINES); //top glNormal3f((x110+x010-xM)*en,y110+y010-yM,z110+z010-zM); glVertex3f( x110*en, y110, z110); glVertex3f( x010*en, y010, z010); glNormal3f((x011+x010-xM)*en,y011+y010-yM,z011+z010-zM); glVertex3f( x010*en, y010, z010); glVertex3f( x011*en, y011, z011); glNormal3f((x011+x111-xM)*en,y011+y111-yM,z011+z111-zM); glVertex3f( x011*en, y011, z011); glVertex3f( x111*en, y111, z111); glNormal3f((x110+x111-xM)*en,y110+y111-yM,z110+z111-zM); glVertex3f( x111*en, y111, z111); glVertex3f( x110*en, y110, z110); //bottom glNormal3f((x101+x001-xM)*en,y101+y001-yM,z101+z001-zM); glVertex3f( x101*en, y101, z101); glVertex3f( x001*en, y001, z001); glNormal3f((x000+x001-xM)*en,y000+y001-yM,z000+z001-zM); glVertex3f( x001*en, y001, z001); glVertex3f( x000*en, y000, z000); glNormal3f((x000+x100-xM)*en,y000+y100-yM,z000+z100-zM); glVertex3f( x000*en, y000, z000); glVertex3f( x100*en, y100, z100); glNormal3f((x101+x100-xM)*en,y101+y100-yM,z101+z100-zM); glVertex3f( x100*en, y100, z100); glVertex3f( x101*en, y101, z101); //sides glNormal3f((x101+x111-xM)*en,y101+y111-yM,z101+z111-zM); glVertex3f( x101*en, y101, z101); glVertex3f( x111*en, y111, z111); glNormal3f((x001+x011-xM)*en,y001+y011-yM,z001+z011-zM); glVertex3f( x001*en, y001, z001); glVertex3f( x011*en, y011, z011); glNormal3f((x000+x010-xM)*en,y000+y010-yM,z000+z010-zM); glVertex3f( x000*en, y000, z000); glVertex3f( x010*en, y010, z010); glNormal3f((x100+x110-xM)*en,y100+y110-yM,z100+z110-zM); glVertex3f( x100*en, y100, z100); glVertex3f( x110*en, y110, z110); glEnd(); glPopMatrix(); } //Describe all Scatterers VFN_DEBUG_MESSAGE("Crystal::GLView(bool):Scatterers...",5) glPushMatrix(); if(displayNames) this->FractionalToOrthonormalCoords(xc,yc,zc); glTranslatef(-xc*en, -yc, -zc); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); { bool displayEnantiomer=false; if(mDisplayEnantiomer.GetChoice()==1) displayEnantiomer=true; for(int i=0;iGetScatt(i).GLInitDisplayList(onlyIndependentAtoms, xMin,xMax,yMin,yMax,zMin,zMax, displayEnantiomer,displayNames,hideHydrogens,fadeDistance,fullMoleculeInLimits); } glPopMatrix(); VFN_DEBUG_EXIT("Crystal::GLInitDisplayList(bool)",5) } #endif // OBJCRYST_GL void Crystal::CalcDynPopCorr(const REAL overlapDist, const REAL mergeDist) const { VFN_DEBUG_ENTRY("Crystal::CalcDynPopCorr(REAL)",4) TAU_PROFILE("Crystal::CalcDynPopCorr()","void (REAL)",TAU_DEFAULT); this->CalcDistTable(true); if(mClockDynPopCorr>mDistTableClock) return; const long nbComponent=mScattCompList.GetNbComponent(); const int nbSymmetrics=this->GetSpaceGroup().GetNbSymmetrics(); CrystVector_REAL neighborsDist(nbComponent*nbSymmetrics); long nbNeighbors=0; REAL corr; int atomicNumber; const REAL overlapDistSq=overlapDist*overlapDist; REAL dist; for(long i=0;iGetDynPopCorrIndex(); nbNeighbors=0; std::vector::const_iterator pos; for(pos=mvDistTableSq[i].mvNeighbour.begin(); posmNeighbourIndex,0) if(0==mScattCompList(pos->mNeighbourIndex).mpScattPow)continue; if(atomicNumber==mScattCompList(pos->mNeighbourIndex).mpScattPow->GetDynPopCorrIndex()) { if(overlapDistSq > pos->mDist2) { //resizing can be necessary if the unit cell is small, so that an atom two unit cells away is //still considered a neighbor... if(nbNeighbors==neighborsDist.numElements()) neighborsDist.resizeAndPreserve(nbNeighbors+20); neighborsDist(nbNeighbors++)=sqrt(pos->mDist2); } } } corr=0.; for(long j=0;jGetUseDynPopCorr()==0) return 1.0; this->GetScatteringComponentList(); unsigned int j=0; for(long i=0;iGetScatt(i))) { return mScattCompList(j+component).mDynPopCorr; } else j+=this->GetScatt(i).GetScatteringComponentList().GetNbComponent(); } // Something is wrong if we got here ! throw ObjCrystException("Crystal::GetDynPopCorr(): did not find this scatterer !"); return 1.0; } void Crystal::SetUseDynPopCorr(const int b) { VFN_DEBUG_MESSAGE("Crystal::SetUseDynPopCorr()",1) mUseDynPopCorr.SetChoice(b); mClockDynPopCorr.Reset(); } int Crystal::GetUseDynPopCorr() const { return mUseDynPopCorr.GetChoice(); } int Crystal::FindScatterer(const string &scattName)const { VFN_DEBUG_MESSAGE("Crystal::FindScatterer(name)",0) for(int i=0;iGetNbScatterer();i++) { if( mScattererRegistry.GetObj(i).GetName() == scattName) return i; } throw ObjCrystException("Crystal::FindScatterer(string)\ Cannot find this scatterer:"+scattName); } Crystal::BumpMergePar::BumpMergePar(): mDist2(1.),mCanOverlap(false){} Crystal::BumpMergePar::BumpMergePar(const REAL dist, const bool canOverlap): mDist2(dist*dist),mCanOverlap(canOverlap){} REAL Crystal::GetBumpMergeCost() const { if(mvBumpMergePar.size()==0) return 0; if(mBumpMergeScale<1e-5) return 0; this->CalcDistTable(true); VFN_DEBUG_ENTRY("Crystal::GetBumpMergeCost()",4) if( (mBumpMergeCostClock>mBumpMergeParClock) &&(mBumpMergeCostClock>mDistTableClock)) return mBumpMergeCost*mBumpMergeScale; TAU_PROFILE("Crystal::GetBumpMergeCost()","REAL (REAL)",TAU_DEFAULT); mBumpMergeCost=0; std::vector::const_iterator pos; std::vector::const_iterator neigh; REAL tmp; const ScatteringPower *i1,*i2; VBumpMergePar::const_iterator par; for(pos=mvDistTableSq.begin();posmIndex).mpScattPow; for(neigh=pos->mvNeighbour.begin();neighmvNeighbour.end();neigh++) { i2=mScattCompList(neigh->mNeighbourIndex).mpScattPow; if(i1mDist2 > par->second.mDist2) continue; if(true==par->second.mCanOverlap) tmp = 0.5*sin(M_PI*(1.-sqrt(neigh->mDist2/par->second.mDist2)))/0.1; else tmp = tan(M_PI*0.49999*(1.-sqrt(neigh->mDist2/par->second.mDist2)))/0.1; mBumpMergeCost += tmp*tmp; } } mBumpMergeCost *= this->GetSpaceGroup().GetNbSymmetrics(); mBumpMergeCostClock.Click(); VFN_DEBUG_EXIT("Crystal::GetBumpMergeCost():"<SetBumpMergeDistance(scatt1,scatt2,dist,true) ; else this->SetBumpMergeDistance(scatt1,scatt2,dist,false); } void Crystal::SetBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2,const REAL dist, const bool allowMerge) { VFN_DEBUG_MESSAGE("Crystal::SetBumpMergeDistance("<GetNbScatterer(); if( ((rand()/(REAL)RAND_MAX)<.02) && (nb>1)) { // This is safe even if one scatterer is partially fixed, // since we the SetX/SetY/SetZ actually use the MutateTo() function. const unsigned long n1=rand()%nb; const unsigned long n2=( (rand()%(nb-1)) +n1+1) %nb; const float x1=this->GetScatt(n1).GetX(); const float y1=this->GetScatt(n1).GetY(); const float z1=this->GetScatt(n1).GetZ(); this->GetScatt(n1).SetX(this->GetScatt(n2).GetX()); this->GetScatt(n1).SetY(this->GetScatt(n2).GetY()); this->GetScatt(n1).SetZ(this->GetScatt(n2).GetZ()); this->GetScatt(n2).SetX(x1); this->GetScatt(n2).SetY(y1); this->GetScatt(n2).SetZ(z1); } else { this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type); } mRandomMoveIsDone=true; VFN_DEBUG_EXIT("Crystal::GlobalOptRandomMove()",2) } REAL Crystal::GetLogLikelihood()const { return this->GetBumpMergeCost()+this->GetBondValenceCost(); } void Crystal::CIFOutput(ostream &os, double mindist)const { VFN_DEBUG_ENTRY("Crystal::OutputCIF()",5) //Data block name (must have no spaces) string tempname = mName; int where, size; size = tempname.size(); if (size > 32) { tempname = tempname.substr(0,32); size = tempname.size(); } if (size == 0) { tempname = "3D"; size = 2; } where = tempname.find(" ",0); while (where != (int)string::npos) { tempname.replace(where,1,"_"); where = tempname.find(" ",0); //cout << tempname << endl; } os << "data_" << tempname <GetScatteringPowerRegistry().GetNb();i++) os << " " << this->GetScatteringPowerRegistry().GetObj(i).GetName()<<" " <GetScatteringPowerRegistry().GetObj(i).GetSymbol()<<" " <<"'International Tables for Crystallography (Vol. IV)'" <GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin(); const char ext = this->GetSpaceGroup().GetExtension(); if(isalnum(ext)) os <<":"<GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hall()<<"'"<GetLatticePar(0),8,5) << endl << "_cell_length_b " << FormatFloat(this->GetLatticePar(1),8,5) << endl << "_cell_length_c " << FormatFloat(this->GetLatticePar(2),8,5) << endl << "_cell_angle_alpha " << FormatFloat(this->GetLatticePar(3)*RAD2DEG,7,3) << endl << "_cell_angle_beta " << FormatFloat(this->GetLatticePar(4)*RAD2DEG,7,3) << endl << "_cell_angle_gamma " << FormatFloat(this->GetLatticePar(5)*RAD2DEG,7,3) << endl << "_cell_volume " << FormatFloat(this->GetVolume(),7,2); os <GetScatteringComponentList(); /* TODO: loop_ _symmetry_equiv_pos_site_id _symmetry_equiv_pos_as_xyz */ os << "loop_" << endl << " _atom_site_label" < anisovec; std::vector namevec; CrystMatrix_REAL minDistTable; minDistTable=this->GetMinDistanceTable(-1.); unsigned long k=0; for(int i=0;iPrint(); const ScatteringComponentList list=this->GetScatt(i).GetScatteringComponentList(); for(int j=0;j 10A if(!redundant) { // We can't have spaces in atom labels string s=this->GetScatt(i).GetComponentName(j); size_t posc=s.find(' '); while(posc!=string::npos){s[posc]='~';posc=s.find(' ');} bool isiso = list(j).mpScattPow->IsIsotropic(); if(!isiso) { anisovec.push_back(list(j).mpScattPow); namevec.push_back(s); } os << " " << FormatString(s,10) << " " << FormatString(list(j).mpScattPow->GetSymbol(),8) << " " << FormatFloat(list(j).mX,9,6) << " " << FormatFloat(list(j).mY,9,6) << " " << FormatFloat(list(j).mZ,9,6) << " " << FormatFloat(list(j).mpScattPow->GetBiso()*BtoU,9,6) << " " << FormatFloat(list(j).mOccupancy,6,4) << (isiso ? " Uiso" : " Uani") << endl; } k++; } } // Handle anisotropic atoms if( anisovec.size() > 0 ) { os << endl << "loop_" << endl << " _atom_site_aniso_label" << endl << " _atom_site_aniso_U_11" << endl << " _atom_site_aniso_U_22" << endl << " _atom_site_aniso_U_33" << endl << " _atom_site_aniso_U_12" << endl << " _atom_site_aniso_U_13" << endl << " _atom_site_aniso_U_23" << endl; for(size_t i = 0; i < anisovec.size(); ++i) { os << " " << FormatString(namevec[i],8) << " "; for(int j=0; j<6; ++j) os << FormatFloat(anisovec[i]->GetBij(j)*BtoU,9,6) << " "; os << endl; } } bool first=true; k=0; for(int i=0;iGetScatt(i).GetScatteringComponentList(); for(int j=0;j 10A if(redundant) { if(first) { first=false; os <GetName(),8) << " " << FormatString(this->GetScatt(i).GetComponentName(j),10) << " " << FormatFloat(list(j).mX,9,6) << " " << FormatFloat(list(j).mY,9,6) << " " << FormatFloat(list(j).mZ,9,6) << " " << FormatFloat(list(j).mpScattPow->GetBiso()*BtoU,9,6) << " " << FormatFloat(list(j).mOccupancy,6,4) << " Uiso" << endl; } k++; } } os <Print(); const ScatteringComponentList list=this->GetScatt(i).GetScatteringComponentList(); for(int j=0;jGetScatt(i).GetComponentName(j),16) << " : " << FormatFloat(mScattCompList(k).mDynPopCorr,6,4) << endl; k++; } } os << "#"<GetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { //if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeUnitCell)) //{ if(latticeIndex==0) latticeIndex=first++; groupIndex(i)=latticeIndex; //} //else //no parameters other than unit cell } } void Crystal::BeginOptimization(const bool allowApproximations,const bool enableRestraints) { if(this->IsBeingRefined()) { // RefinableObj::BeginOptimization() will increase the optimization depth this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); return; } for(int i=0;iGetScattererRegistry().GetNb();i++) { this->GetScattererRegistry().GetObj(i). SetGlobalOptimStep(gpRefParTypeScattTranslX,0.1/this->GetLatticePar(0)); this->GetScattererRegistry().GetObj(i). SetGlobalOptimStep(gpRefParTypeScattTranslY,0.1/this->GetLatticePar(1)); this->GetScattererRegistry().GetObj(i). SetGlobalOptimStep(gpRefParTypeScattTranslZ,0.1/this->GetLatticePar(2)); } this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); // Calculate mDistTableMaxDistance: Default 1 Angstroem, for dynamical occupancy correction mDistTableMaxDistance=1.0; // Up to 4 Angstroem if bond-valence is used if((mvBondValenceRo.size()>0) && (mBondValenceCostScale>1e-5)) mDistTableMaxDistance=4; // Up to whatever antibump distance the user requires (hopefully not too large !) for(Crystal::VBumpMergePar::iterator pos=mvBumpMergePar.begin();pos!=mvBumpMergePar.end();++pos) if(sqrt(pos->second.mDist2)>mDistTableMaxDistance) mDistTableMaxDistance=sqrt(pos->second.mDist2); VFN_DEBUG_MESSAGE("Crystal::BeginOptimization():mDistTableMaxDistance="<UpdateDisplay(); } void Crystal::RemoveBondValenceRo(const ScatteringPower &pow1,const ScatteringPower &pow2) { map, REAL>::iterator pos; if(&pow1 < &pow2) pos=mvBondValenceRo.find(make_pair(&pow1 , &pow2)); else pos=mvBondValenceRo.find(make_pair(&pow2 , &pow1)); if(pos!=mvBondValenceRo.end()) mvBondValenceRo.erase(pos); mBondValenceParClock.Click(); } REAL Crystal::GetBondValenceCost() const { VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost()?",4) if(mBondValenceCostScale<1e-5) return 0.0; if(mvBondValenceRo.size()==0) { mBondValenceCost=0.0; return mBondValenceCost*mBondValenceCostScale; } this->CalcBondValenceSum(); if( (mBondValenceCostClock>mBondValenceCalcClock) &&(mBondValenceCostClock>this->GetMasterClockScatteringPower())) return mBondValenceCost*mBondValenceCostScale; VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost():"<::const_iterator pos; for(pos=mvBondValenceCalc.begin();pos!=mvBondValenceCalc.end();++pos) { const REAL a=pos->second-mScattCompList(pos->first).mpScattPow->GetFormalCharge(); mBondValenceCost += a*a; VFN_DEBUG_MESSAGE("Crystal::GetBondValenceCost():" <first).mpScattPow->GetName() <<"="<second,4) } mBondValenceCostClock.Click(); return mBondValenceCost*mBondValenceCostScale; } std::map, REAL>& Crystal::GetBondValenceRoList() { return mvBondValenceRo;} const std::map, REAL>& Crystal::GetBondValenceRoList()const { return mvBondValenceRo;} void Crystal::CalcBondValenceSum()const { if(mvBondValenceRo.size()==0) return; this->CalcDistTable(true); VFN_DEBUG_MESSAGE("Crystal::CalcBondValenceSum()?",4) if( (mBondValenceCalcClock>mDistTableClock) &&(mBondValenceCalcClock>mBondValenceParClock)) return; VFN_DEBUG_MESSAGE("Crystal::CalcBondValenceSum()",4) TAU_PROFILE("Crystal::CalcBondValenceSum()","void ()",TAU_DEFAULT); mvBondValenceCalc.clear(); for(long i=0;i::const_iterator pos; for(pos=mvDistTableSq[i].mvNeighbour.begin(); posmDist2); const REAL occup= mScattCompList(pos->mNeighbourIndex).mOccupancy *mScattCompList(pos->mNeighbourIndex).mDynPopCorr; const ScatteringPower *pow2=mScattCompList(pos->mNeighbourIndex).mpScattPow; map,REAL>::const_iterator pos; if(pow1second-dist)/0.37); val += occup * v; nb++; } } if(nb!=0) mvBondValenceCalc[i]=val; } mBondValenceCalcClock.Click(); } void Crystal::Init(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId, const string& name) { VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name)",10) this->UnitCell::Init(a,b,c,alpha,beta,gamma,SpaceGroupId,name); mClockScattCompList.Reset(); mClockNeighborTable.Reset(); mClockDynPopCorr.Reset(); VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name):End",10) } bool CompareBondDist(MolBond* b1, MolBond* b2) { return b1->GetLength()GetLength(); } bool ComparePairSecond(const std::pair &b1, const std::pair &b2) { return b1.second < b2.second; } void Crystal::ConnectAtoms(const REAL min_relat_dist, const REAL max_relat_dist, const bool warnuser_fail) { VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...)",10) // Make sure there are only atoms for(unsigned int i=0;iCalcDistTable(true); this->GetScatteringComponentList(); // Create first Molecule // start from start_carbon Molecule *pmol=NULL; std::set vAssignedAtoms;//atoms already assigned to a Molecule std::set vTriedAtom0;//atoms already tried as starting point for a Molecule VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...)",10) while(long(vAssignedAtoms.size()) != mScattererRegistry.GetNb()) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): new Molecule ?",7) // We need at least one carbon atom to start int atom0=-1; int maxAtomicNumber = 0; for(unsigned int i=0;i0) || (vTriedAtom0.find(i)!=vTriedAtom0.end()) ) continue; if(mScattCompList(i).mpScattPow->GetClassName()=="ScatteringPowerAtom") { const ScatteringPowerAtom *p=dynamic_cast(mScattCompList(i).mpScattPow); if((p->GetAtomicNumber()==6)&&(maxAtomicNumber!=6)) {// Start from the first Carbon found atom0=i; maxAtomicNumber=6; } else if((p->GetAtomicNumber()>maxAtomicNumber) && (maxAtomicNumber!=6)) {// Else we'll try from the heaviest atom maxAtomicNumber=p->GetAtomicNumber(); atom0=i; } } else { if(warnuser_fail) (*fpObjCrystInformUser)("Crystal::ConnectAtoms(): cannot connect atoms unless there are only Atoms in a Crystal"); VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...):cannot connect atoms unless there are only Atoms in the structure:"<GetClassName(),10) return; } } if(atom0<0) { if((pmol==NULL) && warnuser_fail) // We did not create any Molecule :-( { (*fpObjCrystInformUser)("Crystal::ConnectAtoms(): cannot connect atoms unless there is at least one carbon atom"); VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...):cannot connect atoms unless there is at least one carbon atom",10) return; } break; } vTriedAtom0.insert(atom0); // Atoms in Molecule but for which neighbors have not yet been searched // first: index in the Crystal's scatt comp list, second: index in the Molecule std::mapnewAtoms; // List of all atoms in the Molecule. First is the MolAtom* in the molecule, second is the index in the Crystal std::map molAtoms; pmol=new Molecule(*this); // Add atom0 to Molecule. newAtoms[atom0]=0; vAssignedAtoms.insert(atom0); const ScatteringPowerAtom *p0=dynamic_cast(mScattCompList(atom0).mpScattPow); { REAL x=mScattCompList(atom0).mX; REAL y=mScattCompList(atom0).mY; REAL z=mScattCompList(atom0).mZ; const REAL occ=mScattCompList(atom0).mOccupancy; this->FractionalToOrthonormalCoords(x,y,z); pmol->AddAtom(x,y,z,p0,mScattererRegistry.GetObj(atom0).GetName(),false); pmol->GetAtomList().back()->SetOccupancy(occ); } molAtoms[pmol->GetAtomList().back()]=atom0; // Count atoms in the Molecule per element type vector vElementCount(140);// Should be safe pending a trans-uranian breakthrough for(vector::iterator pos=vElementCount.begin();pos!=vElementCount.end();++pos) *pos=0; vElementCount[p0->GetAtomicNumber()]+=1; while(newAtoms.size()>0) { atom0=newAtoms.begin()->first; p0=dynamic_cast(mScattCompList(atom0).mpScattPow); VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...):atom0="<GetSymbol()<<"],"< > vatomsneighbours; // Find neigbours between min and max * sum of covalent bonds for(std::vector::const_iterator pos=mvDistTableSq[atom0].mvNeighbour.begin(); pos!=mvDistTableSq[atom0].mvNeighbour.end();pos++) { const ScatteringPowerAtom *p1=dynamic_cast(mScattCompList(pos->mNeighbourIndex).mpScattPow); const REAL dcov= p0->GetCovalentRadius()+p1->GetCovalentRadius(); //if( (vAssignedAtoms.count(pos->mNeighbourIndex)!=0) || (p1->GetMaxCovBonds()==0)) if(p1->GetMaxCovBonds()==0) continue; if( ((min_relat_dist*dcov)mDist2)) &&((max_relat_dist*dcov)>sqrt(pos->mDist2))) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):atom0="<GetName()<<"("<GetMaxCovBonds()<<"):dcov="<mDist2),7) vatomsneighbours.push_back(std::make_pair(pos->mNeighbourIndex,sqrt(pos->mDist2))); } else { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):atom0="<GetName()<<"("<GetMaxCovBonds()<<"):dcov="<mDist2),5) } } // Remove farthest neighbours if in excess of the maximum coordination. // But keep excess neighbours if close (5%) of the last neighbour within the normal coordination number. const unsigned int maxbonds=p0->GetMaxCovBonds(); float extra=vatomsneighbours.size()-maxbonds; if(extra>0) { // Check real number of bonds taking into account occupancy, and sort bonds by length REAL nbbond=0; for(std::vector >::const_iterator pos=vatomsneighbours.begin();pos!=vatomsneighbours.end();++pos) { nbbond+=mScattCompList(pos->first).mOccupancy; } extra = nbbond-maxbonds; if(extra>0.2) { std::sort(vatomsneighbours.begin(), vatomsneighbours.end(),ComparePairSecond); VFN_DEBUG_ENTRY("Crystal::ConnectAtoms(...): too many bonds for"<maxdist) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Remove bond="<0) cout<<"Crystal::ConnectAtoms(): adding neighbours around "< >::const_iterator pos=vatomsneighbours.begin();pos!=vatomsneighbours.end();++pos) { if(vAssignedAtoms.count(pos->first)!=0) { if(extra>0) cout<<"("<first).GetName()<<") "; continue; } //if(extra>0) cout<first).GetName()<<" "; const ScatteringPowerAtom *p1=dynamic_cast(mScattCompList(pos->first).mpScattPow); vAssignedAtoms.insert(pos->first); REAL x=mScattCompList(pos->first).mX; REAL y=mScattCompList(pos->first).mY; REAL z=mScattCompList(pos->first).mZ; this->FractionalToOrthonormalCoords(x,y,z); const REAL occ=mScattCompList(pos->first).mOccupancy; pmol->AddAtom(x,y,z,p1,mScattererRegistry.GetObj(pos->first).GetName(),false); pmol->GetAtomList().back()->SetOccupancy(occ); newAtoms[pos->first]=pmol->GetNbComponent()-1; molAtoms[pmol->GetAtomList().back()]=pos->first; vElementCount[p1->GetAtomicNumber()]+=1; } //if(extra>0) cout<GetSymbol()<<"],"<GetFormula(),7) } // Check this is a valid Molecule object bool keep=false; if((vElementCount[6]>0) && (pmol->GetNbComponent()>=3)) keep=true; else {// no carbon ? std::vector vnb; #ifdef __DEBUG__ cout<<" Crystal::ConnectAtoms(..): Molecule ?"; #endif for(unsigned int i=0;i2)) keep=true; #endif // Accept any type of cluster with exactly two types of atoms keep=true; } } if(!keep) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):Rejected molecule: "<GetFormula(),10) delete pmol; for(std::map::const_iterator pos=molAtoms.begin();pos!=molAtoms.end();++pos) vAssignedAtoms.erase(pos->second); continue;// Will start from another atom to build a molecule } // Add bonds for(unsigned int i=0;iGetAtomList().size();i++) { for(unsigned int j=i+1;jGetAtomList().size();j++) { const REAL d=GetBondLength(pmol->GetAtom(i), pmol->GetAtom(j)); const REAL dcov= dynamic_cast(&(pmol->GetAtom(i).GetScatteringPower()))->GetCovalentRadius() +dynamic_cast(&(pmol->GetAtom(j).GetScatteringPower()))->GetCovalentRadius(); if( ((min_relat_dist*dcov)d)) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):Add bond="<GetAtom(i).GetName()<<"-"<GetAtom(j).GetName()<<", d="<AddBond(pmol->GetAtom(i),pmol->GetAtom(j),d,.01,.02,false); } } } // Remove longest bonds if it exceeds the expected coordination // :TODO: combined with the check already made, this is not fullproof, for atoms where the coordination number is not so well-defined, // e.g. Li and Na is defined as 1, but there could be more linked atoms... // If we still find a too great coordination number, remove excess ones but still keep those that are very close (5%) of the cutoff distance. for(vector::iterator pos=pmol->GetAtomList().begin();pos!=pmol->GetAtomList().end();) { pmol->BuildConnectivityTable(); map >::const_iterator p=pmol->GetConnectivityTable().find(*pos); if(p==pmol->GetConnectivityTable().end()) {// While cleaning the longest bond, this atom had all his bonds removed ! VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...):no bond remaining for:"<<(*pos)->GetName()<<"! Removing atom from Molecule",10) //Remove MolAtom from Molecule and keep in Crystal. vAssignedAtoms.erase(molAtoms[*pos]); molAtoms.erase(*pos); pos=pmol->RemoveAtom(**pos); continue; } const unsigned int maxbonds=dynamic_cast(&(p->first->GetScatteringPower()))->GetMaxCovBonds(); int extra=p->second.size()-maxbonds; if(extra>0) { // Check real number of bonds taking into account occupancy, and sort bonds by length std::vector vbonds; REAL nbbond=0; for(std::set::iterator p1=p->second.begin();p1!=p->second.end();++p1) { vbonds.push_back(*(pmol->FindBond(**pos,**p1)));// We can assume that exactly one bond is found nbbond+=(*p1)->GetOccupancy(); } VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): too many bonds for"<<(*pos)->GetName()<<" ?(allowed="<second.size()<<",nb_occ="<0) { std::sort(vbonds.begin(), vbonds.end(),CompareBondDist); if(size_t(extra) < vbonds.size()) // Am I paranoid ? { const REAL maxdist=vbonds[vbonds.size()-extra]->GetLength()*1.05; while(vbonds.back()->GetLength()>maxdist) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Remove bond="<GetAtom1().GetName()<<"-"<GetAtom2().GetName()<<", d="<GetLength(),10) pmol->RemoveBond(*(vbonds.back())); vbonds.pop_back(); VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): Next bond ="<GetAtom1().GetName()<<"-"<GetAtom2().GetName()<<", d="<GetLength(),10) } } } } ++pos; } // Add all bond angles pmol->BuildConnectivityTable(); for(map >::const_iterator pos=pmol->GetConnectivityTable().begin(); pos!=pmol->GetConnectivityTable().end();++pos) { for(set::const_iterator pos1=pos->second.begin(); pos1!=pos->second.end();++pos1) { for(set::const_iterator pos2=pos1; pos2!=pos->second.end();++pos2) { if(pos2==pos1) continue; if(pmol->FindBondAngle(**pos1,*(pos->first),**pos2)== pmol->GetBondAngleList().end()) pmol->AddBondAngle(**pos1,*(pos->first),**pos2, GetBondAngle(**pos1,*(pos->first),**pos2),0.01,0.02,false); } } } // Correct center of Molecule REAL xc=0,yc=0,zc=0; for(std::map::const_iterator pos=molAtoms.begin();pos!=molAtoms.end();++pos) { REAL x=mScattCompList(pos->second).mX; REAL y=mScattCompList(pos->second).mY; REAL z=mScattCompList(pos->second).mZ; this->FractionalToOrthonormalCoords(x,y,z); xc+=x; yc+=y; zc+=z; } xc /= pmol->GetNbComponent(); yc /= pmol->GetNbComponent(); zc /= pmol->GetNbComponent(); this->OrthonormalToFractionalCoords(xc,yc,zc); VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): center?"<GetNbComponent()<<","<SetX(xc); pmol->SetY(yc); pmol->SetZ(zc); this->AddScatterer(pmol); (*fpObjCrystInformUser)("ConnectAtoms: found Molecule: "+pmol->GetFormula()); } std::set vpAtom; for(std::set::const_iterator pos=vAssignedAtoms.begin();pos!=vAssignedAtoms.end();++pos) { Scatterer *s=&(this->GetScattererRegistry().GetObj(*pos)); vpAtom.insert(s); } while(vpAtom.size()>0) { VFN_DEBUG_MESSAGE("Crystal::ConnectAtoms(...): remove atom:"<<(*vpAtom.begin())->GetName()<<","<RemoveScatterer(*vpAtom.begin(),true); vpAtom.erase(vpAtom.begin()); } VFN_DEBUG_EXIT("Crystal::ConnectAtoms(...)",10) } void Crystal::MergeEqualScatteringPowers(const bool oneScatteringPowerPerElement) { VFN_DEBUG_ENTRY("Crystal::MergeEqualScatteringPowers("< vremovedpow; std::map > vequivpow; for(unsigned int i=0;iGetScatteringPowerRegistry().GetNb();i++) { ScatteringPower *p1 = &(this->GetScatteringPowerRegistry().GetObj(i)); if(vremovedpow.find(p1)!=vremovedpow.end()) continue; vequivpow[p1] = std::set(); for(unsigned int j=i+1;jGetScatteringPowerRegistry().GetNb();j++) { ScatteringPower *p2 = &(this->GetScatteringPowerRegistry().GetObj(j)); if(oneScatteringPowerPerElement) { if(p1->GetClassName() != p2->GetClassName()) continue; if(p1->GetSymbol() != p2->GetSymbol()) continue; } else { if(*p1 != *p2) continue; } vequivpow[p1].insert(p2); vremovedpow.insert(p2); } } if(oneScatteringPowerPerElement) { // Average Biso and Bij for(std::map >::iterator pos=vequivpow.begin();pos!=vequivpow.end();++pos) { if(pos->second.size()==0) continue; REAL b = pos->first->GetBiso(); CrystVector_REAL bij(6); for(unsigned int i=0;i<6;i++) bij(i) = pos->first->GetBij(i); for(std::set::const_iterator pos2=pos->second.begin(); pos2!=pos->second.end();++pos2) { b += (*pos2)->GetBiso(); for(unsigned int i=0;i<6;i++) bij(i) += (*pos2)->GetBij(i); } b /= pos->second.size() + 1; bij /= pos->second.size() + 1; pos->first->SetBiso(b); for(unsigned int i=0;i<6;i++) if(abs(bij(i)) > 1e-6) pos->first->SetBij(i,bij(i)); } } // Update Atoms or MolAtoms with new ScatteringPower for(std::map >::iterator pos=vequivpow.begin();pos!=vequivpow.end();++pos) { const unsigned int nb = pos->second.size(); if(oneScatteringPowerPerElement) pos->first->SetName(pos->first->GetSymbol()); if(nb>0) (*fpObjCrystInformUser)((boost::format("Merging ScatteringPower: %s[%s] (%d identical scattering powers)") % pos->first->GetName().c_str() % pos->first->GetSymbol().c_str() % pos->second.size()).str()); for(std::set::const_iterator pos2=pos->second.begin(); pos2!=pos->second.end();++pos2) { for(unsigned int i=0;iGetNbScatterer();++i) { Scatterer *p = &(this->GetScatt(i)); if(p->GetClassName()=="Atom") { Atom *pat=dynamic_cast(p); if(&(pat->GetScatteringPower()) == (*pos2)) { VFN_DEBUG_MESSAGE("Crystal:MergeEqualScatteringPowers() Atom "<GetName()<<": "<GetScatteringPower().GetName()<<"->"<first->GetName(), 10) pat->SetScatteringPower(*(pos->first)); } } else if (p->GetClassName()=="Molecule") { Molecule *pmol=dynamic_cast(p); for(std::vector::iterator pat=pmol->GetAtomList().begin();pat!=pmol->GetAtomList().end();++pat) { if(&((*pat)->GetScatteringPower()) == (*pos2)) (*pat)->SetScatteringPower(*(pos->first)); } } else { // This should only happen if a new type of scatterer was derived cout<<__FILE__<<":"<<__LINE__<<":Crystal::MergeEqualScatteringPowers(): unidentified scatterer, cannot merge scattering power..." <<(*pos2)->GetName()<<"["<<(*pos2)->GetClassName()<<"]"<::iterator pos=vremovedpow.begin();pos!=vremovedpow.end();++pos) { #ifdef __DEBUG__ const unsigned int nb=(*pos)->GetClientRegistry().GetNb(); if(nb>0) { VFN_DEBUG_MESSAGE("Crystal::MergeEqualScatteringPowers(): "<GetName()<<"["<<(*pos)->GetClassName()<<"]", 5) for(unsigned int i=0; iGetClientRegistry().GetObj(i))<<":"<<(*pos)->GetClientRegistry().GetObj(i).GetName()<<"["<<(*pos)->GetClientRegistry().GetObj(i).GetClassName()<<"]", 5) } } #endif this->RemoveScatteringPower(*pos,true); } this->UpdateDisplay(); VFN_DEBUG_EXIT("Crystal::MergeEqualScatteringPowers()", 10) } void Crystal::InitOptions() { VFN_DEBUG_ENTRY("Crystal::InitOptions",10) static string UseDynPopCorrname; static string UseDynPopCorrchoices[2]; static string DisplayEnantiomername; static string DisplayEnantiomerchoices[2]; static bool needInitNames=true; if(true==needInitNames) { UseDynPopCorrname="Use Dynamical Occupancy Correction"; UseDynPopCorrchoices[0]="No"; UseDynPopCorrchoices[1]="Yes"; DisplayEnantiomername="Display Enantiomer"; DisplayEnantiomerchoices[0]="No"; DisplayEnantiomerchoices[1]="Yes"; needInitNames=false;//Only once for the class } VFN_DEBUG_MESSAGE("Crystal::Init(a,b,c,alpha,beta,gamma,Sg,name):Init options",5) mUseDynPopCorr.Init(2,&UseDynPopCorrname,UseDynPopCorrchoices); mUseDynPopCorr.SetChoice(1); this->AddOption(&mUseDynPopCorr); mDisplayEnantiomer.Init(2,&DisplayEnantiomername,DisplayEnantiomerchoices); mDisplayEnantiomer.SetChoice(0); this->AddOption(&mDisplayEnantiomer); VFN_DEBUG_EXIT("Crystal::InitOptions",10) } Crystal::Neighbour::Neighbour(const unsigned long neighbourIndex,const int sym, const REAL dist2): mNeighbourIndex(neighbourIndex),mNeighbourSymmetryIndex(sym),mDist2(dist2) {} struct DistTableInternalPosition { DistTableInternalPosition(const long atomIndex, const int sym, const REAL x,const REAL y,const REAL z): mAtomIndex(atomIndex),mSymmetryIndex(sym),mX(x),mY(y),mZ(z) {} /// Index of the atom (order) in the component list long mAtomIndex; /// Which symmetry operation does this symmetric correspond to ? int mSymmetryIndex; /// Fractionnal coordinates REAL mX,mY,mZ; }; void Crystal::CalcDistTable(const bool fast) const { this->GetScatteringComponentList(); if(!this->IsBeingRefined()) { if(mDistTableMaxDistance!=10) mDistTableClock.Reset(); mDistTableMaxDistance=10; } if( (mDistTableClock>mClockScattCompList) &&(mDistTableClock>this->GetClockMetricMatrix())) return; VFN_DEBUG_ENTRY("Crystal::CalcDistTable(fast="<::iterator pos; for(pos=mvDistTableSq.begin();posmvNeighbour.clear(); } VFN_DEBUG_MESSAGE("Crystal::CalcDistTable():1",3) // Get range and origin of the (pseudo) asymmetric unit const REAL asux0=this->GetSpaceGroup().GetAsymUnit().Xmin(); const REAL asuy0=this->GetSpaceGroup().GetAsymUnit().Ymin(); const REAL asuz0=this->GetSpaceGroup().GetAsymUnit().Zmin(); const REAL asux1=this->GetSpaceGroup().GetAsymUnit().Xmax(); const REAL asuy1=this->GetSpaceGroup().GetAsymUnit().Ymax(); const REAL asuz1=this->GetSpaceGroup().GetAsymUnit().Zmax(); const REAL halfasuxrange=(asux1-asux0)*0.5+1e-5; const REAL halfasuyrange=(asuy1-asuy0)*0.5+1e-5; const REAL halfasuzrange=(asuz1-asuz0)*0.5+1e-5; const REAL asuxc=0.5*(asux0+asux1); const REAL asuyc=0.5*(asuy0+asuy1); const REAL asuzc=0.5*(asuz0+asuz1); const REAL maxdx=halfasuxrange+mDistTableMaxDistance/GetLatticePar(0); const REAL maxdy=halfasuyrange+mDistTableMaxDistance/GetLatticePar(1); const REAL maxdz=halfasuzrange+mDistTableMaxDistance/GetLatticePar(2); // List of all positions within or near the first atom generated std::vector vPos; // index of unique atoms in vPos, which are strictly in the asymmetric unit std::vector vUniqueIndex(nbComponent); const REAL asymUnitMargin2 = mDistTableMaxDistance*mDistTableMaxDistance; if(true)//(true==fast) { VFN_DEBUG_MESSAGE("Crystal::CalcDistTable(fast):2",3) TAU_PROFILE("Crystal::CalcDistTable(fast=true)","Matrix (string&)",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"DiffractionData::CalcDistTable1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"DiffractionData::CalcDistTable2","", TAU_FIELD); TAU_PROFILE_START(timer1); // No need to loop on a,b,c translations if mDistTableMaxDistance is small enough bool loopOnLattice=true; if( ((this->GetLatticePar(0)*.5)>mDistTableMaxDistance) &&((this->GetLatticePar(1)*.5)>mDistTableMaxDistance) &&((this->GetLatticePar(2)*.5)>mDistTableMaxDistance)) loopOnLattice=false; CrystMatrix_REAL symmetricsCoords; const int nbSymmetrics=this->GetSpaceGroup().GetNbSymmetrics(false,false); // Get the list of all atoms within or near the asymmetric unit for(long i=0;iGetSpaceGroup().GetAllSymmetrics(mScattCompList(i).mX, mScattCompList(i).mY, mScattCompList(i).mZ, false,false,false); mvDistTableSq[i].mIndex=i;//USELESS ? bool hasUnique=false; for(int j=0;j.5)x-=1; REAL y=fmod(symmetricsCoords(j,1)-asuyc,(REAL)1.0);if(y<-.5)y+=1;else if(y>.5)y-=1; REAL z=fmod(symmetricsCoords(j,2)-asuzc,(REAL)1.0);if(z<-.5)z+=1;else if(z>.5)z-=1; //cout<GetOrthMatrix()); const REAL m00=(*pOrthMatrix)(0,0); const REAL m01=(*pOrthMatrix)(0,1); const REAL m02=(*pOrthMatrix)(0,2); const REAL m11=(*pOrthMatrix)(1,1); const REAL m12=(*pOrthMatrix)(1,2); const REAL m22=(*pOrthMatrix)(2,2); for(long i=0;iIsBeingRefined()) cout<GetName()<<":" < * const vnb=&(mvDistTableSq[i].mvNeighbour); const REAL x0i=vPos[vUniqueIndex[i] ].mX; const REAL y0i=vPos[vUniqueIndex[i] ].mY; const REAL z0i=vPos[vUniqueIndex[i] ].mZ; for(unsigned long j=0;j.5)x-=1; REAL y=fmod(vPos[j].mY - y0i,(REAL)1.0);if(y<-.5)y+=1;if(y>.5)y-=1; REAL z=fmod(vPos[j].mZ - z0i,(REAL)1.0);if(z<-.5)z+=1;if(z>.5)z-=1; const REAL x0=m00 * x + m01 * y + m02 * z; const REAL y0= m11 * y + m12 * z; const REAL z0= m22 * z; if(loopOnLattice)// distance to self ! {//Now loop over lattice translations for(int sz=-1;sz<=1;sz+=2)// Sign of translation { for(int nz=(sz+1)/2;;++nz) { const REAL z=z0+sz*nz*m22; if(abs(z)>mDistTableMaxDistance) break; for(int sy=-1;sy<=1;sy+=2)// Sign of translation { for(int ny=(sy+1)/2;;++ny) { const REAL y=y0 + sy*ny*m11 + sz*nz*m12; if(abs(y)>mDistTableMaxDistance) break; for(int sx=-1;sx<=1;sx+=2)// Sign of translation { for(int nx=(sx+1)/2;;++nx) { if((vUniqueIndex[i]==j) && (nx==0) && (ny==0) && (nz==0)) continue;// distance to self ! const REAL x=x0 + sx*nx*m00 + sy*ny*m01 + sz*nz*m02; if(abs(x)>mDistTableMaxDistance) break; const REAL d2=x*x+y*y+z*z; if(d2<=asymUnitMargin2) { Neighbour neigh(vPos[j].mAtomIndex,vPos[j].mSymmetryIndex,d2); vnb->push_back(neigh); #if 0 if(!this->IsBeingRefined()) cout<<" "<GetName()<<":" <push_back(neigh); #if 0 if(!this->IsBeingRefined()) cout<GetName()<<":" < #include //#include //#include //#include //#include //#include namespace ObjCryst { class Scatterer; //forward declaration of another header's class :KLUDGE: extern const RefParType *gpRefParTypeCrystal; class NiftyStaticGlobalObjectsInitializer_Crystal { public: NiftyStaticGlobalObjectsInitializer_Crystal() { if (mCount++ == 0) { gpRefParTypeCrystal=new RefParType (gpRefParTypeUnitCell,"Crystal"); } } ~NiftyStaticGlobalObjectsInitializer_Crystal() { if (--mCount == 0) { delete gpRefParTypeCrystal; gpRefParTypeCrystal=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_Crystal NiftyStaticGlobalObjectsInitializer_Crystal_counter; //###################################################################### /** \brief Crystal class: Unit cell, spacegroup, scatterers * * A Crystal object has several main characteristics : (1) a unit cell, * (2) a Spacegroup and (3) a list of Scatterer. Also stored in the Crystal * is a list of the ScttaringPower used by all the scatterers of this crystal. * * The crystal is capable of giving a list of all scattering components * (ie the list of all unique scattering 'points' (ScatteringComponent, ie atoms) * in the unit cell, each associated to a ScatteringPower). * * When those scattering components are on a special position or overlapping with * another component of the same type, it is possible to correct * dynamically the occupancy of this/these components to effectively have * only one component instead of several due to the overlapping. This * method is interesting for global optimization where atoms must not be "locked" * on a special position. If this "Dynamical Occupancy Correction" * is used then no occupancy should be corrected for special positions, since * this will be done dynamically. * * A crystal structure can be viewed in 3D using OpenGL. * * \todo exporting (and importing) crystal structures to/from other files * format than ObjCryst's XML (eg CIF, and format used by refinement software) * * Currently only 3D crystal structures can be handled, with no magnetic * structure (that may be done later) and no incommensurate structure. */ //###################################################################### class Crystal:public UnitCell { public: /// Default Constructor Crystal(); /** \brief Crystal Constructor (orthorombic) * \param a,b,c : unit cell dimension, in angstroems * \param SpaceGroupId: space group symbol or number */ Crystal(const REAL a, const REAL b, const REAL c, const string &SpaceGroupId); /** \brief Crystal Constructor (triclinic) * \param a,b,c : unit cell dimension, in angstroems * \param alpha,beta,gamma : unit cell angles, in radians. * \param SpaceGroupId: space group symbol or number */ Crystal(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId); /// Crystal copy constructor Crystal(const Crystal &oldCryst); /// Crystal destructor ~Crystal(); virtual const string& GetClassName() const; /** \brief Add a scatterer to the crystal. * * \warning the scatterer \e must be allocated in the heap, since the scatterer * will \e not be copied but used directly. A Scatterer can only belong to one Crystal. It * will be detroyed when removed or when the Crystal is destroyed. * \param scatt : the address of the scatterer to be included in the crystal * scatterer names \b must be unique in a given crystal. * \note that the ScatteringPower used in the Scatterer should be one * of the Crystal (see Crystal::AddScatteringPower()) * */ void AddScatterer(Scatterer *scatt); /// Remove a Scatterer. This also deletes the scatterer unless del=false. void RemoveScatterer(Scatterer *scatt, const bool del=true); /// Number of scatterers in the crystal long GetNbScatterer()const; /** \brief Provides an access to the scatterers * * \param scattName the name of the scatterer to access */ Scatterer & GetScatt(const string &scattName); /** \brief Provides a const access to the scatterers * * \param scattName the name of the scatterer to access */ const Scatterer & GetScatt(const string &scattName) const; /** \brief Provides an access to the scatterers * * \param scattIndex the number of the scatterer to access */ Scatterer & GetScatt(const long scattIndex); /** \brief Provides a const access to the scatterers * * \param scattIndex the number of the scatterer to access */ const Scatterer & GetScatt(const long scattIndex) const; /// Get the registry of scatterers ObjRegistry& GetScattererRegistry(); /// Get the registry of scatterers const ObjRegistry& GetScattererRegistry()const; /// Get the registry of ScatteringPower included in this Crystal. ObjRegistry& GetScatteringPowerRegistry(); /// Get the registry of ScatteringPower included in this Crystal. const ObjRegistry& GetScatteringPowerRegistry()const; /// Add a ScatteringPower for this Crystal. It must be allocated in the heap, /// and not used by any other Crystal. void AddScatteringPower(ScatteringPower *scattPow); /// Remove a ScatteringPower for this Crystal. (the Scattering power is deleted unless del=false). /// This function should check that it is not used any more before removing it. void RemoveScatteringPower(ScatteringPower *scattPow, const bool del=true); /// Find a ScatteringPower from its name. Names must be unique in a given Crystal. ScatteringPower& GetScatteringPower(const string &name); /// Find a ScatteringPower from its name. Names must be unique in a given Crystal. const ScatteringPower& GetScatteringPower(const string &name)const; /// Get the clock which reports all changes in ScatteringPowers const RefinableObjClock& GetMasterClockScatteringPower()const; /** \brief Get the list of all scattering components */ virtual const ScatteringComponentList& GetScatteringComponentList()const; /** \brief Get the list of all scattering components */ const RefinableObjClock& GetClockScattCompList()const; /// Prints some info about the crystal /// \todo one function to print on one line and a PrintLong() function /// \param os the stream to which the information is outputed (default=cout) void Print(ostream &os=cout) const; /// Formula with atoms in alphabetic order std::string GetFormula() const; /// Weight for the crystal formula, in atomic units (g/mol). This should be /// multiplied by the spacegroup multiplity to get the unit cell weight. REAL GetWeight() const; /** \brief Minimum interatomic distance between all scattering components (atoms) in * the crystal. * * This will return a symmetrical matrix with NbComp rows and cols, where * NbComp is the number of independent scattering components in the unit cell. * All distances are given in Angstroems. * * Note that the distance of a given atom with 'itself' is not generally equal * to 0 (except full special position), but equal to the min distance with its * symmetrics. * * \param minDistance : atoms who are less distant than (minDistance,in Angstroems) * are considered equivalent. So the smallest distance between any atoms will * be at least minDistance. */ CrystMatrix_REAL GetMinDistanceTable(const REAL minDistance=0.1) const; /** \brief Print the minimum distance table between all scattering centers * (atoms) in the crystal. * \param os the stream to which the information is outputed (default=cout) */ void PrintMinDistanceTable(const REAL minDistance=0.1,ostream &os=cout) const; /** \brief XMLOutput POV-Ray Description for this Crystal * * \param onlyIndependentAtoms if false, all symmetrics are showed in the * drawing. * * \warning This currently needs some fixing (ZScatterer does not work ?) * Use rather the OpenGL 3D display which is more useful. * * \param os the stream to which the information is outputed (default=cout) */ ostream& POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const; #ifdef OBJCRYST_GL /** Create an OpenGL DisplayList of the crystal. * \param onlyIndependentAtoms if false (the default), then all symmetrics * are displayed within the given limits * \ param xMin,xMax,yMin,yMax,zMin,zMax: in fractionnal coordinates, the region * in which we want scaterrers to be displayed. The test is made on the center * of the scatterer (eg a ZScatterer (molecule) will not be 'cut' on the border). * \param displayNames: if true, only the names of the scatterers will be displayed, * at the position of the scatterers (to actually see them, they will have to * be translated with respect to the drawing of the scatterers). * \param hideHydrogens: if true, do not display hydrogens/deuterium and their bonds * \param fadeDistance: atoms which are beyond the display limits are still showm, but * with transparency which is progressively fading up to a certain distance. */ virtual void GLInitDisplayList(const bool onlyIndependentAtoms=false, const REAL xMin=-.1,const REAL xMax=1.1, const REAL yMin=-.1,const REAL yMax=1.1, const REAL zMin=-.1,const REAL zMax=1.1, const bool displayNames=false, const bool hideHydrogens=false, const REAL fadeDistance=0, const bool fullMoleculeInLimits=false)const; #endif // OBJCRYST_GL /** \internal \brief Compute the 'Dynamical population correction for all atoms. * Atoms which are considered "equivalent" (ie currently with the same Z number) * and which are overlapping see their Dynamical occupancy changed so that when they * fully overlap, they are equivalent to 1 atom. * * *\param overlapDist : distance below which atoms (ScatteringComponents, to be more precise) * are considered overlapping and * should be corrected. The correction changes the dynamical occupancy from * 1 to 1/nbAtomOverlapping, progressively as the distance falls from \e overlapDist * to \e mergeDist. *\param mergeDist : distance below which atoms are considered fully overlapping. * If 3 atoms are 'fully' overlapping, then all have a dynamical population * correction equal to 1/3 * * This is const since ScatteringComponent::mDynPopCorr is mutable. * * \warning. Do not call this function, which will turn private. This is * called by \e only Crystal::GetScatteringComponentList() */ void CalcDynPopCorr(const REAL overlapDist=1., const REAL mergeDist=.0)const ; /// Reset Dynamical Population Correction factors (ie set it to 1) void ResetDynPopCorr()const ; /** Access the Dynamical Occupancy Correction for a given component (atom) * in a given Scatterer */ REAL GetDynPopCorr(const Scatterer* pscatt, unsigned int component)const; /** Set the use of dynamical population correction (Crystal::mUseDynPopCorr). * Atoms which are considered "equivalent" (ie currently with the same Z number) * and which are overlapping see their Dynamical occupancy changed so that when they * fully overlap, they are equivalent to 1 atom. * * The Dynamical Occupancy correction will be performed in * Crystal::GetScatteringComponentList() automatically. * * This \e seriously affects the speed of the calculation, since computing * interatomic distances is lenghty. * \param use set to 1 to use, 0 not to use it. */ void SetUseDynPopCorr(const int use); /** Get dynamical population correction setting. * See SetUseDynPopCorr. */ int GetUseDynPopCorr() const; /** Get the Anti-bumping/pro-Merging cost function. Only works (ie returnes a non-null * value) if you have added antibump distances using Crystal::SetBumpMergeDistance(). * */ REAL GetBumpMergeCost() const; /** Set the Anti-bumping distance between two scattering types * */ void SetBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2, const REAL dist=1.5); /// Set the Anti-bumping distance between two scattering types. void SetBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2, const REAL dist, const bool allowMerge); /// Remove an Anti-bumping distance between two scattering types. void RemoveBumpMergeDistance(const ScatteringPower &scatt1, const ScatteringPower &scatt2); /// Storage for anti-bump/merge parameters struct BumpMergePar { BumpMergePar(); /** Constructor * * \param dist: the bump/merge distance in Angstroems */ BumpMergePar(const REAL dist, const bool canOverlap=false); /// The squared antibump interatomic distance REAL mDist2; /// Can the two atoms completely overlap ? bool mCanOverlap; }; /// Anti-bump parameters. Each atom type (ScatteringPower is referenced /// using a reference number) typedef std::map,Crystal::BumpMergePar > VBumpMergePar; const VBumpMergePar& GetBumpMergeParList()const; VBumpMergePar& GetBumpMergeParList(); /// When was the list of scatterers last changed ? const RefinableObjClock& GetClockScattererList()const; virtual void XMLOutput(ostream &os,int indent=0)const; /** \brief Input the crystal structure from a stream. * * This will destroy any Scatterer of ScatteringPower if * mDeleteSubObjInDestructor is true. Otherwise they will just * be de-registered and should be deleted somewhere else, * but there is a special hook implemented where any * previously existing ScatteringPowerAtom will be re-used if * equivalent to the one in the input. */ virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); virtual REAL GetLogLikelihood()const; /** \brief output Crystal structure as a cif file * \param mindist : minimum distance between atoms to consider them * overlapping. Overlapping atoms are only included as comments in the * CIF file. * */ virtual void CIFOutput(ostream &os, double mindist = 0.5)const; virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); void AddBondValenceRo(const ScatteringPower&,const ScatteringPower&,const REAL ro); void RemoveBondValenceRo(const ScatteringPower&,const ScatteringPower&); /** Get the Bond-Valence cost function, which compares the expected valence * to the one computed from Bond-Valence Ro parameters. */ REAL GetBondValenceCost() const; std::map, REAL>& GetBondValenceRoList(); const std::map, REAL>& GetBondValenceRoList()const; /** \brief Init all Crystal parameters * \param a,b,c : unit cell dimension, in angstroems * \param alpha,beta,gamma : unit cell angles * \param SpcGroup: space group number (1..230) * \param name: name for the crystal, : '(TaSe4)2I' */ void Init(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId, const string& name); /** Set whether to delete the Scatterers and ScatteringPowers in the * destructor. By default these sub-objects are deleted. */ void SetDeleteSubObjInDestructor(const bool b); /** Convert as much as possible the crystal's atoms to molecule(s). * * \param min_relat_dist, max_relat_dist: this compares all interatomic distances with the sum of atomic covalent radii d_cov, *if d_cov*min_relat_dist < d < d_cov*max_relat_dist, the atoms are assumed to be connected by a bond. * This function only works if the Crystal contains only atoms. * \param warnuser_fail: if true, will pass a message to the end user that auto-creating at least one Molecule failed. * \warning: experimental, unstable */ void ConnectAtoms(const REAL min_relat_dist=0.4, const REAL max_relat_dist=1.3, const bool warnuser_fail=false); /** Merge all equal scattering powers * * \param oneScatteringPowerPerElement: if true, all scattering powers corresponding to the same elemnt of the periodic * classification will be merged into one, with the averaged isotropic Debye-Waller factor. Otherwise, the scattering * powers will be merged only if the Debye Waller factors (isotropic and anisotropic, if any) are identical. * * \warning: this currently only works if the Crystal is only made of Atoms and ScatteringPowerAtoms (it is used at the end * of a CIF import). */ void MergeEqualScatteringPowers(const bool oneScatteringPowerPerElement); private: /** Init options. * * Need only be done once per Crystal. */ void InitOptions(); /// Find a scatterer (its index # in mpScatterrer[]) with a given name /// \warning There should be no duplicate names !!! :TODO: test in AddScatterer() int FindScatterer(const string &scattName)const; /** \internal \brief Compute the distance Table (mDistTable) for all scattering components * \param fast : if true, the distance calculations will be made using * integers, thus with a lower precision but faster. Less atoms will also * be involved (using the AsymmetricUnit and mDistTableMaxDistance2) to make it even faster. * * \warning Crystal::GetScatteringComponentList() \b must be called beforehand, * since this will not be done here. * * \return see Crystal::mDistTableSq and Crystal::mDistTableIndex * \todo sanitize the result distance table in a more usable structure than the currently * used Crystal::mDistTableSq and Crystal::mDistTableIndex. * \warning \e not using the fast option has not been very much tested... * \todo optimize again. Test if recomputation is needed using Clocks. * Use a global option instead of asymUnitMargin. */ void CalcDistTable(const bool fast)const; /** Calculate all Bond Valences. * */ void CalcBondValenceSum()const; /// The registry of scatterers for this UnitCell ObjRegistry mScattererRegistry ; /// Anti-bump parameters map VBumpMergePar mvBumpMergePar; /// Last Time Anti-bump parameters were changed RefinableObjClock mBumpMergeParClock; /// Last Time Anti-bump parameters were changed mutable RefinableObjClock mBumpMergeCostClock; /// Current bump-merge cost mutable REAL mBumpMergeCost; /// Bump-merge scale factor REAL mBumpMergeScale; /// Interatomic distance for a given neighbour struct Neighbour { Neighbour(const unsigned long neighbourIndex,const int sym, const REAL dist2); /// The number associated to the neighbour /// (its index in the Crystal's scattering component list) unsigned long mNeighbourIndex; /// The symmetry position associated to the neighbour /// (its index in the Crystal's scattering component list) unsigned int mNeighbourSymmetryIndex; /// The squared distance, in square Angstroems REAL mDist2; }; /// Table of neighbours for a given unique atom struct NeighbourHood { /// Index of the atom in the scattering component list unsigned long mIndex; /// Index of the symmetry operation for the chosen unique position in the /// (pseudo) asymmetric unit unsigned int mUniquePosSymmetryIndex; /// List of neighbours std::vector mvNeighbour; }; /** Interatomic distance table for all unique atoms * */ mutable std::vector mvDistTableSq; /// The time when the distance table was last calculated mutable RefinableObjClock mDistTableClock; /// The distance up to which the distance table & neighbours needs to be calculated mutable REAL mDistTableMaxDistance; /// The list of all scattering components in the crystal mutable ScatteringComponentList mScattCompList; /// Clock for lattice paramaters. RefinableObjClock mLatticeClock; /// Use Dynamical population correction (ScatteringComponent::mDynPopCorr) during Structure /// factor calculation ? RefObjOpt mUseDynPopCorr; /// The registry of ScatteringPower for this Crystal. ObjRegistry mScatteringPowerRegistry; //Clocks /// Last time the list of Scatterers was changed RefinableObjClock mClockScattererList; /// \internal Last time the ScatteringComponentList was generated mutable RefinableObjClock mClockScattCompList; /// \internal Last time the Neighbor Table was generated mutable RefinableObjClock mClockNeighborTable; /// \internal Last time the dynamical population correction was computed mutable RefinableObjClock mClockDynPopCorr; /// master clock recording every change in Scattering Powers RefinableObjClock mMasterClockScatteringPower; /// Display the enantiomeric (mirror along x) structure in 3D? This can /// be helpful for non-centrosymmetric structure which have been solved using /// powder diffraction (which only gives the relative configuration). RefObjOpt mDisplayEnantiomer; /** Map of Bond Valence "Ro" parameters for each couple of * ScatteringPower */ map, REAL> mvBondValenceRo; /// Last Time Bond Valence parameters were changed RefinableObjClock mBondValenceParClock; /// Last time Bond Valences were calculated mutable RefinableObjClock mBondValenceCalcClock; /// Last time the Bond Valence cost was calculated mutable RefinableObjClock mBondValenceCostClock; /// Current Bond Valence cost mutable REAL mBondValenceCost; /// Bond Valence cost scale factor REAL mBondValenceCostScale; /// List of calculated bond valences, as a map, the key being the index /// of the atom in Crystal::mScattCompList. mutable std::map mvBondValenceCalc; // Flag indicating whether to delete Scatterers and ScatteringPowers in // the destructor (default true). Modified by // SetDeleteSubObjInDestructor. bool mDeleteSubObjInDestructor; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXCrystal; #endif }; /// Global registry for all Crystal objects extern ObjRegistry gCrystalRegistry; }// namespace #endif //_OBJCRYST_CRYSTAL_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/DiffractionDataSingleCrystal.cpp000066400000000000000000001244711417150057700273070ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for ObjCryst++ DiffractionData class * */ //#include #include #include #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" #include "ObjCryst/ObjCryst/CIF.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxDiffractionSingleCrystal.h" #endif #include #include #include //for sprintf() //#include #ifdef _MSC_VER // MS VC++ predefined macros.... #undef min #undef max #endif namespace ObjCryst { //###################################################################### // DiffractionDataSingleCrystal //###################################################################### ObjRegistry gDiffractionDataSingleCrystalRegistry("Global DiffractionDataSingleCrystal Registry"); DiffractionDataSingleCrystal::DiffractionDataSingleCrystal(const bool regist): mHasObservedData(false),mScaleFactor(1.) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::DiffractionDataSingleCrystal()",5) this->InitRefParList(); this->InitOptions(); if(regist) gDiffractionDataSingleCrystalRegistry.Register(*this); if(regist) gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mClockScaleFactor); this->AddSubRefObj(mRadiation); } DiffractionDataSingleCrystal::DiffractionDataSingleCrystal(Crystal &cryst,const bool regist): mHasObservedData(false),mScaleFactor(1.) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::DiffractionDataSingleCrystal()",5) this->InitRefParList(); this->SetCrystal(cryst); this->InitOptions(); if(regist) gDiffractionDataSingleCrystalRegistry.Register(*this); if(regist) gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mClockScaleFactor); this->AddSubRefObj(mRadiation); } DiffractionDataSingleCrystal::DiffractionDataSingleCrystal(const DiffractionDataSingleCrystal &old): ScatteringData(old), mHasObservedData(old.mHasObservedData),mRadiation(old.mRadiation) { mObsIntensity=old.mObsIntensity; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); mObsSigma=old.mObsSigma; mWeight=old.mWeight; mCalcIntensity=old.mCalcIntensity; mScaleFactor=old.mScaleFactor; this->InitOptions(); mGroupOption.SetChoice(old.mGroupOption.GetChoice()); gDiffractionDataSingleCrystalRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mClockScaleFactor); this->AddSubRefObj(mRadiation); } DiffractionDataSingleCrystal::~DiffractionDataSingleCrystal() { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::~DiffractionDataSingleCrystal()",5) gDiffractionDataSingleCrystalRegistry.DeRegister(*this); gTopRefinableObjRegistry.DeRegister(*this); } DiffractionDataSingleCrystal* DiffractionDataSingleCrystal::CreateCopy()const { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::CreateCopy()",5) return new DiffractionDataSingleCrystal(*this); } const string& DiffractionDataSingleCrystal::GetClassName() const { const static string className="DiffractionDataSingleCrystal"; return className; } void DiffractionDataSingleCrystal::SetHklIobs(const CrystVector_long &h, const CrystVector_long &k, const CrystVector_long &l, const CrystVector_REAL &iObs, const CrystVector_REAL &sigma) { VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::SetHklIobs(h,k,l,i,s)",5) mNbRefl=h.numElements(); mH.resize(mNbRefl); mK.resize(mNbRefl); mL.resize(mNbRefl); mObsIntensity.resize(mNbRefl); mObsSigma.resize(mNbRefl); mWeight.resize(mNbRefl); mMultiplicity.resize(mNbRefl); mH=h; mK=k; mL=l; mObsIntensity=iObs; mObsSigma=sigma; mMultiplicity=1; this->PrepareHKLarrays(); this->CalcSinThetaLambda(); this->SortReflectionBySinThetaOverLambda(); this->SetWeightToInvSigma2(1e-4,0); mHasObservedData=true; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); /*{ char buf [200]; sprintf(buf,"Changed HKL list, with %d reflections",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); }*/ VFN_DEBUG_EXIT("DiffractionDataSingleCrystal::SetHklIobs(h,k,l,i,s)",5) } const CrystVector_REAL& DiffractionDataSingleCrystal::GetIcalc()const { this->CalcIcalc(); return mCalcIntensity; } std::map & DiffractionDataSingleCrystal::GetIcalc_FullDeriv(std::set &vPar) { this->CalcIcalc_FullDeriv(vPar); return mCalcIntensity_FullDeriv; } const CrystVector_REAL& DiffractionDataSingleCrystal::GetIobs()const { //if(mHasObservedData==false) DoSomething return mObsIntensity; } void DiffractionDataSingleCrystal::SetIobs(const CrystVector_REAL &obs) { mObsIntensity=obs; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); } const CrystVector_REAL& DiffractionDataSingleCrystal::GetSigma()const { //if(mHasObservedData=false) DoSomething return mObsSigma; } void DiffractionDataSingleCrystal::SetSigma(const CrystVector_REAL& sigma) {mObsSigma=sigma;} const CrystVector_REAL& DiffractionDataSingleCrystal::GetWeight()const { //if(mHasObservedData=false) DoSomething return mWeight; } void DiffractionDataSingleCrystal::SetWeight(const CrystVector_REAL& weight) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SetWeight(w)",5) mWeight=weight; mClockMaster.Click(); } void DiffractionDataSingleCrystal::SetIobsToIcalc() { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SetIobsToIcalc()",5) mObsIntensity=this->GetIcalc(); mObsSigma.resize(mNbRefl); mWeight.resize(mNbRefl); mWeight=1; mObsSigma=0; mHasObservedData=true; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); mClockMaster.Click(); } void DiffractionDataSingleCrystal::ImportHklIobs(const string &fileName, const long nbRefl, const int skipLines) { //configure members mNbRefl=nbRefl; mH.resize(mNbRefl); mK.resize(mNbRefl); mL.resize(mNbRefl); mObsIntensity.resize(mNbRefl); mObsSigma.resize(mNbRefl); //Import data { //:TODO: Skip the lines if required !!! cout << "inputing reflections from file : "+fileName<> mH(i); fin >> mK(i); fin >> mL(i); fin >> mObsIntensity(i); mObsSigma(i)=sqrt(fabs(mObsIntensity(i))); //cout << mObsIntensity(i) <"<< endl; fin.close(); } //Finish mWeight.resize(mNbRefl); const REAL minIobs=mObsIntensity.max()*1e-6; for(int i=0;iPrepareHKLarrays(); this->SortReflectionBySinThetaOverLambda(); { char buf [200]; sprintf(buf,"Imported HKLIobs, with %d reflections",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); } cout << "Finished storing data..."<< endl ; } void DiffractionDataSingleCrystal::ImportHklIobsSigma(const string &fileName, const long nbRefl, const int skipLines) { //configure members mNbRefl=nbRefl; mH.resize(mNbRefl); mK.resize(mNbRefl); mL.resize(mNbRefl); mObsIntensity.resize(mNbRefl); mObsSigma.resize(mNbRefl); //Import data { cout << "inputing reflections from file : "+fileName<0) {//Get rid of first lines if required char tmpComment[200]; for(int i=0;i> mH(i); fin >> mK(i); fin >> mL(i); fin >> mObsIntensity(i); fin >> mObsSigma(i); //cout << mH(i)<<" "<"<< endl; fin.close(); } //Finish mWeight.resize(mNbRefl); this->SetWeightToInvSigma2(1e-4,0); mHasObservedData=true; mMultiplicity.resize(mNbRefl); mMultiplicity=1; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); this->PrepareHKLarrays(); this->SortReflectionBySinThetaOverLambda(); { char buf [200]; sprintf(buf,"Imported HKLIobsSigma, with %d reflections",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); } cout << "Finished storing data..."<< endl ; } void DiffractionDataSingleCrystal::ImportShelxHKLF4(const string &fileName) { VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::ImportShelxHKLF4():"<SetWeightToInvSigma2(1e-4,0); mHasObservedData=true; mMultiplicity.resize(mNbRefl); mMultiplicity=1; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); this->PrepareHKLarrays(); this->SortReflectionBySinThetaOverLambda(); { char buf [200]; sprintf(buf,"Imported Shelx HKLF 4 file, with %d reflections",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_EXIT("DiffractionDataSingleCrystal::ImportShelxHKLF4() read "<::iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos) { if(pos->second.mH.numElements()>0) { this->SetHklIobs(pos->second.mH,pos->second.mK,pos->second.mL,pos->second.mIobs,pos->second.mSigma); break; } } VFN_DEBUG_EXIT("DiffractionDataSingleCrystal::ImportCIF() read "<> tmpH; while(tmpH != 999) { // :TODO: A little faster.... //:TODO: Check for the end of the stream if(!fin.good()) {throw...} i++; if(i>=mNbRefl) { cout << mNbRefl << " reflections imported..." << endl; mNbRefl+=1000; mH.resizeAndPreserve(mNbRefl); mK.resizeAndPreserve(mNbRefl); mL.resizeAndPreserve(mNbRefl); mObsIntensity.resizeAndPreserve(mNbRefl); mObsSigma.resizeAndPreserve(mNbRefl); } mH(i)=tmpH; fin >> mK(i); fin >> mL(i); fin >> mObsIntensity(i); fin >> mObsSigma(i); fin >> junk; fin >> junk; fin >> junk; fin >> junk; fin >> tmpH; } fin.close(); mNbRefl=i; cout << mNbRefl << " reflections imported." << endl; mH.resizeAndPreserve(mNbRefl); mK.resizeAndPreserve(mNbRefl); mL.resizeAndPreserve(mNbRefl); mObsIntensity.resizeAndPreserve(mNbRefl); mObsSigma.resizeAndPreserve(mNbRefl); } //Finish mWeight.resize(mNbRefl); mWeight=1; mMultiplicity.resize(mNbRefl); mMultiplicity=1; // Keep a copy as squared F(hkl), to enable fourier maps // :TODO: stop using mObsIntensity and just keep mFhklObsSq ? mFhklObsSq=mObsIntensity; mClockFhklObsSq.Click(); this->PrepareHKLarrays(); this->SortReflectionBySinThetaOverLambda(); cout << "Finished storing data..."<< endl ; mHasObservedData=true; { char buf [200]; sprintf(buf,"Imported HKLIobsSigma from Jana, with %d reflections",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); } } void DiffractionDataSingleCrystal::ImportHklIobsGroup(const string &fileName,const unsigned int skipLines) { //configure members mNbRefl=0; mNbGroup=0; mH.resize(500); mK.resize(500); mL.resize(500); mObsIntensity.resize(500); mObsSigma.resize(500); mGroupIndex.resize(500); mGroupIobs.resize(500); mGroupSigma.resize(500); mGroupWeight.resize(500); //Import data { //:TODO: Skip the lines if required !!! cout << "inputing reflections from file : "+fileName<> h >> k >> l) ? 3 : 0; nn += bool(linestream >> iobs); nn += bool(linestream >> sigma); const int n = nn; if(n<3) break; mH(mNbRefl)=h; mK(mNbRefl)=k; mL(mNbRefl)=l; mGroupIndex(mNbRefl)=mNbGroup; //cout<SortReflectionBySinThetaOverLambda(); this->CalcIcalc(); } REAL DiffractionDataSingleCrystal::GetRw()const { TAU_PROFILE("DiffractionData::Rw()"," REAL()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("DiffractionData::Rw()",3); if(mHasObservedData==false) { return 0; } REAL tmp1=0; REAL tmp2=0; const REAL *p1; const REAL *p2; const REAL *p3; long nb; if(mGroupOption.GetChoice()==0) { p1=mCalcIntensity.data(); p2=mObsIntensity.data(); p3=mWeight.data(); nb=mNbReflUsed; } else { p1=mGroupIcalc.data(); p2=mGroupIobs.data(); p3=mGroupWeight.data(); nb=mGroupIobs.numElements(); } for(long i=nb;i>0;i--) { tmp1 += *p3 * ( *p1 - *p2) * ( *p1 - *p2); tmp2 += *p3 * *p2 * *p2; p1++;p2++;p3++; } tmp1=sqrt(tmp1/tmp2); VFN_DEBUG_MESSAGE("DiffractionData::Rw()="<GetNbRefl(); } REAL DiffractionDataSingleCrystal::GetR()const { TAU_PROFILE("DiffractionData::R()"," REAL()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("DiffractionData::R()",3); if(mHasObservedData==false) { return 0; } REAL tmp1=0; REAL tmp2=0; const REAL *p1; const REAL *p2; long nb; if(mGroupOption.GetChoice()==0) { p1=mCalcIntensity.data(); p2=mObsIntensity.data(); nb=mNbReflUsed; } else { p1=mGroupIcalc.data(); p2=mGroupIobs.data(); nb=mGroupIobs.numElements(); } for(long i=nb;i>0;i--) { tmp1 += ( *p1 - *p2) * ( *p1 - *p2); tmp2 += *p2 * *p2; p1++;p2++; } tmp1=sqrt(tmp1/tmp2); VFN_DEBUG_MESSAGE("DiffractionData::R()="<GetNbReflBelowMaxSinThetaOvLambda(); if(mClockChi2>mClockMaster) return mChi2; this->CalcIcalc(); if(mClockChi2>mClockIcalc) return mChi2; TAU_PROFILE("DiffractionData::Chi2()"," REAL()",TAU_DEFAULT); VFN_DEBUG_ENTRY("DiffractionData::Chi2()",3); this->FitScaleFactorForRw(); mChi2=0; const REAL *p1; const REAL *p2; const REAL *p3; long nb; if(mGroupOption.GetChoice()==0) { p1=mCalcIntensity.data(); p2=mObsIntensity.data(); p3=mWeight.data(); nb=mNbReflUsed; } else { p1=mGroupIcalc.data(); p2=mGroupIobs.data(); p3=mGroupWeight.data(); nb=mGroupIobs.numElements(); } for(long i=nb;i>0;i--) { mChi2 += *p3++ * ( *p1 - *p2) * ( *p1 - *p2); p1++;p2++; } /* // SSE code gives about 30% faster code on P3 (tested with 10000 reflections), // but scarcely any improvement on athlon-xp union sse4f { __m128 m128; struct { float x, y, z, w; }; } ; const long nb=mNbReflUsed/4; const float* p1=mCalcIntensity.data(); const float* p2=mObsIntensity.data(); const float* p3=mWeight.data(); for(long i=0;i0;i--) { tmp1 += *p3 * (*p1) * (*p2++); tmp2 += *p3++ * (*p1) * (*p1); p1++; } mScaleFactor *= tmp1/tmp2; mClockScaleFactor.Click(); mCalcIntensity *= tmp1/tmp2; if(0!=mGroupOption.GetChoice()) mGroupIcalc*= tmp1/tmp2; mClockIcalc.Click(); } void DiffractionDataSingleCrystal::FitScaleFactorForR() const { TAU_PROFILE("DiffractionData::FitScaleFactorForR()","void ()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("DiffractionData::FitScaleFactorForR()",3); if(mHasObservedData==false) {//throw exception here ? return; //throw ObjCrystException("DiffractionData::FitScaleFactorForR() Cannot compute R // or scale factor: there is no observed data !"); } REAL tmp1=0; REAL tmp2=0; const REAL *p1; const REAL *p2; long nb; if(mGroupOption.GetChoice()==0) { p1=mCalcIntensity.data(); p2=mObsIntensity.data(); nb=mNbReflUsed; } else { p1=mGroupIcalc.data(); p2=mGroupIobs.data(); nb=mGroupIobs.numElements(); } for(long i=nb;i>0;i--) { tmp1 += (*p1) * (*p2++); tmp2 += (*p1) * (*p1); p1++; } mScaleFactor *= tmp1/tmp2; mClockScaleFactor.Click(); mCalcIntensity *= tmp1/tmp2; if(0!=mGroupOption.GetChoice()) mGroupIcalc*= tmp1/tmp2; mClockIcalc.Click(); } REAL DiffractionDataSingleCrystal::GetBestRFactor() const { TAU_PROFILE("DiffractionData::GetBestRFactor()","void ()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("DiffractionData::GetBestRFactor()",3); this->FitScaleFactorForR(); return this->GetR(); } void DiffractionDataSingleCrystal::SetSigmaToSqrtIobs() { for(long i=0;iCalcSinThetaLambda(); cout << "DiffractionData : " << mName < (mH,mK,mL,mObsIntensity,mObsSigma,mSinThetaLambda,12,4); } void DiffractionDataSingleCrystal::PrintObsCalcData()const { this->CalcIcalc(); CrystVector_REAL tmpTheta=mTheta; tmpTheta*= RAD2DEG; /* CrystVector_REAL tmp=mObsIntensity; CrystVector_REAL tmpS=mObsSigma; if(true==mHasObservedData) { cout << "Scale factor : " << mScaleFactor <(mH,mK,mL, mObsIntensity,mObsSigma,mCalcIntensity, mMultiplicity,tmpTheta,mSinThetaLambda, mFhklCalcReal,mFhklCalcImag,mWeight,12,4); } void DiffractionDataSingleCrystal::SetUseOnlyLowAngleData( const bool useOnlyLowAngle,const REAL angle) { throw ObjCrystException("DiffractionDataSingleCrystal::SetUseOnlyLowAngleData() :\ not yet implemented for DiffractionDataSingleCrystal."); } void DiffractionDataSingleCrystal::SaveHKLIobsIcalc(const string &filename) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SaveHKLIobsIcalc",5) this->GetIcalc(); ofstream out(filename.c_str()); CrystVector_REAL theta; theta=mTheta; theta *= RAD2DEG; if(false == mHasObservedData) { out << "# H K L Icalc theta sin(theta)/lambda" <<" Re(F) Im(F)" << endl; out << FormatVertVectorHKLFloats(mH,mK,mL,mCalcIntensity, theta,mSinThetaLambda,mFhklCalcReal,mFhklCalcImag,12,4); } else { out << "# H K L Iobs Icalc theta" <<" sin(theta)/lambda Re(F) Im(F)" << endl; out << FormatVertVectorHKLFloats(mH,mK,mL,mObsIntensity,mCalcIntensity, theta,mSinThetaLambda,mFhklCalcReal,mFhklCalcImag,12,4); } out.close(); VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SaveHKLIobsIcalc:End",3) } void DiffractionDataSingleCrystal::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type); //this->FitScaleFactorForRw(); } REAL DiffractionDataSingleCrystal::GetLogLikelihood()const { return this->GetChi2(); } void DiffractionDataSingleCrystal::InitRefParList() { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::InitRefParList()",5) RefinablePar tmp("Scale factor",&mScaleFactor, 1e-10,1e10,gpRefParTypeScattDataScale,REFPAR_DERIV_STEP_RELATIVE, false,true,true,false,1.); tmp.SetGlobalOptimStep(0.); tmp.AssignClock(mClockScaleFactor); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } unsigned int DiffractionDataSingleCrystal::GetNbLSQFunction()const{return 1;} const CrystVector_REAL& DiffractionDataSingleCrystal::GetLSQCalc(const unsigned int) const {return this->GetIcalc();} const CrystVector_REAL& DiffractionDataSingleCrystal::GetLSQObs(const unsigned int) const {return this->GetIobs();} const CrystVector_REAL& DiffractionDataSingleCrystal::GetLSQWeight(const unsigned int) const {return this->GetWeight();} std::map & DiffractionDataSingleCrystal::GetLSQ_FullDeriv(const unsigned int,std::set &vPar) { #if 0 this->GetIcalc_FullDeriv(vPar); std::map fullderiv_old; std::vector v; int n=0; for(std::map::reverse_iterator pos=mCalcIntensity_FullDeriv.rbegin();pos!=mCalcIntensity_FullDeriv.rend();++pos) { v.push_back(&(pos->second)); fullderiv_old[pos->first]=this->GetLSQDeriv(0,*(pos->first)); v.push_back(&(fullderiv_old[pos->first])); cout<first->GetName()<<":"<second.size()<<","<first].size()<8) break; } cout<(v,10)<GetIcalc_FullDeriv(vPar); } const Radiation& DiffractionDataSingleCrystal::GetRadiation()const { return mRadiation;} Radiation& DiffractionDataSingleCrystal::GetRadiation() { return mRadiation;} void DiffractionDataSingleCrystal::SetRadiationType(const RadiationType radiation) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SetRadiationType():End",5) mRadiation.SetRadiationType(radiation); } void DiffractionDataSingleCrystal::SetWavelength(const REAL lambda) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SetWavelength() to "<GetRadiation().SetWavelength(lambda); } void DiffractionDataSingleCrystal::SetWavelength(const string &XRayTubeElementName, const REAL alpha2Alpha2ratio) { VFN_DEBUG_MESSAGE("DiffractionDataSingleCrystal::SetWavelength() to "<GetRadiation().SetWavelength(XRayTubeElementName,alpha2Alpha2ratio); } void DiffractionDataSingleCrystal::SetEnergy(const REAL energy) { this->SetWavelength(12398.4/energy); } void DiffractionDataSingleCrystal::CalcIcalc() const { TAU_PROFILE("DiffractionData::CalcIcalc()","void ()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("DiffractionData::CalcIcalc():"<GetName(),3) this->GetFhklCalcSq(); if( (mClockStructFactorSqPrepareTwinningCalc(); mGroupIcalc.resize(mNbGroup); mGroupIcalc=0; long first=0; for(long i=0;i"< Icalc="<< mGroupIcalc(i) <<" , Iobs="<< mGroupIobs(i)< &vPar) { TAU_PROFILE("DiffractionDataSingleCrystal::CalcIcalc_FullDeriv()","void ()",TAU_DEFAULT); this->GetFhklCalcSq_FullDeriv(vPar); // :TODO: instead of clear(), only add/remove when necessary ? mCalcIntensity_FullDeriv.clear(); mCalcIntensity_FullDeriv=mFhklCalcSq_FullDeriv; //:TODO: multiplication only up to mNbReflUsed for(std::map::iterator pos=mCalcIntensity_FullDeriv.begin(); pos!=mCalcIntensity_FullDeriv.end();pos++) { if(pos->first==0) {// This is Icalc, not derived pos->second *=mScaleFactor; continue; } if(pos->first->GetPointer()!=&mScaleFactor) { /*if(pos->second.size()>0) */ // not needed pos->second *=mScaleFactor; } else { pos->second=mFhklCalcSq; } } if(0!=mGroupOption.GetChoice()) {//:TODO: if(1==mGroupOption.GetChoice()) this->PrepareTwinningCalc(); // :TODO: instead of clear(), only add/remove when necessary ? mGroupIcalc_FullDeriv.clear(); for(std::map::iterator pos=mCalcIntensity_FullDeriv.begin(); pos!=mCalcIntensity_FullDeriv.end();pos++) { mGroupIcalc_FullDeriv[pos->first].resize(mNbGroup); mGroupIcalc_FullDeriv[pos->first]=0; long first=0; for(long i=0;ifirst](i)+=mCalcIntensity_FullDeriv[pos->first](j); } first=mGroupIndex(i); } } } } CrystVector_long DiffractionDataSingleCrystal::SortReflectionBySinThetaOverLambda(const REAL maxSTOL) { TAU_PROFILE("DiffractionDataSingleCrystal::SortReflectionBySinThetaOverLambda()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::SortReflectionBySinThetaOverLambda()",5) // ScatteringData::SortReflectionBySinThetaOverLambda only sorts H,K,L and multiplicity. CrystVector_long index=this->ScatteringData::SortReflectionBySinThetaOverLambda(maxSTOL); if(mObsIntensity.numElements()==mNbRefl) { CrystVector_REAL tmpObs,tmpSigma,tmpWeight; tmpObs=mObsIntensity; tmpSigma=mObsSigma; tmpWeight=mWeight; for(long i=0;i"<PrepareHKLarrays(); this->CalcSinThetaLambda(); } // re-write mGroupIndex so that it marks the // last reflection of each group. index=mGroupIndex; mGroupIndex.resize(mNbGroup); long group=0; for(long i=0;iAddOption(&mGroupOption); } void DiffractionDataSingleCrystal::PrepareTwinningCalc() const { if(mClockPrepareTwinningCorr>mClockHKL) return; VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::PrepareTwinningCalc()",5) // first get the index of reflections which limit each block of summed reflections mNbGroup=0; { const REAL dSiThOvLa=.0001; mGroupIndex.resize(mNbReflUsed); this->CalcSinThetaLambda(); REAL sithol0=mSinThetaLambda(0)+dSiThOvLa; for(long i=1;isithol0) { mGroupIndex(mNbGroup++)=i; sithol0=mSinThetaLambda(i)+dSiThOvLa; } } mGroupIndex(mNbGroup++)=mNbReflUsed; mGroupIndex.resizeAndPreserve(mNbGroup); } // Calculate summed Iobs and weight { mGroupIobs.resize(mNbGroup); mGroupIobs=0; mGroupWeight.resize(mNbGroup); mGroupWeight=0; mGroupSigma.resize(mNbGroup); mGroupSigma=0; long first=0; for(long i=0;i #include //#include //#include //#include //#include //#include namespace ObjCryst { //###################################################################### // DiffractionDataSingleCrystal /** * \brief DiffractionData object for Single Crystal analysis. * * Currently this handles only in the simplest way single crystal dat: ie * only data which has been completely corrected for Lorentz/Polarization * and absorption. * * What needs to be developped: define the geometry of the experiment * (incident and emerging angles), the polarization of the beam, etc... */ //###################################################################### class DiffractionDataSingleCrystal:public ScatteringData { public: /** Default constructor * * \param regist: if false, do not add to the global registry of * single crystal data or refinable objects - this is only useful * for data to be used internally only. * * \deprecated Use the constructor passing a crystal structure instead. */ DiffractionDataSingleCrystal(const bool regist=true); /** Constructor, with an assigned crystal structure. * * \param regist: if false, do not add to the global registry of * single crystal data or refinable objects - this is only useful * for data to be used internally only. */ DiffractionDataSingleCrystal(Crystal &cryst,const bool regist=true); /// Copy constructor DiffractionDataSingleCrystal(const DiffractionDataSingleCrystal &old); ~DiffractionDataSingleCrystal(); virtual DiffractionDataSingleCrystal* CreateCopy()const; virtual const string& GetClassName() const; /** \brief returns the calculated diffracted intensity. * * This is an array of calculated intensities for each reflections in the * single crystal case, and the array with the full powder powder profile * for powder diffraction. */ const CrystVector_REAL& GetIcalc() const; /// \todo std::map & GetIcalc_FullDeriv(std::set &vPar); /// Return the array of observed intensities for all peaks const CrystVector_REAL& GetIobs() const; /// Return the array of observed intensities for all peaks void SetIobs(const CrystVector_REAL&); /// Return the array of sigmas for observed intensities, for all peaks. const CrystVector_REAL& GetSigma() const; /// Return the array of sigmas for observed intensities, for all peaks. void SetSigma(const CrystVector_REAL&); /// Set Iobs to current values of Icalc. Mostly used for tests. void SetIobsToIcalc(); /// Return the weights (for each reflection) used for computing Rw. const CrystVector_REAL& GetWeight() const; /// Change the weights (for each reflection) used for computing Rw. void SetWeight(const CrystVector_REAL&); /** \brief input H,K,L, Iobs and Sigma * * \param h,k,l: REAL arrays (vectors with NbRefl elements -same size) *with the h, k and l coordinates of all reflections. * \param iobs,sigma: REAL arrays (vectors with NbRefl elements -same size) *with the Observed intensity and sigma for all reflections. * */ void SetHklIobs(const CrystVector_long &h, const CrystVector_long &k, const CrystVector_long &l, const CrystVector_REAL &iObs, const CrystVector_REAL &sigma); /** \brief Import h,k,l,I from a file * *The file is assumed to correspond to a single crystal diffraction file. * \param fileName The name of the data file. This file should be formatted *with H,k,l, Iobs separated by spaces. * \param nbRefl The number of reflections to extract. * \param skipLines The number of lines to skip at the beginning of the file. */ void ImportHklIobs(const string &fileName,const long nbRefl,const int skipLines=0); /** \brief Import h,k,l,I,Sigma from a file * *The file is assumed to correspond to a single crystal diffraction file. * \param fileName The name of the data file. This file should be formatted *with H,k,l, Iobs and Sigma separated by spaces. * \param nbRefl The number of reflections to extract. * \param skipLines The number of lines to skip at the beginning of the file. */ void ImportHklIobsSigma(const string &fileName,const long nbRefl,const int skipLines=0); /** \brief Import h,k,l,I,Sigma from a file using shelx HKLF 4 format * *The file is assumed to correspond to a single crystal diffraction file.This file * should be formatted with H,k,l, Iobs and Sigma using a strict formatting 3I4+2F8, * and the last line should contain 0 0 0 for hkl values. * \param fileName The name of the data file. */ void ImportShelxHKLF4(const string &fileName); /** \brief Import diffraction data from a CIF file * *The file is assumed to correspond to a single crystal diffraction file. * \param fileName The name of the data file. */ void ImportCIF(const string &fileName); /** \brief Import h,k,l,I,Sigma from a Jana98 '*.m91' file * *The file is assumed to correspond to a single crystal diffraction file. * \param fileName The name of the data file. */ void ImportHklIobsSigmaJanaM91(const string &fileName); /** \brief Import h,k,l and grouped intensities from a file * *The file is assumed to correspond to a single crystal diffraction file. * \param fileName The name of the data file. This file should be formatted *with H,k,l, Iobs separated by spaces. * \param skipLines The number of lines to skip at the beginning of the file. * * File format (the reflection which has an intensity entry marks the end of the group) * h k l Igroup * -2 4 2 * -2 -4 2 100.4 * 2 -4 1 * 2 4 1 193.2 * ... */ void ImportHklIobsGroup(const string &fileName,const unsigned int skipLines=0); /** \brief Return the Crystal R-factor (weighted) * * \return \f$ R_{w}= \sqrt {\frac{\sum_i w_i\left( I_i^{obs}-I_i^{calc} \right)^2} * {\sum_i w_i (I_i^{obs})^2} }\f$ */ virtual REAL GetRw()const; /** \brief Return the Crystal R-factor (unweighted) * * \return \f$ R= \sqrt {\frac{\sum_i \left( I_i^{obs}-I_i^{calc} \right)^2} * {\sum_i (I_i^{obs})^2} }\f$ */ virtual REAL GetR()const; /** \brief Return conventionnal Chi^2 * \return \f$ \chi^2 = \sum_i w_i \left(I_i^{obs}-I_i^{calc} \right)^2 * \f$ */ // \return \f$ \chi^2 = \sum_i \left( \frac{ y_i^{obs}-y_i^{calc}}{\sigma_i} \right)^2 virtual REAL GetChi2()const; /* \brief Return Goodness of Fit * * \return \f$ GoF = \frac{\sum_i w_i\left( y_i^{obs}-y_i^{calc} \right)^2} * {N_{obs}-N_{indep.par}} \f$ virtual REAL GoF()const; */ /** Compute the best scale factor minimising Rw. * * The computed scale factor is \e immediatly applied to Icalc */ virtual void FitScaleFactorForRw() const; /** Compute the best scale factor minimising R. * * The computed scale factor is \e immediatly applied to Icalc */ virtual void FitScaleFactorForR() const; /// Compute the best scale factor to minimize R, apply this scale factor and return /// the R value obtained. virtual REAL GetBestRFactor() const; /** \brief Set sigma for all observed intensities to sqrt(obs) * */ virtual void SetSigmaToSqrtIobs(); /** \brief Set the weight for all observed intensities to 1/sigma^2 * *For sigmas which are smaller than minRelatSigma times the max value of sigma, *the output weight is set to 0. * * For reflections where the intensity is below minIobsSigmaRatio*sigma, the weight is set to zero * so that this reflection is ignored. */ virtual void SetWeightToInvSigma2(const REAL minRelatSigma=1e-4, const REAL minIobsSigmaRatio=0); /// Scale factor (applied to Icalc to match Iobs) REAL GetScaleFactor()const; // Set the Scale factor (applied to Icalc to match Iobs) //void SetScaleFactor(const REAL); /** \brief Print H, K, L Iobs sigma for all reflections * */ virtual void PrintObsData()const; /** \brief Print H, K, L Iobs sigma Icalc for all reflections *Iobs and sigma (if given) are scaled to Icalc (if available). * */ virtual void PrintObsCalcData()const; virtual void SetUseOnlyLowAngleData(const bool useOnlyLowAngle,const REAL angle=0.); ///Save H,K,L Iobs Icalc to a file, text format, 3 columns theta Iobs Icalc. ///If Iobs is missing, the column is omitted. void SaveHKLIobsIcalc(const string &filename="hklIobsIcalc.out"); virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); virtual REAL GetLogLikelihood()const; //LSQ functions virtual unsigned int GetNbLSQFunction()const; virtual const CrystVector_REAL& GetLSQCalc(const unsigned int) const; virtual const CrystVector_REAL& GetLSQObs(const unsigned int) const; virtual const CrystVector_REAL& GetLSQWeight(const unsigned int) const; virtual std::map & GetLSQ_FullDeriv(const unsigned int,std::set &vPar); virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual const Radiation& GetRadiation()const; Radiation& GetRadiation(); /// Set : neutron or x-ray experiment ? Wavelength ? virtual void SetRadiationType(const RadiationType radiation); /// Set the (monochromatic) wavelength of the beam. void SetWavelength(const REAL ); /** \ brief Set X-Ray tube radiation. * *\param XRayTubeElementName : name of the anticathode element name. Known *ones are Cr, Fe, Cu, Mo, Ag. *\param alpha2Alpha2ratio: Kalpha2/Kalpha1 ratio (0.5 by default) * *the average wavelength is calculated *using the alpha2/alpha1 weight. All structure factors computation are made *using the average wavelength, and for powder diffraction, profiles are output *at the alpha1 and alpha2 ratio for the calculated pattern. * *NOTE : if the name of the wavelength is generic (eg"Cu"), *then the program considers that *there are both Alpha1 and Alpha2, and thus automatically changes the WavelengthType *to WAVELENGTH_ALPHA12. If instead either alpha1 or alpha2 (eg "CuA1") is asked for, *the WavelengthType is set to WAVELENGTH_MONOCHROMATIC. In both cases, * the radiation type is set to X-Ray. */ void SetWavelength(const string &XRayTubeElementName,const REAL alpha2Alpha2ratio=0.5); /// Set the (monochromatic) energy of the beam. void SetEnergy(const REAL ); protected: private: virtual void InitRefParList(); /// Calc intensities void CalcIcalc() const; void CalcIcalc_FullDeriv(std::set &vPar); virtual CrystVector_long SortReflectionBySinThetaOverLambda(const REAL maxTheta=-1.); /// Init options (currently only twinning). void InitOptions(); /// Determine the index of reflections to be summed because of twinning (GroupOption==1) /// The reflections \e must have been sorted by increasing theta beforehand. void PrepareTwinningCalc() const; /// Are there observed intensities ? bool mHasObservedData; /** \brief Observed intensity (after ABS and LP corrections) * * In the single crystal case, this is a list of intensity corresponding to (h,k,l). * For a powder sample, this is a list of all peaks intensities. */ CrystVector_REAL mObsIntensity ; /// Sigma for observed intensities (either individual reflections or spectrum) CrystVector_REAL mObsSigma ; /// weight for computing R-Factor, for each observed value. CrystVector_REAL mWeight ; /// Calculated intensities mutable CrystVector_REAL mCalcIntensity ; /// mutable std::map mCalcIntensity_FullDeriv; /// Scale factor. It is applied when computing intensities. The scale ///applies to intensities mutable REAL mScaleFactor; /// Chi^2 mutable REAL mChi2; //Clocks /// Last time Icalc was computed mutable RefinableObjClock mClockIcalc; /// Last modification of the scale factor mutable RefinableObjClock mClockScaleFactor; ///Clock the last time Chi^2 was computed mutable RefinableObjClock mClockChi2; // Grouped reflections /// Option for the type of grouping (0:no, 1:by theta values (twinning), 2:user-supplied groups) RefObjOpt mGroupOption; /// The observed intensities summed on all reflections that are (or could be) /// overlapped dur to a twinning mutable CrystVector_REAL mGroupIobs; /// The uncertainty on observed grouped intensities. mutable CrystVector_REAL mGroupSigma; /// The calculated intensities summed on all reflections that are grouped mutable CrystVector_REAL mGroupIcalc; mutable std::map mGroupIcalc_FullDeriv; /// The weight on each reflection sum in case of grouped reflections. The sum is the /// inverse of the sum of all sigma^2 mutable CrystVector_REAL mGroupWeight; /** The index of reflections which need to be summed. They must have been sorted * by increasing theta values. Each entry (the reflection index) marks the beginning * of a new batch of reflections to be summed. * * Here only the groups of reflections are \e roughly sorted by sin(theta)/lambda. * It is assumed, howver, that grouped reflections are of approximately the same * d_hkl. After ScatteringData::GetNbReflBelowMaxSinThetaOvLambda(), * the number of groups for which *all* reflections are below the limit are * taken into account for the statistics. * * Note that \before DiffractionDataSingleCrystal::SortReflectionBySinThetaOverLambda() * is called (i.e. immediately after importing the reflections) **/ mutable CrystVector_long mGroupIndex; /// Number of groups mutable long mNbGroup; /// Number of groups below max[sin(theta)/lambda] mutable long mNbGroupUsed; /// Clock for twinning, when the preparation of twinning correction was last made. mutable RefinableObjClock mClockPrepareTwinningCorr; // The Radiation for this object Radiation mRadiation; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXDiffractionSingleCrystal;//to access the Radiation object #endif }; /// Global registry for all PowderPattern objects extern ObjRegistry gDiffractionDataSingleCrystalRegistry; } //namespace ObjCryst #endif //_OBJCRYST_DIFFDATA_SINGLECRYSTAL_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Exception.cpp000066400000000000000000000045561417150057700235200ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for LibCryst++ ObjCrystException class * */ #include "ObjCryst/ObjCryst/General.h" #include #include #include "ObjCryst/ObjCryst/IO.h" namespace ObjCryst { bool ObjCrystException::verbose = true; ObjCrystException::ObjCrystException() : message() { if (ObjCrystException::verbose) { cout << "LibCryst ++ exception thrown!!" << endl; } } ObjCrystException::ObjCrystException(const string & _message) { message = _message; if (!ObjCrystException::verbose) { return; } static bool inException; cout << "LibCryst ++ exception thrown!!" << endl; cout << " Message: " + message < #include #include // Restricted pointers (useful for auto-vectorization) #ifdef __GNUG__ #define RESTRICT __restrict__ #elif defined(_MSC_VER) || defined(__ICL) // MS and VC++ compiler #define RESTRICT __restrict #else #define RESTRICT #endif //profiling #ifdef __MWERKS__ #include #endif #ifdef PROFILING_ON #include "Profile/Profiler.h" #else #define TAU_PROFILE(name, type, group) #define TAU_PROFILE_START(var) #define TAU_PROFILE_TIMER(var, name, type, group) #define TAU_PROFILE_STOP(var) #define TAU_PROFILE_INIT(argc, argv) #define TAU_PROFILE_SET_NODE(node) #define TAU_PROFILE_SET_CONTEXT(context) #define TAU_EVENT(event, data) #define TAU_REPORT_STATISTICS() #define TAU_REPORT_THREAD_STATISTICS() #endif #include "ObjCryst/Quirks/VFNDebug.h" using namespace std; /** The namespace which includes all objects (crystallographic and * algorithmic) in ObjCryst++. * * \note It may be a good idea to separate in 3 namespaces for ObjCryst, WXObjCryst, * and RefinableObj */ namespace ObjCryst { #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif #define DEG2RAD (M_PI/180.) #define RAD2DEG (180./M_PI) #ifndef REAL #define REAL double #endif // Implemented in IO.cpp /// Function to convert a substring to a floating point value, imposing a C locale (using '.' as decimal separator). /// This is used for input/output from data file, which are only using the C locale, contrary to the GUI. float string2floatC(const string &s); //###################################################################### /// Type of radiation used. Only neutrons and X-Rays are used so far, /// electrons would require a very different treatment. enum RadiationType { RAD_NEUTRON, RAD_XRAY, RAD_ELECTRON}; /// Sample type (not used yet) enum SampleType { SAMPLE_SINGLE_CRYSTAL, SAMPLE_POWDER}; /// Incident beam characteristics : monochromatic, X-Ray tube with Alpha1 and alpha2, /// MAD (a few wavelengths-UNUSED YET), DAFS (continuous wavelength range-UNUSED YET) /// LAUE (UNUSED YET), WAVELENGTH_TOF (neutron Time Of Flight) enum WavelengthType { WAVELENGTH_MONOCHROMATIC, WAVELENGTH_ALPHA12, WAVELENGTH_TOF, WAVELENGTH_MAD, WAVELENGTH_DAFS, WAVELENGTH_LAUE}; /// Profile type for powder (could it be used fopr single crystals on 2D detectors ?) enum ReflectionProfileType { PROFILE_GAUSSIAN, PROFILE_LORENTZIAN, PROFILE_PSEUDO_VOIGT, PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT, PROFILE_PEARSON_VII }; enum PowderBackgroundInterpType{ POWDER_BACKGROUND_LINEAR, POWDER_BACKGROUND_CUBIC_SPLINE}; #define XRAY_WAVELENGTH_TO_ENERGY 12398.4 //###################################################################### // Exception. /** \brief Exception class for ObjCryst++ library * */ //###################################################################### //:TODO: This should go into VFNDebug.h class ObjCrystException { public: ObjCrystException(); ObjCrystException(const string & message); ~ObjCrystException(); static bool verbose; string message; protected: private: }; //###################################################################### /** Print some information for the user during long processes. */ void ObjCrystInformUserStdOut(const string &); //###################################################################### /** \brief Pointer to a function for passing info to the user during or * after long/important processes (use scarcely!) * * This function pointer is by default assigned to ObjCrystInformUserStdOut, * which outputs the message to the standard output. If a user interface is * used (eg in Fox), this pointer should be reassigned at the beginning of the * application to a more user-suitable function. */ extern void (*fpObjCrystInformUser)(const string &); /** Class to compare pairs of objects, with the two objects playing a * symmetric role. */ template class SymmetricPairCompare { public: bool operator()(const pair &p1, const pair &p2) const { const T* p1f= &(p1.first); const T* p1s= &(p1.second); const T* p2f= &(p2.first); const T* p2s= &(p2.second); if(*p1f < *p1s) { p1s= &(p1.first); p1f= &(p1.second);} if(*p2f < *p2s) { p2s= &(p2.first); p2f= &(p2.second);} if(*p1f != *p2f) return *p1f < *p2f; else return *p1s < *p2s; } }; #ifdef OBJCRYST_GL /// Print a string in 2D at the current OpenGL position /// This is actually implemented in wxCryst/wxCrystal.cpp void crystGLPrint(const string &); #endif /// Class to store POV-Ray output options struct CrystalPOVRayOptions { /// Display limits in reduced coordinates REAL mXmin, mXmax, mYmin, mYmax, mZmin, mZmax; /// Show labels ? bool mShowLabel; /// Show hydrogens ? bool mShowHydrogens; }; /// This class only serves to temporarilly set the LC_NUMERIC C locale to "C", /// in order to use '.' as the decimal separator. /// Just creating one object of type tmp_C_Numeric_locale will switch to the C locale, /// and when the object gets destroyed it will restore the old locale. class tmp_C_Numeric_locale {// Implemented in SpaceGroup.cpp public: tmp_C_Numeric_locale(); ~tmp_C_Numeric_locale(); private: std::string mLocale; }; }//Namespace #endif //_VFN_OBJCRYST_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/GeomStructFactor.h000066400000000000000000000252251417150057700244560ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // This file declares all the functions used to compute the geometrical //structure factors //Use pointers for the calculation of geometrical structure factors ? //Else use the blitz library... //This is *not* useful for performance reasons, but rather //for memory /disk space reasons when using the GNU gcc compiler. //(complex array expressions using blitz take a *huge* space //on disk and in memory when compiling). Performance is still the best... #ifndef _VFN_RC_CRISTALLO_GEOM_STRUCT_FACTOR_H_ #define _VFN_RC_CRISTALLO_GEOM_STRUCT_FACTOR_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include namespace ObjCryst { // This is the default fonction, which does *not* use //the geometrical structure factor, but calculates all the symmetric //positions of the atom. This is done for SpaceGroups which //do not yet have a coded Geom Structure factor, or for those //where it does not make much difference /// \deprecated void RealGeomStructFactor (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); // Same for the imaginary part /// \deprecated void ImagGeomStructFactor (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_1 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_2 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67ba_c(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67cab(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67_cba(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67bca(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_67a_cb(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_97 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void RealGeomStructFactor_230 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /// \deprecated void ImagGeomStructFactor_centro(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); //do nothing /// \deprecated void ImagGeomStructFactor_1 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); /// \deprecated void ImagGeomStructFactor_2 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); /// \deprecated void ImagGeomStructFactor_67 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); /// \deprecated void ImagGeomStructFactor_67ba_c(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void ImagGeomStructFactor_67cab(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void ImagGeomStructFactor_67_cba(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void ImagGeomStructFactor_67bca(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void ImagGeomStructFactor_67a_cb(const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf); /// \deprecated void ImagGeomStructFactor_97 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); /// \deprecated void ImagGeomStructFactor_230 (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf); }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/IO.cpp000066400000000000000000002337711417150057700220740ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2006 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for XMLInput/XMLOutput in ObjCryst++ * */ #include //for sprintf #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/ObjCryst/IO.h" #include "ObjCryst/RefinableObj/IO.h" #include "ObjCryst/RefinableObj/GlobalOptimObj.h" //#include "ObjCryst/ObjCryst/SpaceGroup.h" #include "ObjCryst/ObjCryst/Scatterer.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/ZScatterer.h" //#include "ObjCryst/ObjCryst/ScatteringData.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/ObjCryst/ScatteringPowerSphere.h" #include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" #include "ObjCryst/ObjCryst/PowderPattern.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/ObjCryst/Molecule.h" #include #include #include #include #include //#define USE_BACKGROUND_MAXLIKE_ERROR namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // Global functions // //////////////////////////////////////////////////////////////////////// float string2floatC(const string &s) { float v=0; stringstream ss(s); ss.imbue(std::locale::classic()); ss>>v; return v; } float InputFloat(istream &is, const char endchar) { float f; // Get rid of spaces, returns etc... while(0==isgraph(is.peek())) is.get(); stringstream tmp; char c; while((endchar!=is.peek())&&(' '!=is.peek())) { is.get(c) ; // Explicit typecasting to char otherwise it is understood as an integer number from type charT... tmp<<(char)(tolower(c)) ; } if(tmp.str().find("nan")!=string::npos) { VFN_DEBUG_MESSAGE("InputFloat(..):"< NAN ! -> 1",9); return 1; } if(tmp.str().find("inf")!=string::npos) { VFN_DEBUG_MESSAGE("InputFloat(..):"< INF ! -> 1",9); return 1; } tmp.imbue(std::locale::classic()); tmp>>f; VFN_DEBUG_MESSAGE("InputFloat(..):"< XMLCrystFileLoadObjectList(const string & filename) { VFN_DEBUG_ENTRY("XMLCrystFileLoadObjectList(filename)",5) ifstream is(filename.c_str()); if(!is){};//:TODO: is.imbue(std::locale::classic()); ObjRegistry reg; for(;;) { XMLCrystTag *pTag =new XMLCrystTag (is); if(true==is.eof()) { VFN_DEBUG_EXIT("XMLCrystFileLoadObjectList(filename):End",5) for(int i=0;iPrint(); if(("Crystal"==pTag->GetName()|| "DiffractionDataSingleCrystal"==pTag->GetName()|| "PowderPattern"==pTag->GetName()|| "GlobalOptimObj"==pTag->GetName()) && !(pTag->IsEndTag())) reg.Register(*pTag); else delete pTag; } return reg; } template void XMLCrystFileLoadObject(const string & filename, const string &tagName, const string &name, T*obj) { VFN_DEBUG_ENTRY("XMLCrystFileLoadObject(filename,IOCrystTag,T&)",5) ifstream is(filename.c_str()); if(!is){};//:TODO: is.imbue(std::locale::classic()); XMLCrystTag tag; while(true) { is>>tag; if(true==is.eof()) { cout<<"XMLCrystFileLoadObject(filename,IOCrystTag,T&):Not Found !"<XMLInput(is,tag); is.close(); VFN_DEBUG_EXIT("XMLCrystFileLoadObject(filename,IOCrystTag,T&)",5) } template void XMLCrystFileLoadObject(const string & ,const string &,const string &, Crystal*); template void XMLCrystFileLoadObject(const string & ,const string &,const string &, PowderPattern*); template void XMLCrystFileLoadObject(const string & ,const string &,const string &, DiffractionDataSingleCrystal*); //template void IOCrystFileLoadObject(const string &,const IOCrystTag &, // ZScatterer*); template void XMLCrystFileLoadObject(const string & ,const string &,const string &, PowderPatternBackground*); template void XMLCrystFileLoadObject(const string & ,const string &,const string &, PowderPatternDiffraction*); template void XMLCrystFileLoadObject(const string & ,const string &,const string &, MonteCarloObj*); void XMLCrystFileLoadAllObject(const string & filename) { VFN_DEBUG_ENTRY("XMLCrystFileLoadAllObject(filename,)",5) ifstream is(filename.c_str()); if(is.fail()) throw ObjCrystException("XMLCrystFileLoadAllObject() failed input"); XMLCrystFileLoadAllObject(is); (*fpObjCrystInformUser)("Finished loading XML file:"+filename); VFN_DEBUG_EXIT("XMLCrystFileLoadAllObject(filename,)",5) } void XMLCrystFileLoadAllObject(istream &is) { VFN_DEBUG_ENTRY("XMLCrystFileLoadAllObject(istream)",5) is.imbue(std::locale::classic()); XMLCrystTag tag; do {is>>tag;} while(("ObjCryst"!=tag.GetName()) && (false==is.eof())); while(true) { XMLCrystTag tag(is); if(true==is.eof()) break; if(tag.GetName()=="Crystal") { Crystal* obj = new Crystal; obj->XMLInput(is,tag); (*fpObjCrystInformUser)("XML: finished reading Crystal object:"+obj->GetName()); } if(tag.GetName()=="PowderPattern") { PowderPattern* obj = new PowderPattern; obj->XMLInput(is,tag); (*fpObjCrystInformUser)("XML: finished reading Powder Pattern object:"+obj->GetName()); } if(tag.GetName()=="DiffractionDataSingleCrystal") { DiffractionDataSingleCrystal* obj = new DiffractionDataSingleCrystal; obj->XMLInput(is,tag); (*fpObjCrystInformUser)("XML: finished reading Single Crystal Diffraction object:"+obj->GetName()); } if(tag.GetName()=="GlobalOptimObj") { MonteCarloObj* obj = new MonteCarloObj; obj->XMLInput(is,tag); (*fpObjCrystInformUser)("XML: finished reading Global Optimization object:"+obj->GetName()); } } (*fpObjCrystInformUser)("Finished loading XML"); VFN_DEBUG_EXIT("XMLCrystFileLoadAllObject(istream)",5) } //////////////////////////////////////////////////////////////////////// // // I/O ScatteringPowerAtom // //////////////////////////////////////////////////////////////////////// void ScatteringPowerAtom::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ScatteringPowerAtom::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mBiso).XMLOutput(os,"Biso",indent+1); os<mIsIsotropic) { REAL* bdata = (REAL*) mB.data(); this->GetPar(&bdata[0]).XMLOutput(os,"B11",indent+1); os<GetPar(&bdata[1]).XMLOutput(os,"B22",indent+1); os<GetPar(&bdata[2]).XMLOutput(os,"B33",indent+1); os<GetPar(&bdata[3]).XMLOutput(os,"B12",indent+1); os<GetPar(&bdata[4]).XMLOutput(os,"B13",indent+1); os<GetPar(&bdata[5]).XMLOutput(os,"B23",indent+1); os<GetPar("ML Error").XMLOutput(os,"ML Error",indent+1); os <GetPar("ML-Nb Ghost Atoms").XMLOutput(os,"ML-NbGhost",indent+1); os <GetPar("Formal Charge").XMLOutput(os,"Formal Charge",indent+1); os <GetName(),5) } void ScatteringPowerAtom::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ScatteringPowerAtom::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("Symbol"==tagg.GetAttributeName(i)) mSymbol=tagg.GetAttributeValue(i); } (*fpObjCrystInformUser)("Input ScatteringPowerAtom:"+mName+"("+mSymbol+")"); this->Init(mName,mSymbol,mBiso); while(true) { XMLCrystTag tag(is); if(("ScatteringPowerAtom"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("ScatteringPowerAtom::Exit():"<GetName(),5) return; } if("RGBColour"==tag.GetName()) { float r,g,b; is>>r>>g>>b; this->SetColour(r,g,b); XMLCrystTag junk(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mBiso).XMLInput(is,tag); this->mIsIsotropic = true; break; } if("B11"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[0]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("B22"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[1]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("B33"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[2]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("B12"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[3]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("B13"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[4]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("B23"==tag.GetAttributeValue(i)) { this->GetPar(&mB.data()[5]).XMLInput(is,tag); this->mIsIsotropic = false; break; } if("ML Error"==tag.GetAttributeValue(i)) { this->GetPar("ML Error").XMLInput(is,tag); break; } if("ML-NbGhost"==tag.GetAttributeValue(i)) { this->GetPar("ML-Nb Ghost Atoms").XMLInput(is,tag); break; } if("Formal Charge"==tag.GetAttributeValue(i)) { this->GetPar("Formal Charge").XMLInput(is,tag); break; } } } continue; } } } //////////////////////////////////////////////////////////////////////// // // I/O Atom // //////////////////////////////////////////////////////////////////////// void Atom::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("Atom::XMLOutput():"<GetName(),5) for(int i=0;iGetName()); os <GetPar(mXYZ.data()+0).XMLOutput(os,"x",indent); os <GetPar(mXYZ.data()+1).XMLOutput(os,"y",indent); os <GetPar(mXYZ.data()+2).XMLOutput(os,"z",indent); os <GetPar(&mOccupancy).XMLOutput(os,"Occup",indent); os <GetName(),5) } void Atom::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("Atom::XMLInput():"<GetName(),5) string scattPowName; for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("ScattPow"==tagg.GetAttributeName(i)) scattPowName=tagg.GetAttributeValue(i); } (*fpObjCrystInformUser)("XML: Loading Atom:"+this->GetName()); const ScatteringPower* scattPow= &(this->GetCrystal().GetScatteringPowerRegistry().GetObj(scattPowName)); VFN_DEBUG_MESSAGE("Found Scattering Power:"<< scattPowName<<" at "<Init(0,0,0,mName,scattPow,1); while(true) { XMLCrystTag tag(is); if(("Atom"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("Atom::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(mXYZ.data()+0).XMLInput(is,tag); break; } if("y"==tag.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+1).XMLInput(is,tag); break; } if("z"==tag.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+2).XMLInput(is,tag); break; } if("Occup"==tag.GetAttributeValue(i)) { this->GetPar(&mOccupancy).XMLInput(is,tag); break; } } } continue; } } } //////////////////////////////////////////////////////////////////////// // // I/O ZAtom // //////////////////////////////////////////////////////////////////////// void ZAtom::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ZAtom::XMLOutput():"<GetName(),5) for(int i=0;iGetScatteringPower())//else it is a dummy atom tag.AddAttribute("ScattPow",this->GetScatteringPower()->GetName()); tag.AddAttribute("BondAtom",this->GetZScatterer() .GetZAtomRegistry() .GetObj(this->GetZBondAtom()) .GetName()); tag.AddAttribute("AngleAtom",this->GetZScatterer() .GetZAtomRegistry() .GetObj(this->GetZAngleAtom()) .GetName()); tag.AddAttribute("DihedAtom",this->GetZScatterer() .GetZAtomRegistry() .GetObj(this->GetZDihedralAngleAtom()) .GetName()); os <GetZScatterer().GetPar(&mBondLength).XMLOutput(os,"BondLength",indent); os <GetZScatterer().GetPar(&mAngle).XMLOutput(os,"Angle",indent); os <GetZScatterer().GetPar(&mDihed).XMLOutput(os,"DihedAng",indent); os <GetZScatterer().GetPar(&mOccupancy).XMLOutput(os,"Occup",indent); os <GetName(),5) } void ZAtom::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ZAtom::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); continue; } if("ScattPow"==tagg.GetAttributeName(i)) { const ScatteringPower* scattPow=&(this->GetZScatterer() .GetCrystal() .GetScatteringPowerRegistry() .GetObj(tagg.GetAttributeValue(i))); this->SetScatteringPower(scattPow); continue; } if("BondAtom"==tagg.GetAttributeName(i)) { mAtomBond=this->GetZScatterer().GetZAtomRegistry().Find(tagg.GetAttributeValue(i)); continue; } if("AngleAtom"==tagg.GetAttributeName(i)) { mAtomAngle=this->GetZScatterer().GetZAtomRegistry().Find(tagg.GetAttributeValue(i)); continue; } if("DihedAtom"==tagg.GetAttributeName(i)) { mAtomDihed=this->GetZScatterer().GetZAtomRegistry().Find(tagg.GetAttributeValue(i)); continue; } } while(true) { XMLCrystTag tag(is); if(("ZAtom"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("ZAtom::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetZScatterer().GetPar(&mBondLength).XMLInput(is,tag); break; } if("Angle"==tag.GetAttributeValue(i)) { this->GetZScatterer().GetPar(&mAngle).XMLInput(is,tag); break; } if("DihedAng"==tag.GetAttributeValue(i)) { this->GetZScatterer().GetPar(&mDihed).XMLInput(is,tag); break; } if("Occup"==tag.GetAttributeValue(i)) { this->GetZScatterer().GetPar(&mOccupancy).XMLInput(is,tag); break; } } } continue; } } } //////////////////////////////////////////////////////////////////////// // // I/O ZScatterer // //////////////////////////////////////////////////////////////////////// void ZScatterer::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ZScatterer::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(mXYZ.data()+0).XMLOutput(os,"x",indent); os <GetPar(mXYZ.data()+1).XMLOutput(os,"y",indent); os <GetPar(mXYZ.data()+2).XMLOutput(os,"z",indent); os <GetPar(&mOccupancy).XMLOutput(os,"Occup",indent); os <GetPar(&mPhi).XMLOutput(os,"Phi",indent); os <GetPar(&mChi).XMLOutput(os,"Chi",indent); os <GetPar(&mPsi).XMLOutput(os,"Psi",indent); os <0) { for(int i=0;i<=indent;i++) os << " " ; XMLCrystTag tag2("PivotAtom",false,true); tag2.AddAttribute("Name",this->GetZAtomRegistry().GetObj(mCenterAtomIndex).GetName()); os <GetName(),5) } void ZScatterer::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ZScatterer::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); } (*fpObjCrystInformUser)("XML: Loading ZScatterer:"+this->GetName()); while(true) { XMLCrystTag tag(is); if(("ZScatterer"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("ZScatterer::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(mXYZ.data()+0).XMLInput(is,tag); break; } if("y"==tag.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+1).XMLInput(is,tag); break; } if("z"==tag.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+2).XMLInput(is,tag); break; } if("Occup"==tag.GetAttributeValue(i)) { this->GetPar(&mOccupancy).XMLInput(is,tag); break; } if("Phi"==tag.GetAttributeValue(i)) { this->GetPar(&mPhi).XMLInput(is,tag); break; } if("Chi"==tag.GetAttributeValue(i)) { this->GetPar(&mChi).XMLInput(is,tag); break; } if("Psi"==tag.GetAttributeValue(i)) { this->GetPar(&mPsi).XMLInput(is,tag); break; } } } continue; } if("ZAtom"==tag.GetName()) { //we must take care of possible dummy atoms const ScatteringPower* scattPow=0; for(unsigned int i=0;iGetCrystal().GetScatteringPowerRegistry() .GetObj(tag.GetAttributeValue(i))); const long nb=mZAtomRegistry.GetNb(); this->AddAtom("",scattPow,0,0,0,0,0,1); mZAtomRegistry.GetObj(nb).XMLInput(is,tag); // Update the name of refinable parameters { char buf [20]; sprintf(buf,"%d-%d",(int)nb,(int)(mZAtomRegistry.GetObj(nb).GetZBondAtom())); this->GetPar(&(mZAtomRegistry.GetObj(nb).mBondLength)) .SetName("Length"+(string)buf); sprintf(buf,"%d-%d-%d",(int)nb,(int)(mZAtomRegistry.GetObj(nb).GetZBondAtom()), (int)(mZAtomRegistry.GetObj(nb).GetZAngleAtom())); this->GetPar(&(mZAtomRegistry.GetObj(nb).mAngle)) .SetName("Angle"+(string)buf); sprintf(buf,"%d-%d-%d-%d",(int)nb,(int)(mZAtomRegistry.GetObj(nb).GetZBondAtom()), (int)(mZAtomRegistry.GetObj(nb).GetZAngleAtom()), (int)(mZAtomRegistry.GetObj(nb).GetZDihedralAngleAtom())); this->GetPar(&(mZAtomRegistry.GetObj(nb).mDihed)) .SetName("Dihed"+(string)buf); } } if("PivotAtom"==tag.GetName()) { for(unsigned int i=0;iGetZAtomRegistry().Find(tag.GetAttributeValue(i)); } } } } //////////////////////////////////////////////////////////////////////// // // I/O Crystal // //////////////////////////////////////////////////////////////////////// void Crystal::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("Crystal::XMLOutput():"<GetName(),5) for(int i=0;iGetSpaceGroup().GetName()); os <GetPar("a").XMLOutput(os,"a",indent); os <GetPar("b").XMLOutput(os,"b",indent); os <GetPar("c").XMLOutput(os,"c",indent); os <GetPar("alpha").XMLOutput(os,"alpha",indent); os <GetPar("beta").XMLOutput(os,"beta",indent); os <GetPar("gamma").XMLOutput(os,"gamma",indent); os <GetNbOption();i++) { this->GetOption(i).XMLOutput(os,indent); os <0) { VBumpMergePar::const_iterator pos; for(pos=mvBumpMergePar.begin();pos!=mvBumpMergePar.end();pos++) { for(int k=0;k<=indent;k++) os << " " ; XMLCrystTag tagBump("AntiBumpDistance"); tagBump.AddAttribute("ScattPow1",pos->first.first->GetName()); tagBump.AddAttribute("ScattPow2",pos->first.second->GetName()); { stringstream ss; ss << pos->second.mCanOverlap; tagBump.AddAttribute("AllowMerge",ss.str()); } os<second.mDist2)<0) { map, REAL>::const_iterator pos; for(pos=mvBondValenceRo.begin();pos!=mvBondValenceRo.end();pos++) { for(int k=0;k<=indent;k++) os << " " ; XMLCrystTag tagBVRo("BondValenceRo"); tagBVRo.AddAttribute("ScattPow1",pos->first.first->GetName()); tagBVRo.AddAttribute("ScattPow2",pos->first.second->GetName()); os<second<GetName(),5) } void Crystal::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("Crystal::XMLInput():"<GetName(),5) (*fpObjCrystInformUser)("XML: Loading Crystal:"); //Remove Scatterers and Scattering Powers for(long i=0;iRemoveSubRefObj(mScatteringPowerRegistry.GetObj(i)); mScatteringPowerRegistry.GetObj(i).DeRegisterClient(*this); } std::list vold_scattpow; if(mDeleteSubObjInDestructor) { mScatteringPowerRegistry.DeleteAll(); } else { // Keep track of the old atomic scattering powers to see if they can be re-used for(std::vector::const_iterator pos=mScatteringPowerRegistry.begin() ; pos!=mScatteringPowerRegistry.end(); ++pos) { if((*pos)->GetClassName().compare("ScatteringPowerAtom")!=0) continue; vold_scattpow.push_back(dynamic_cast(*pos)); } mScatteringPowerRegistry.DeRegisterAll(); } for(long i=0;iRemoveSubRefObj(mScattererRegistry.GetObj(i)); mScattererRegistry.GetObj(i).DeRegisterClient(*this); } if(mDeleteSubObjInDestructor) { mScattererRegistry.DeleteAll(); } else { mScattererRegistry.DeRegisterAll(); } for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("SpaceGroup"==tagg.GetAttributeName(i)) this->Init(1,2,3,M_PI/2,M_PI/2,M_PI/2,tagg.GetAttributeValue(i),this->GetName()); } (*fpObjCrystInformUser)("XML: Loading Crystal:"+this->GetName()+"(spg:"+this->GetSpaceGroup().GetName()+")"); while(true) { XMLCrystTag tag(is); if(("Crystal"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("Crystal::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(tag.GetAttributeValue(i)).XMLInput(is,tag); } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iInitRefParList();// Fix the "used" tag of refinable par after options continue; } if("AntiBumpDistance"==tag.GetName()) { float dist; bool useMerge=false; bool allowMerge; string scattPow1; string scattPow2; for(unsigned int i=0;i>allowMerge; useMerge=true; continue; } if("ScattPow1"==tag.GetAttributeName(i)) scattPow1=tag.GetAttributeValue(i); if("ScattPow2"==tag.GetAttributeName(i)) scattPow2=tag.GetAttributeValue(i); } is>>dist; XMLCrystTag junk(is);//end tag if(useMerge) this->SetBumpMergeDistance(mScatteringPowerRegistry.GetObj(scattPow1), mScatteringPowerRegistry.GetObj(scattPow2), dist,allowMerge); else this->SetBumpMergeDistance(mScatteringPowerRegistry.GetObj(scattPow1), mScatteringPowerRegistry.GetObj(scattPow2), dist); continue; } if("BondValenceRo"==tag.GetName()) { float ro; string scattPow1; string scattPow2; for(unsigned int i=0;i>ro; XMLCrystTag junk(is);//end tag this->AddBondValenceRo(mScatteringPowerRegistry.GetObj(scattPow1), mScatteringPowerRegistry.GetObj(scattPow2),ro); continue; } if("AntiBumpScale"==tag.GetName()) { is>>mBumpMergeScale; XMLCrystTag junk(is); } if("BondValenceCostScale"==tag.GetName()) { is>>mBondValenceCostScale; XMLCrystTag junk(is); } if("Atom"==tag.GetName()) { VFN_DEBUG_ENTRY("Crystal::XMLInput():reading an Atom",5) Atom *at=new Atom; at->SetCrystal(*this); at->XMLInput(is,tag); this->AddScatterer(at); VFN_DEBUG_EXIT("Crystal::XMLInput():reading an Atom",5) continue; } if("ScatteringPowerAtom"==tag.GetName()) { VFN_DEBUG_ENTRY("Crystal::XMLInput():reading a ScatteringPowerAtom",5) VFN_DEBUG_MESSAGE("Crystal::XMLInput():reading a ScatteringPowerAtom",5) ScatteringPowerAtom *sc=new ScatteringPowerAtom; sc->XMLInput(is,tag); if(!mDeleteSubObjInDestructor) { // Can we re-use a previous scattering power since we did not delete them ? for(std::list::iterator pos= vold_scattpow.begin(); pos!=vold_scattpow.end();++pos) { if((*pos)->GetSymbol() != sc->GetSymbol()) continue; if((*pos)->GetName() != sc->GetName()) continue; if((*pos)->GetFormalCharge() != sc->GetFormalCharge()) continue; if((*pos)->GetMaximumLikelihoodNbGhostAtom() != sc->GetMaximumLikelihoodNbGhostAtom()) continue; if((*pos)->GetMaximumLikelihoodPositionError() != sc->GetMaximumLikelihoodPositionError()) continue; if((*pos)->IsIsotropic() != sc->IsIsotropic()) continue; if(fabs((*pos)->GetBiso() - sc->GetBiso()) > 1e-4f) continue; if(!(*pos)->IsIsotropic()) { if(fabs((*pos)->GetBij(0) - sc->GetBij(0)) > 1e-4f) continue; if(fabs((*pos)->GetBij(1) - sc->GetBij(1)) > 1e-4f) continue; if(fabs((*pos)->GetBij(2) - sc->GetBij(2)) > 1e-4f) continue; if(fabs((*pos)->GetBij(3) - sc->GetBij(3)) > 1e-4f) continue; if(fabs((*pos)->GetBij(4) - sc->GetBij(4)) > 1e-4f) continue; if(fabs((*pos)->GetBij(5) - sc->GetBij(5)) > 1e-4f) continue; } VFN_DEBUG_MESSAGE("Crystal::XMLInput(): reusing scattering power: "<GetName(),5); delete sc; sc = *pos; } } this->AddScatteringPower(sc); VFN_DEBUG_EXIT("Crystal::XMLInput():reading a ScatteringPowerAtom",5) continue; } if("ScatteringPowerSphere"==tag.GetName()) { VFN_DEBUG_ENTRY("Crystal::XMLInput():reading a ScatteringPowerSphere",5) VFN_DEBUG_MESSAGE("Crystal::XMLInput():reading a ScatteringPowerSphere",5) ScatteringPowerSphere *sc=new ScatteringPowerSphere; sc->XMLInput(is,tag); this->AddScatteringPower(sc); VFN_DEBUG_EXIT("Crystal::XMLInput():reading a ScatteringPowerSphere",5) continue; } if("ZScatterer"==tag.GetName()) { VFN_DEBUG_ENTRY("Crystal::XMLInput():reading a ZScatterer",5) VFN_DEBUG_MESSAGE("Crystal::XMLInput():reading a ZScatterer",5) ZScatterer *z=new ZScatterer("",*this); z->XMLInput(is,tag); this->AddScatterer(z); VFN_DEBUG_EXIT("Crystal::XMLInput():reading a ZScatterer",5) continue; } if("Molecule"==tag.GetName()) { VFN_DEBUG_ENTRY("Crystal::XMLInput():reading a Molecule",5) VFN_DEBUG_MESSAGE("Crystal::XMLInput():reading a Molecule",5) Molecule *z=new Molecule(*this,""); z->XMLInput(is,tag); this->AddScatterer(z); VFN_DEBUG_EXIT("Crystal::XMLInput():reading a Molecule",5) continue; } } (*fpObjCrystInformUser)("XML: Finished loading Crystal:"+this->GetName()); } //////////////////////////////////////////////////////////////////////// // // I/O Radiation // //////////////////////////////////////////////////////////////////////// void Radiation::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("Radiation::XMLOutput():"<GetName(),5) XMLCrystTag tag("Radiation"); if(WAVELENGTH_ALPHA12==this->GetWavelengthType()) tag.AddAttribute("XRayTube",mXRayTubeName); for(int i=0;iGetWavelengthType()) { case WAVELENGTH_MONOCHROMATIC: this->GetPar(mWavelength.data()).XMLOutput(os,indent);break; case WAVELENGTH_ALPHA12: { this->GetPar(mWavelength.data()).XMLOutput(os,indent); os <GetPar("XRayTubeDeltaLambda").XMLOutput(os,indent); os <GetPar("XRayTubeAlpha2Alpha1Ratio").XMLOutput(os,indent); break; } case WAVELENGTH_TOF:break; default: throw ObjCrystException("This radiation is not implemented !!"); } os<GetName(),5) } void Radiation::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("Radiation::XMLInput():"<GetName(),5) string scattPowName; for(unsigned int i=0;iSetWavelength(tagg.GetAttributeValue(i)); } while(true) { XMLCrystTag tag(is); if(("Radiation"==tag.GetName())&&tag.IsEndTag()) { // This will force the update of the 'used' status of the alpha1/alpha2 and delta lambda parameters this->SetWavelengthType((WavelengthType) mWavelengthType.GetChoice()); VFN_DEBUG_EXIT("Radiation::Exit():"<GetName(),5) return; } if("Option"==tag.GetName()) { for(unsigned int i=0;i>mLinearPolarRate; XMLCrystTag junk(is); } if("XRayTubeDeltaLambda"==tag.GetName()) { is>>mXRayTubeDeltaLambda; XMLCrystTag junk(is); } if("XRayTubeAlpha2Alpha1Ratio"==tag.GetName()) { is>>mXRayTubeAlpha2Alpha1Ratio; XMLCrystTag junk(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(mWavelength.data()).XMLInput(is,tag); break; } if("XRayTubeDeltaLambda"==tag.GetAttributeValue(i)) { this->GetPar("XRayTubeDeltaLambda").XMLInput(is,tag); break; } if("XRayTubeAlpha2Alpha1Ratio"==tag.GetAttributeValue(i)) { this->GetPar("XRayTubeAlpha2Alpha1Ratio").XMLInput(is,tag); break; } } } continue; } } } //////////////////////////////////////////////////////////////////////// // // I/O DiffractionDataSingleCrystal // //////////////////////////////////////////////////////////////////////// void DiffractionDataSingleCrystal::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::XMLOutput():"<GetName(),5) for(int i=0;iGetCrystal().GetName()); os <GetPar("Scale factor").XMLOutput(os,"Scale factor",indent); os <GetPar(&mGlobalBiso).XMLOutput(os,"globalBiso",indent); os <GetNbRefl();j++) { for(int i=0;i<=indent;i++) os << " " ; os << mIntH(j) <<" " << mIntK(j) <<" " << mIntL(j) <<" " << mObsIntensity(j) <<" " << mObsSigma(j) <<" " << mWeight(j) <<" " <GetName(),5) } void DiffractionDataSingleCrystal::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("DiffractionDataSingleCrystal::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("Crystal"==tagg.GetAttributeName(i)) this->SetCrystal(gCrystalRegistry.GetObj(tagg.GetAttributeValue(i))); } while(true) { XMLCrystTag tag(is); if(("DiffractionDataSingleCrystal"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("DiffractionDataSingleCrystal::XMLInput():"<GetName(),5) return; } if("Option"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mScaleFactor).XMLInput(is,tag); break; } } } } if("Radiation"==tag.GetName()) mRadiation.XMLInput(is,tag); if("MaxSinThetaOvLambda"==tag.GetName()) { is>>mMaxSinThetaOvLambda; XMLCrystTag junk(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mGlobalBiso).XMLInput(is,tag); break; } } } } if("HKLIobsSigmaWeightList"==tag.GetName()) { long nbrefl=0; CrystVector_long h(100),k(100),l(100); CrystVector_REAL iobs(100),sigma(100),weight(100); do { is >>h(nbrefl)>>k(nbrefl)>>l(nbrefl); iobs (nbrefl)=InputFloat(is); if(ISNAN_OR_INF(iobs (nbrefl))||(iobs (nbrefl)<0)) iobs (nbrefl)=1e-8; sigma (nbrefl)=InputFloat(is); if(ISNAN_OR_INF(sigma (nbrefl))||(sigma (nbrefl)<0)) sigma (nbrefl)=1e-8; weight(nbrefl)=InputFloat(is); if(ISNAN_OR_INF(weight(nbrefl))||(weight(nbrefl)<0)) weight(nbrefl)=1e-8; nbrefl++; if(nbrefl==iobs.numElements()) { h.resizeAndPreserve(nbrefl+100); k.resizeAndPreserve(nbrefl+100); l.resizeAndPreserve(nbrefl+100); iobs.resizeAndPreserve(nbrefl+100); sigma.resizeAndPreserve(nbrefl+100); weight.resizeAndPreserve(nbrefl+100); } while(0==isgraph(is.peek())) is.get(); //cout << is.peek()<<" "<SetHklIobs(h,k,l,iobs,sigma); this->SetWeight(weight); this->SortReflectionBySinThetaOverLambda(); this->CalcIcalc(); this->FitScaleFactorForRw(); } if("HKLIobsSigmaWeightGROUPList"==tag.GetName()) { mNbRefl=0; mNbGroup=0; // This must NOT be changed with this kind of data. mGroupOption.SetChoice(2); // So de-register the option so that it is hidden from the user's view mOptionRegistry.DeRegister(mGroupOption); mClockMaster.RemoveChild(mGroupOption.GetClock()); mH.resize(500); mK.resize(500); mL.resize(500); mObsIntensity.resize(500); mObsSigma.resize(500); mGroupIndex.resize(500); mGroupIobs.resize(500); mGroupSigma.resize(500); mGroupWeight.resize(500); while(true) { XMLCrystTag grouptag(is); if(grouptag.GetName()=="HKLIobsSigmaWeightGROUPList") break; if(grouptag.GetName()=="HKLGroup") { for(unsigned int i=0;i>mGroupIobs(mNbGroup); continue; } if(grouptag.GetAttributeName(i)=="IobsSigma") { stringstream sst; sst<>mGroupSigma(mNbGroup); continue; } if(grouptag.GetAttributeName(i)=="Weight") { stringstream sst; sst<>mGroupWeight(mNbGroup); continue; } } VFN_DEBUG_MESSAGE("Group #"<PrepareHKLarrays(); this->SortReflectionBySinThetaOverLambda(); } } } //////////////////////////////////////////////////////////////////////// // // I/O PowderPatternBackground // //////////////////////////////////////////////////////////////////////// void PowderPatternBackground::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("PowderPatternBackground::XMLOutput():"<GetName(),5) for(int i=0;iGetName()); os <GetParentPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) scale=RAD2DEG; for(long j=0;jGetPar(mBackgroundInterpPointIntensity.data()+j).IsFixed()<<" " <GetPar("ML Model Error").XMLOutput(os,"ML Model Error",indent); os <GetName(),5) } void PowderPatternBackground::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("PowderPatternBackground::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("Interpolation"==tagg.GetAttributeName(i)) {// Obsolete, but we must still read this if("Linear"==tagg.GetAttributeValue(i)) mInterpolationModel.SetChoice(0); if("Spline"==tagg.GetAttributeValue(i)) mInterpolationModel.SetChoice(1); } } while(true) { XMLCrystTag tag(is); if(("PowderPatternBackground"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("PowderPatternBackground::Exit():"<GetName(),5) return; } if(("TThetaIntensityList"==tag.GetName())||("XIntensityList"==tag.GetName())) { long nbPoint=0; CrystVector_REAL bckgd2Theta(100); CrystVector_REAL bckgd(100); CrystVector_bool fix(100); do { VFN_DEBUG_MESSAGE("PowderPatternBackground::XMLInput():"<>bckgd2Theta(nbPoint) >>bckgd(nbPoint) >>fix(nbPoint); nbPoint++; if(nbPoint==bckgd2Theta.numElements()) { bckgd2Theta.resizeAndPreserve(nbPoint+100); bckgd.resizeAndPreserve(nbPoint+100); fix.resizeAndPreserve(nbPoint+100); } while(0==isgraph(is.peek())) is.get();//Why do I need that ? //cout << is.peek()<<" "<GetParentPowderPattern().GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) bckgd2Theta*= DEG2RAD; this->SetInterpPoints(bckgd2Theta,bckgd); this->InitRefParList(); //read closing tag XMLCrystTag junkEndTag(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar("ML Model Error").XMLInput(is,tag); break; #endif } } } } if("Option"==tag.GetName()) { for(unsigned int i=0;iGetName(),5) for(int i=0;iGetName()); tag.AddAttribute("Crystal",this->GetCrystal().GetName()); { stringstream ss; ss<IsIgnoringImagScattFact(); tag.AddAttribute("IgnoreImagScattFact",ss.str()); } os <XMLOutput(os,indent); this->GetPar(&mGlobalBiso).XMLOutput(os,"globalBiso",indent); os <0) { mCorrTextureMarchDollase.XMLOutput(os,indent); } mCorrTextureEllipsoid.XMLOutput(os,indent); #if 0 if(mFhklObsSq.numElements()>0) { XMLCrystTag tag2("FhklObsSq"); for(int i=0;iGetNbRefl();j++) { for(int i=0;i<=indent;i++) os << " " ; os << mIntH(j) <<" " << mIntK(j) <<" " << mIntL(j) <<" " << mFhklObsSq(j) <XMLOutput(os,indent); #endif indent--; tag.SetIsEndTag(true); for(int i=0;iGetName(),5) } void PowderPatternDiffraction::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("PowderPatternDiffraction::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("Crystal"==tagg.GetAttributeName(i)) this->SetCrystal(gCrystalRegistry.GetObj(tagg.GetAttributeValue(i))); if("NeedLorentzCorr"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); bool b; ss>>b; //mNeedLorentzCorr=b; //mClockLorentzPolarSlitCorrPar.Reset(); } if("NeedPolarCorr"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); bool b; ss>>b; //mNeedPolarCorr=b; //mClockLorentzPolarSlitCorrPar.Reset(); } if("Polar_AFactor"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); float b; ss>>b; //mPolarAfactor=b; //mClockLorentzPolarSlitCorrPar.Reset(); } if("NeedSlitApertureCorr"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); bool b; ss>>b; //mNeedSlitApertureCorr=b; //mClockLorentzPolarSlitCorrPar.Reset(); } if("IgnoreImagScattFact"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); bool b; ss>>b; this->SetIsIgnoringImagScattFact(b); mClockLorentzPolarSlitCorrPar.Reset(); } } while(true) { XMLCrystTag tag(is); if(("PowderPatternCrystal"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("PowderPatternDiffraction::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mGlobalBiso).XMLInput(is,tag); break; } if("U"==tag.GetAttributeValue(i)) { mpReflectionProfile->GetPar("U").XMLInput(is,tag); break; } if("V"==tag.GetAttributeValue(i)) { mpReflectionProfile->GetPar("V").XMLInput(is,tag); break; } if("W"==tag.GetAttributeValue(i)) { mpReflectionProfile->GetPar("W").XMLInput(is,tag); break; } if("Eta0"==tag.GetAttributeValue(i)) { mpReflectionProfile->GetPar("Eta0").XMLInput(is,tag); break; } if("Eta1"==tag.GetAttributeValue(i)) { mpReflectionProfile->GetPar("Eta1").XMLInput(is,tag); break; } if("W0"==tag.GetAttributeValue(i)) { //:TODO: mpReflectionProfile->GetPar("Eta0").XMLInput(is,tag); break; } if("W1"==tag.GetAttributeValue(i)) { //:TODO: mpReflectionProfile->GetPar("Eta1").XMLInput(is,tag); break; } if("W2"==tag.GetAttributeValue(i)) { //:TODO: mpReflectionProfile->GetPar("Eta2").XMLInput(is,tag); break; } } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iGetClassName()!="ReflectionProfilePseudoVoigt") { this->SetProfile(new ReflectionProfilePseudoVoigt); } mpReflectionProfile->XMLInput(is,tag); continue; } if("ReflectionProfilePseudoVoigtAnisotropic"==tag.GetName()) { if(mpReflectionProfile==0) { mpReflectionProfile=new ReflectionProfilePseudoVoigtAnisotropic; } else if(mpReflectionProfile->GetClassName()!="ReflectionProfilePseudoVoigtAnisotropic") { this->SetProfile(new ReflectionProfilePseudoVoigtAnisotropic); } mpReflectionProfile->XMLInput(is,tag); continue; } if("ReflectionProfileDoubleExponentialPseudoVoigt"==tag.GetName()) { if(mpReflectionProfile==0) { mpReflectionProfile =new ReflectionProfileDoubleExponentialPseudoVoigt(this->GetCrystal()); } else if(mpReflectionProfile->GetClassName()!="ReflectionProfileDoubleExponentialPseudoVoigt") { this->SetProfile(new ReflectionProfileDoubleExponentialPseudoVoigt(this->GetCrystal())); } mpReflectionProfile->XMLInput(is,tag); continue; } if("FhklObsSq"==tag.GetName()) {// old-style extracted data long nbrefl=0; CrystVector_REAL iobs(100),sigma; CrystVector_long h(100),k(100),l(100); mFhklObsSq.resize(100); do { is >>h(nbrefl)>>k(nbrefl)>>l(nbrefl)>>iobs(nbrefl); nbrefl++; if(nbrefl==h.numElements()) { h.resizeAndPreserve(nbrefl+100); k.resizeAndPreserve(nbrefl+100); l.resizeAndPreserve(nbrefl+100); iobs.resizeAndPreserve(nbrefl+100); } while(0==isgraph(is.peek())) is.get(); } while(is.peek()!='<');//until next tag XMLCrystTag junkEndTag(is); h.resizeAndPreserve(nbrefl); k.resizeAndPreserve(nbrefl); l.resizeAndPreserve(nbrefl); iobs.resizeAndPreserve(nbrefl); sigma.resizeAndPreserve(nbrefl); sigma=1; if(mpLeBailData==0) mpLeBailData=new DiffractionDataSingleCrystal(this->GetCrystal(),false); mpLeBailData->SetHklIobs(h,k,l,iobs,sigma); mpLeBailData->SetWavelength(this->GetRadiation().GetWavelength()(0)); mpLeBailData->SetRadiationType(this->GetRadiation().GetRadiationType()); // Estimate resolution const REAL min=iobs.max()*1e-6; unsigned long iresol=0; for(long i=0;imin) iresol=i; char buf[200]; sprintf(buf,"LeBail (d=%4.2fA?):",1/(2*abs(mpLeBailData->GetSinThetaOverLambda()(iresol))+1e-6)); mpLeBailData->SetName(string(buf)+this->GetCrystal().GetName()); //mpLeBailData->SetName(string("LeBail (resol=?):")+this->GetCrystal().GetName()); } if("DiffractionDataSingleCrystal"==tag.GetName()) {// Le Bail data if(mpLeBailData==0) mpLeBailData=new DiffractionDataSingleCrystal(this->GetCrystal(),false); mpLeBailData->XMLInput(is,tag); } if("FrozenLatticePar"==tag.GetName()) { this->FreezeLatticePar(true); for(unsigned int i=0;i>v; this->SetFrozenLatticePar(0,v); } if("b"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); //ss.imbue(std::locale::classic()); float v; ss>>v; this->SetFrozenLatticePar(1,v); } if("c"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); //ss.imbue(std::locale::classic()); float v; ss>>v; this->SetFrozenLatticePar(2,v); } if("alpha"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); //ss.imbue(std::locale::classic()); float v; ss>>v; this->SetFrozenLatticePar(3,v*M_PI/180); } if("beta"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); //ss.imbue(std::locale::classic()); float v; ss>>v; this->SetFrozenLatticePar(4,v*M_PI/180); } if("gamma"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); //ss.imbue(std::locale::classic()); float v; ss>>v; this->SetFrozenLatticePar(5,v*M_PI/180); } } } } } //////////////////////////////////////////////////////////////////////// // // I/O PowderPattern // //////////////////////////////////////////////////////////////////////// void PowderPattern::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("PowderPattern::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mXZero).XMLOutput(os,"Zero",indent); os <GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { this->GetPar(&mDIFC).XMLOutput(os,"TOF-DIFC",indent); os <GetPar(&mDIFA).XMLOutput(os,"TOF-DIFA",indent); os <GetPar(&m2ThetaDisplacement).XMLOutput(os,"2ThetaDisplacement",indent); os <GetPar(&m2ThetaTransparency).XMLOutput(os,"2ThetaTransparency",indent); os <0) { this->GetPar(&mMuR).XMLOutput(os,"MuR",indent); os <GetNbOption();i++) { this->GetOption(i).XMLOutput(os,indent); os <GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) scale=RAD2DEG; for(unsigned long j=0;jGetNbPoint();j++) { for(int i=0;i<=indent;i++) os << " " ; os << scale*mX(j) <<" " << mPowderPatternObs(j) <<" " << mPowderPatternObsSigma(j) <<" " << mPowderPatternWeight(j) <<" " <GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { os << tag3 << mExcludedRegionMinX(j) <<" " << mExcludedRegionMaxX(j) ; } else { os << tag3 << mExcludedRegionMinX(j)*RAD2DEG <<" " << mExcludedRegionMaxX(j)*RAD2DEG ; } tag3.SetIsEndTag(true); os<GetName(),5) } void PowderPattern::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("PowderPattern::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); } while(true) { XMLCrystTag tag(is); if(("PowderPattern"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("PowderPattern::Exit():"<GetName(),5) return; } if("Radiation"==tag.GetName()) mRadiation.XMLInput(is,tag); if("MaxSinThetaOvLambda"==tag.GetName()) { is>>mMaxSinThetaOvLambda; XMLCrystTag junk(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mXZero).XMLInput(is,tag); break; } if("2ThetaDisplacement"==tag.GetAttributeValue(i)) { this->GetPar(&m2ThetaDisplacement).XMLInput(is,tag); break; } if("2ThetaTransparency"==tag.GetAttributeValue(i)) { this->GetPar(&m2ThetaTransparency).XMLInput(is,tag); break; } if("TOF-DIFC"==tag.GetAttributeValue(i)) { this->GetPar(&mDIFC).XMLInput(is,tag); break; } if("TOF-DIFA"==tag.GetAttributeValue(i)) { this->GetPar(&mDIFA).XMLInput(is,tag); break; } if("MuR"==tag.GetAttributeValue(i)) { this->GetPar(&mMuR).XMLInput(is,tag); break; } } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iSetParentPowderPattern(*this); comp->XMLInput(is,tag); continue; } if("PowderPatternCrystal"==tag.GetName()) { PowderPatternDiffraction *comp=new PowderPatternDiffraction; comp->SetParentPowderPattern(*this); comp->XMLInput(is,tag); continue; } if("PowderPatternComponent"==tag.GetName()) { REAL scale=1.0; string name; for(unsigned int i=0;i>scale; continue; } if("Name"==tag.GetAttributeName(i)) name=tag.GetAttributeValue(i); } this->AddPowderPatternComponent(gPowderPatternComponentRegistry.GetObj(name)); mScaleFactor(mPowderPatternComponentRegistry.GetNb()-1)=scale; VFN_DEBUG_MESSAGE("->Adding Component :"<>min>>max; if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) this->AddExcludedRegion(min,max); else this->AddExcludedRegion(min*DEG2RAD,max*DEG2RAD); XMLCrystTag end(is); continue; } if("IobsSigmaWeightList"==tag.GetName()) { // Old version, just for 2theta-intensity pattern (no TOF) VFN_DEBUG_ENTRY("Loading Iobs-Sigma-Weight List...",8); REAL min,step; for(unsigned int i=0;i>min; VFN_DEBUG_MESSAGE("2Theta min="<>step; VFN_DEBUG_MESSAGE("2Theta step="<>mPowderPatternObs(mNbPoint) >>mPowderPatternObsSigma(mNbPoint) >>mPowderPatternWeight(mNbPoint); mNbPoint++; VFN_DEBUG_MESSAGE("Point #"<SetPowderPatternPar(min,step,mNbPoint); mClockPowderPatternPar.Click(); XMLCrystTag junk(is); VFN_DEBUG_EXIT("Loading Iobs-Sigma-Weight List...",8); continue; } if("XIobsSigmaWeightList"==tag.GetName()) { VFN_DEBUG_ENTRY("Loading X-Iobs-Sigma-Weight List...",8); while(0==isgraph(is.peek())) is.get(); if(is.peek()=='<') { cout <<"PowderPattern::XMLInput(): no data point in the powder pattern !"<>mX(mNbPoint) >>mPowderPatternObs(mNbPoint) >>mPowderPatternObsSigma(mNbPoint) >>mPowderPatternWeight(mNbPoint); mNbPoint++; VFN_DEBUG_MESSAGE("Point #"<GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) mX*=DEG2RAD; this->SetPowderPatternX(mX); XMLCrystTag junk(is); VFN_DEBUG_EXIT("Loading X-Iobs-Sigma-Weight List...",8); continue; } } } } //namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/IO.h000066400000000000000000000073771417150057700215420ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* IO.h * */ #ifndef _OBJCRYST_IOCRYST_H_ #define _OBJCRYST_IOCRYST_H_ #endif //_OBJCRYST_IOCRYST_H_ #include "ObjCryst/RefinableObj/IO.h" #include "ObjCryst/RefinableObj/RefinableObj.h" namespace ObjCryst { /** \brief Save all Objcryst++ objects. * * This saves all Crystal, PowderPattern, DiffDataSingleCrystal and GlobalOptimObj objects, * using the global registries for these classes. All other objects (Scatterer, * ScatteringPower, PowderPatternComponent are saved as well since they are sub-objects * of Crystal or PowderPattern objects). * * Saving is done in well-formed xml format. */ void XMLCrystFileSaveGlobal(const string & filename); /** \brief Save all Objcryst++ objects. * * This saves all Crystal, PowderPattern, DiffDataSingleCrystal and GlobalOptimObj objects, * using the global registries for these classes. All other objects (Scatterer, * ScatteringPower, PowderPatternComponent are saved as well since they are sub-objects * of Crystal or PowderPattern objects). * * Saving is done in well-formed xml format. */ void XMLCrystFileSaveGlobal(std::ostream &out); /** \brief Get the list (tags) of ObjCryst objects in a file * * This will recognize only certain tags in the file (Crystal,PowderPattern, * DiffDataSingleCrystal, GlobalOptimObj). Eventually it should include also * the ZScatterer objects. * * \note It will be the duty of the caller to destroy all the tags which have been * allocated. * * NOT TESTED YET ! */ ObjRegistry XMLCrystFileLoadObjectList(const string & filename); /** \brief Load an object from a file, identifying it from its tag * * \param file: the filename from which the object will be loaded. * \param tagName: the name of the tag * \param name: the name of the object to be found (in a 'Name' attribute) * \param obj: the pointer to the object to be loaded. The allocation will be done * by the function, and the pointer changed accordingly. * * NOT TESTED YET ! */ template void XMLCrystFileLoadObject(const string & file, const string &tagName, const string &name, T*obj); /** \brief Load all 'top' objects from a file (Crystal, PowderPattern, DiffDataSingleCrystal * and GlobalOptimObj objects). All objects are directly allocated, and can be accessed through * their respective global registry (eg gCrystalRegistry fro a Crysta, etc...) * * \param file: the filename from which the objects will be loaded. */ void XMLCrystFileLoadAllObject(const string & file); /** \brief Load all 'top' objects from a file (Crystal, PowderPattern, DiffDataSingleCrystal * and GlobalOptimObj objects). All objects are directly allocated, and can be accessed through * their respective global registry (eg gCrystalRegistry fro a Crysta, etc...) * * \param file: the filename from which the objects will be loaded. */ void XMLCrystFileLoadAllObject(std::istream &is); } libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Indexing.cpp000066400000000000000000003231271417150057700233250ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2006- Vincent Favre-Nicolin vincefn@users.sourceforge.net 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for Indexing classes & functions * */ #include #include #include "ObjCryst/ObjCryst/Indexing.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/Chronometer.h" using namespace std; #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif #ifndef DEG2RAD #define DEG2RAD (M_PI/180.) #endif #ifndef RAD2DEG #define RAD2DEG (180./M_PI) #endif namespace ObjCryst { float EstimateCellVolume(const float dmin, const float dmax, const float nbrefl, const CrystalSystem system,const CrystalCentering centering,const float kappa) { const float q1=dmin*dmin*dmin-dmax*dmax*dmax; const float q2=dmin*dmin -dmax*dmax; float D0,C0; if(system==TRICLINIC) { C0=2.095; return nbrefl/(C0*kappa*q1); } if(system==CUBIC) { if(centering==LATTICE_P) D0=0.862; if(centering==LATTICE_I) D0=0.475; if(centering==LATTICE_F) D0=0.354; return pow(nbrefl/(D0*kappa*q2),(float)1.5); } // "*.85" means using D0_min rather than D0 if(system==MONOCLINIC) {C0=1.047;D0=0.786*.85;} if(system==ORTHOROMBIC){C0=0.524;D0=1.36 *.85;} if(system==HEXAGONAL) {C0=0.150;D0=1.04 *.85;} if(system==RHOMBOEDRAL){C0=0.230;D0=1.04 *.85;} if(system==TETRAGONAL) {C0=0.214;D0=1.25 *.85;} if((centering==LATTICE_I)||(centering==LATTICE_A)||(centering==LATTICE_B)||(centering==LATTICE_C)) {C0/=2;D0/=2;} if(centering==LATTICE_F){C0/=4;D0/=4;} const float alpha=D0*q2/(3*C0*q1), beta=nbrefl/(2*kappa*C0*q1); const float eta=beta-alpha*alpha*alpha,gamma=sqrt(beta*beta-2*beta*alpha*alpha*alpha); const float v=pow(pow(eta+gamma,(float)(1/3.))+pow(fabs(eta-gamma),(float)(1/3.))-alpha,(float)3); return v; } /** light-weight class storing the reciprocal space unitcell */ RecUnitCell::RecUnitCell(const float zero,const float p0,const float p1,const float p2, const float p3,const float p4,const float p5,CrystalSystem lattice, const CrystalCentering cent, const unsigned int nbspurious): mlattice(lattice),mCentering(cent),mNbSpurious(nbspurious) { this->par[0]=zero; this->par[1]=p0; this->par[2]=p1; this->par[3]=p2; this->par[4]=p3; this->par[5]=p4; this->par[6]=p5; } RecUnitCell::RecUnitCell(const RecUnitCell &old) { *this=old; } void RecUnitCell::operator=(const RecUnitCell &rhs) { for(unsigned int i=0;i<7;++i) par[i]=rhs.par[i]; mlattice=rhs.mlattice; mCentering=rhs.mCentering; mNbSpurious=rhs.mNbSpurious; } float RecUnitCell::hkl2d(const float h,const float k,const float l,REAL *derivpar,const unsigned int derivhkl) const { if((derivpar==NULL)&&(derivhkl==0)) { switch(mlattice) { case TRICLINIC: { return par[0]+par[1]*h*h + par[2]*k*k + par[3]*l*l + par[4]*h*k + par[5]*k*l + par[6]*h*l; break; } case MONOCLINIC: { return par[0]+par[1]*par[1]*h*h + par[2]*par[2]*k*k + par[3]*par[3]*l*l + 2*par[1]*par[3]*par[4]*h*l; break; } case ORTHOROMBIC: { return par[0]+par[1]*par[1]*h*h + par[2]*par[2]*k*k + par[3]*par[3]*l*l; break; } case HEXAGONAL: { return par[0]+par[1]*par[1]*(h*h + k*k + h*k)+ par[2]*par[2]*l*l ; break; } case RHOMBOEDRAL: { return par[0]+par[1]*par[1]*(h*h + k*k + l*l + 2*par[2]*(h*k + k*l + h*l)); break; } case TETRAGONAL: { return par[0]+par[1]*par[1]*(h*h + k*k) + par[2]*par[2]*l*l; break; } case CUBIC: { return par[0]+par[1]*par[1]*(h*h+k*k+l*l); break; } } } if(derivhkl==1) { switch(mlattice) { case TRICLINIC: { return 2*par[1]*h + par[4]*k + par[6]*l; break; } case MONOCLINIC: { return 2*par[1]*par[1]*h + 2*par[1]*par[3]*par[4]*l; break; } case ORTHOROMBIC: { return 2*par[1]*par[1]*h; break; } case HEXAGONAL: { return par[1]*par[1]*(2*h + k); break; } case RHOMBOEDRAL: { return par[1]*par[1]*(2*h + 2*par[2]*(k + l)); break; } case TETRAGONAL: { return 2*par[1]*par[1]*h; break; } case CUBIC: { return 2*par[1]*par[1]*h; break; } } } if(derivhkl==2) { switch(mlattice) { case TRICLINIC: { return 2*par[2]*k + par[4]*h + par[5]*l; break; } case MONOCLINIC: { return 2*par[2]*par[2]*k; break; } case ORTHOROMBIC: { return 2*par[2]*par[2]*k; break; } case HEXAGONAL: { return par[1]*par[1]*(2*k + h); break; } case RHOMBOEDRAL: { return par[1]*par[1]*(2*k + l*l + 2*par[2]*(h + l)); break; } case TETRAGONAL: { return 2*par[1]*par[1]*k; break; } case CUBIC: { return 2*par[1]*par[1]*k; break; } } } if(derivhkl==3) { switch(mlattice) { case TRICLINIC: { return 2*par[3]*l + par[5]*k + par[6]*h; break; } case MONOCLINIC: { return 2*par[3]*par[3]*l + 2*par[1]*par[3]*par[4]*h; break; } case ORTHOROMBIC: { return 2*par[3]*par[3]*l; break; } case HEXAGONAL: { return 2*par[2]*par[2]*l; break; } case RHOMBOEDRAL: { return par[1]*par[1]*(2*l + 2*par[2]*(k + h)); break; } case TETRAGONAL: { return 2*par[2]*par[2]*l; break; } case CUBIC: { return 2*par[1]*par[1]*l; break; } } } if(derivpar==&par[0]) return 1.0; if(derivpar==(par+1)) { switch(mlattice) { case TRICLINIC: { return h*h; break; } case MONOCLINIC: { return 2*par[1]*h*h + 2*par[3]*par[4]*h*l; break; } case ORTHOROMBIC: { return 2*par[1]*h*h; break; } case HEXAGONAL: { return 2*par[1]*(h*h + k*k + h*k); break; } case RHOMBOEDRAL: { return 2*par[1]*(h*h + k*k + l*l + 2*par[2]*(h*k + k*l + h*l)); break; } case TETRAGONAL: { return 2*par[1]*(h*h + k*k); break; } case CUBIC: { return 2*par[1]*(h*h+k*k+l*l); break; } } } if(derivpar==(par+2)) { switch(mlattice) { case TRICLINIC: { return k*k; break; } case MONOCLINIC: { return 2*par[2]*k*k; break; } case ORTHOROMBIC: { return 2*par[2]*k*k; break; } case HEXAGONAL: { return 2*par[2]*l*l ; break; } case RHOMBOEDRAL: { return par[1]*par[1]*(h*h + k*k + l*l + 2*(h*k + k*l + h*l)); break; } case TETRAGONAL: { return 2*par[2]*l*l; break; } case CUBIC: { throw 0; break; } } } if(derivpar==(par+3)) { switch(mlattice) { case TRICLINIC: { return l*l; break; } case MONOCLINIC: { return 2*par[3]*l*l + 2*par[1]*par[4]*h*l; break; } case ORTHOROMBIC: { return 2*par[3]*l*l; break; } case HEXAGONAL: { throw 0; break; } case RHOMBOEDRAL: { throw 0; break; } case TETRAGONAL: { throw 0; break; } case CUBIC: { throw 0; break; } } } if(derivpar==(par+4)) { switch(mlattice) { case TRICLINIC: { return h*k; break; } case MONOCLINIC: { return 2*par[1]*par[3]*h*l; break; } default: { throw 0; break; } } } if(derivpar==(par+5)) { switch(mlattice) { case TRICLINIC: { return k*l; break; } default: { throw 0; break; } } } if(derivpar==(par+6)) { switch(mlattice) { case TRICLINIC: { return h*l; break; } default: { throw 0; break; } } } throw 0; return 0.0; } void RecUnitCell::hkl2d_delta(const float h,const float k,const float l, const RecUnitCell &delta, float & dmin, float &dmax) const { const float p0m=par[0]-delta.par[0] , p0p=par[0]+delta.par[0], p1m=par[1]-delta.par[1] , p1p=par[1]+delta.par[1], p2m=par[2]-delta.par[2] , p2p=par[2]+delta.par[2], p3m=par[3]-delta.par[3] , p3p=par[3]+delta.par[3], p4m=par[4]-delta.par[4] , p4p=par[4]+delta.par[4], p5m=par[5]-delta.par[5] , p5p=par[5]+delta.par[5], p6m=par[6]-delta.par[6] , p6p=par[6]+delta.par[6]; switch(mlattice) { case TRICLINIC: {//par[0]+par[1]*h*h + par[2]*k*k + par[3]*l*l + par[4]*h*k + par[5]*k*l + par[6]*h*l; float p4mm,p5mm,p6mm,p4pp,p5pp,p6pp; if((h*k)>0){p4mm=p4m;p4pp=p4p;}else{p4mm=p4p;p4pp=p4m;} if((k*l)>0){p5mm=p5m;p5pp=p5p;}else{p5mm=p5p;p5pp=p5m;} if((h*l)>0){p6mm=p6m;p6pp=p6p;}else{p6mm=p6p;p6pp=p6m;} dmin=p0m+p1m*h*h+p2m*k*k+p3m*l*l+p4mm*h*k+p5mm*k*l+p6mm*h*l; dmax=p0p+p1p*h*h+p2p*k*k+p3p*l*l+p4pp*h*k+p5pp*k*l+p6pp*h*l; /* if(dmin<0) { cout<<"hkl2d_delta: dmin<0 ! "<0) { dmin = p0m + p1m*p1m*h*h + p2m*p2m*k*k + p3m*p3m*l*l + 2*p1m*p3m*p4m*h*l; dmax = p0p + p1p*p1p*h*h + p2p*p2p*k*k + p3p*p3p*l*l + 2*p1p*p3p*p4p*h*l; return; } else { const bool b1=(h*(par[1]*h+par[3]*par[4]*l))>0;// d(d*^2)/dp1 const bool b3=(l*(par[3]*l+par[1]*par[4]*h))>0;// d(d*^2)/dp2 if(b1 && b3) { dmin = p0m + p1m*p1m*h*h + p2m*p2m*k*k + p3m*p3m*l*l + 2*p1m*p3m*p4p*h*l; dmax = p0p + p1p*p1p*h*h + p2p*p2p*k*k + p3p*p3p*l*l + 2*p1p*p3p*p4m*h*l; return; } else if(b1 && (!b3)) { dmin = p0m + p1m*p1m*h*h + p2m*p2m*k*k + p3p*p3p*l*l + 2*p1m*p3p*p4p*h*l; dmax = p0p + p1p*p1p*h*h + p2p*p2p*k*k + p3m*p3m*l*l + 2*p1p*p3m*p4m*h*l; return; } else if((!b1) && b3) { dmin = p0m + p1p*p1p*h*h + p2m*p2m*k*k + p3m*p3m*l*l + 2*p1p*p3m*p4p*h*l; dmax = p0p + p1m*p1m*h*h + p2p*p2p*k*k + p3p*p3p*l*l + 2*p1m*p3p*p4m*h*l; return; } else { dmin = p0m + p1p*p1p*h*h + p2m*p2m*k*k + p3p*p3p*l*l + 2*p1p*p3p*p4p*h*l; dmax = p0p + p1m*p1m*h*h + p2p*p2p*k*k + p3m*p3m*l*l + 2*p1m*p3m*p4m*h*l; return; } } } case ORTHOROMBIC: //OK { dmin= p0m + p1m*p1m*h*h + p2m*p2m*k*k + p3m*p3m*l*l; dmax= p0p + p1p*p1p*h*h + p2p*p2p*k*k + p3p*p3p*l*l; return; } case HEXAGONAL: //OK { dmin=p0m+p1m*p1m*(h*h + k*k + h*k)+ p2m*p2m*l*l ; dmax=p0p+p1p*p1p*(h*h + k*k + h*k)+ p2p*p2p*l*l ; return; } case RHOMBOEDRAL: { if((h*k + k*l + h*l)>=0) { dmin= p0m+p1m*p1m*(h*h + k*k + l*l + 2*p2m*(h*k + k*l + h*l)); dmax= p0p+p1p*p1p*(h*h + k*k + l*l + 2*p2p*(h*k + k*l + h*l)); } else { dmin= p0m+p1m*p1m*(h*h + k*k + l*l + 2*p2p*(h*k + k*l + h*l)); dmax= p0p+p1p*p1p*(h*h + k*k + l*l + 2*p2m*(h*k + k*l + h*l)); } return; } case TETRAGONAL: //OK { dmin= p0m + p1m*p1m*(h*h + k*k) + p2m*p2m*l*l; dmax= p0p + p1p*p1p*(h*h + k*k) + p2p*p2p*l*l; return; } case CUBIC: //OK { dmin=p0m + p1m*p1m*(h*h+k*k+l*l); dmax=p0p + p1p*p1p*(h*h+k*k+l*l); return; } } } vector RecUnitCell::DirectUnitCell(const bool equiv)const { // reciprocal unit cell parameters float aa,bb,cc,calphaa,cbetaa,cgammaa,salphaa,sbetaa,sgammaa; switch(mlattice) { case TRICLINIC: { aa=sqrt(par[1]); bb=sqrt(par[2]); cc=sqrt(par[3]); calphaa=par[5]/(2*bb*cc); cbetaa =par[6]/(2*aa*cc); cgammaa=par[4]/(2*aa*bb); salphaa=sqrt(abs(1-calphaa*calphaa)); sbetaa =sqrt(abs(1-cbetaa *cbetaa)); sgammaa=sqrt(abs(1-cgammaa*cgammaa)); break; } case MONOCLINIC: { aa=par[1]; bb=par[2]; cc=par[3]; calphaa=0; cbetaa=par[4]; cgammaa=0; salphaa=1; sbetaa =sqrt(abs(1-cbetaa *cbetaa)); sgammaa=1; break; } case ORTHOROMBIC: { aa=par[1]; bb=par[2]; cc=par[3]; calphaa=0; cbetaa =0; cgammaa=0; salphaa=1; sbetaa =1; sgammaa=1; break; } case HEXAGONAL: { aa=par[1]; bb=par[1]; cc=par[2]; calphaa=0; cbetaa =0; cgammaa=0.5; salphaa=1; sbetaa =1; sgammaa=0.8660254037844386; break; } case RHOMBOEDRAL: { aa=par[1]; bb=par[1]; cc=par[1]; calphaa=par[4]; cbetaa =par[4]; cgammaa=par[4]; salphaa=sqrt(abs(1-calphaa *calphaa)); sbetaa =salphaa; sgammaa=salphaa; break; } case TETRAGONAL: { aa=par[1]; bb=par[1]; cc=par[2]; calphaa=0; cbetaa =0; cgammaa=0; salphaa=1; sbetaa =1; sgammaa=1; break; } case CUBIC: { aa=par[1]; bb=par[1]; cc=par[1]; calphaa=0; cbetaa =0; cgammaa=0; salphaa=1; sbetaa =1; sgammaa=1; break; } // This should never happen. Avoid using unitialized cell parameters. default: throw 0; } // Volume of reciprocal unit cell const float vv=sqrt(abs(1-calphaa*calphaa-cbetaa*cbetaa-cgammaa*cgammaa+2*calphaa*cbetaa*cgammaa)); const float a=salphaa/(aa*vv); const float b=sbetaa /(bb*vv); const float c=sgammaa/(cc*vv); const float calpha=(cbetaa *cgammaa-calphaa)/(sbetaa *sgammaa); const float cbeta =(calphaa*cgammaa-cbetaa )/(salphaa*sgammaa); const float cgamma=(calphaa*cbetaa -cgammaa)/(salphaa*sbetaa ); const float alpha=acos( calpha ); const float beta =acos( cbeta ); const float gamma=acos( cgamma ); const float v=a*b*c*sqrt(1-calpha*calpha-cbeta*cbeta-cgamma*cgamma+2*calpha*cbeta*cgamma); vector par(7); par[0]=a; par[1]=b; par[2]=c; par[3]=alpha; par[4]=beta; par[5]=gamma; par[6]=v; return par; } ///////////////////////////////////////////////// PEAKLIST:HKL0 ///////////////////// PeakList::hkl0::hkl0(const int h0,const int k0, const int l0): h(h0),k(k0),l(l0) {} ///////////////////////////////////////////////// PEAKLIST:HKL ///////////////////// PeakList::hkl::hkl(const float d,const float i,const float ds,const float is, const int h0,const int k0, const int l0,const float dc0): dobs(d),dobssigma(ds),d2obs(d*d),d2obsmin((d-ds/2)*(d-ds/2)),d2obsmax((d+ds/2)*(d+ds/2)),iobs(i),iobssigma(is), h(h0),k(k0),l(l0),isIndexed(false),isSpurious(false),stats(0), d2calc(dc0),d2diff(0) {} bool compareHKL_d(const PeakList::hkl &d1, const PeakList::hkl &d2) { return d1.dobs < d2.dobs; } ///////////////////////////////////////////////// PEAKLIST ///////////////////// PeakList::PeakList() {} PeakList::PeakList(const PeakList &old) { *this=old; } void PeakList::operator=(const PeakList &rhs) { VFN_DEBUG_ENTRY("PeakList::operator=(PeakList &old)",10); mvHKL=rhs.mvHKL; VFN_DEBUG_EXIT("PeakList::operator=(PeakList &old)",10); } PeakList::~PeakList() {} void PeakList::ImportDhklDSigmaIntensity(istream &is,float defaultsigma) { float d,sigma,iobs; while(true) {// :TODO: use readline to make sure when the end is reached is >>d; cout<<__FILE__<<":"<<__LINE__<<" "<>sigma; if(is.good()==false) break; is>>iobs; if(sigma<=0) sigma=d*defaultsigma; if(iobs<=0) iobs=1.0; mvHKL.push_back(hkl(1/d,iobs,1/(d-sigma/2)-1/(d+sigma/2))); cout<<"+/-"<>d; if(is.eof()) break; is>>iobs; mvHKL.push_back(hkl(1/d,iobs)); cout<<__FILE__<<":"<<__LINE__<<" "< > v; float d; while(true) {// :TODO: use readline to make sure when the end is reached is >>d; if(is.eof()) break; mvHKL.push_back(hkl(1/d)); cout<<__FILE__<<":"<<__LINE__<<" "< bool comparePairFirst(std::pair &p1, std::pair &p2) { return p1.first < p2.first; } void PeakList::Import2ThetaIntensity(istream &is, const float wavelength) { std::list > v; float d,iobs; while(true) {// :TODO: use readline to make sure when the end is reached is >>d; if(is.eof()) break; is>>iobs; d=2*sin(d/2*DEG2RAD)/wavelength; mvHKL.push_back(hkl(1/d,iobs)); cout<<__FILE__<<":"<<__LINE__<<" "< vd2; for(int h=0;h<=20;h++) for(int k=-20;k<=20;k++) { if((h==0) && (k<0)) k=0; for(int l=-20;l<=20;l++) { if((h==0) && (k==0) && (l<=0)) l=1; vd2.push_back(sqrt(ruc.hkl2d(h,k,l))); } } // std::list::iterator pos=vd2.begin(); if(percentMissing>0.90) percentMissing=0.90; for(;pos!=vd2.end();++pos) { if((rand()/float(RAND_MAX))::const_iterator pos=mvHKL.begin();pos!=mvHKL.end();++pos) { const float sigma=1/(pos->dobs-pos->dobssigma/2)-1/(pos->dobs+pos->dobssigma/2); os<< std::fixed << setw(6) << setprecision(3) << 1/pos->dobs <<" "<< sigma <<" "<< std::scientific << pos->iobs <::const_iterator pos=mvHKL.begin();pos!=mvHKL.end();++pos) s+= pos->dobssigma; s/=mvHKL.size(); if(s>0) mvHKL.push_back(hkl(d,iobs,s,iobssigma,h,k,l,d2calc)); else mvHKL.push_back(hkl(d,iobs,1e-4,iobssigma,h,k,l,d2calc)); } else mvHKL.push_back(hkl(d,iobs,dobssigma,iobssigma,h,k,l,d2calc)); sort(mvHKL.begin(),mvHKL.end(),compareHKL_d); //this->Print(cout); } void PeakList::RemovePeak(unsigned int idx) { for(unsigned int i=idx;i<(mvHKL.size()-1);++i) mvHKL[i]=mvHKL[i+1]; mvHKL.pop_back(); } void PeakList::Print(std::ostream &os) const { unsigned int i=0; char buf[200]; os<<"PeakList, with "<::const_iterator pos=mvHKL.begin();pos!=mvHKL.end();++pos) { const float sigma=1/(pos->dobs-pos->dobssigma/2)-1/(pos->dobs+pos->dobssigma/2); if(pos->isIndexed) sprintf(buf,"#%3d d=%6.3f+/-%7.4f dcalc=%6.3f, diff=%7.4f, iobs=%6.3f HKL=%2d %2d %2d Spurious=%1d stats=%6lu", i++,1/pos->dobs,sigma, 1/sqrt(abs(pos->d2calc)),1/sqrt(abs(pos->d2calc))-1/pos->dobs, pos->iobs,pos->h,pos->k,pos->l,pos->isSpurious,pos->stats); else sprintf(buf,"#%3d d=%6.3f+/-%6.3f iobs=%6.3f UNINDEXED Spurious=%1d stats=%6lu", i++,1/pos->dobs,1/(pos->dobs-pos->dobssigma/2)-1/(pos->dobs+pos->dobssigma/2), pos->iobs,pos->isSpurious,pos->stats); os< & PeakList::GetPeakList(){return mvHKL;} const vector & PeakList::GetPeakList()const {return mvHKL;} /////////////////////////////////////////////////////// SCORE /////////////////////////////////////// float Score(const PeakList &dhkl, const RecUnitCell &rpar, const unsigned int nbSpurious, const bool verbose,const bool storehkl,const bool storePredictedHKL) { const bool autozero=false; vector::const_iterator pos,first,last; for(pos=dhkl.GetPeakList().begin();pos!=dhkl.GetPeakList().end();++pos) { if(storehkl) pos->isIndexed=false; pos->d2calc=0; pos->d2diff=1000; } const unsigned long nb=dhkl.GetPeakList().size(); if(storePredictedHKL) dhkl.mvPredictedHKL.clear(); unsigned long nbCalc=0; int h,k,l; float predict_coeff=1; if(storePredictedHKL)predict_coeff=2; const float dmax=dhkl.mvHKL[nb-1].d2obs*predict_coeff*1.05; int sk0,sl0;// do we need >0 *and* <0 indices for k,l ? switch(rpar.mlattice) { case TRICLINIC: sk0=-1;sl0=-1; break; case MONOCLINIC: sk0=1;sl0=-1; break; case ORTHOROMBIC: sk0=1;sl0=1; break; case HEXAGONAL: sk0=-1;sl0=1; break; case RHOMBOEDRAL: sk0=-1;sl0=-1; break; case TETRAGONAL: sk0=1;sl0=1; break; case CUBIC: sk0=1;sl0=1; break; // This should never happen. Avoid using unitialized values. default: throw 0; } int stepk,stepl;// steps in k,l to use for centered lattices switch(rpar.mCentering) { case LATTICE_P:stepk=1;stepl=1;break; case LATTICE_I:stepk=1;stepl=2;break; case LATTICE_A:stepk=1;stepl=2;break; case LATTICE_B:stepk=1;stepl=2;break; case LATTICE_C:stepk=2;stepl=1;break; case LATTICE_F:stepk=2;stepl=2;break; // This should never happen. Avoid using unitialized values. default: throw 0; } first=dhkl.GetPeakList().begin();last=dhkl.GetPeakList().end(); unsigned long nbCalcH,nbCalcK;// Number of calculated lines below dmax for each h,k for(h=0;;++h) { nbCalcH=0; for(int sk=sk0;sk<=1;sk+=2) { if(h==0) sk=1;// no need to explore 0kl with both sk -1 and 1 if(stepk==2) k=(h%2);// For LATTICE_C,LATTICE_F: h odd => k odd else k=0; for(;;k+=stepk) { nbCalcK=0; for(int sl=sl0;sl<=1;sl+=2) { if((h+k)==0) { sl=1;// No need to list 0 0 l with l<0 l=1; } else { if(h==0) { if(rpar.mlattice==MONOCLINIC) sl=1;// 0 k l and 0 k -l are equivalent if((sk<0)||(sl<0)) l=1;// Do not list 0 k 0 with k<0 else l=0;// h==k==0 already covered } else { if(sl<0) l=1;// Do not list h k 0 twice else l=0; } } if(stepl==2) { if(rpar.mCentering==LATTICE_I) l+=(h+k+l)%2; if(rpar.mCentering==LATTICE_A) l+=(k+l)%2;// Start at hk1 if k odd if( (rpar.mCentering==LATTICE_B) ||(rpar.mCentering==LATTICE_F)) l+=(h+l)%2;// Start at hk1 if h odd } for(;;l+=stepl) { const float d2=rpar.hkl2d(h,sk*k,sl*l); if(d2>dmax) { //cout<<__FILE__<<":"<<__LINE__<<" hkl: "<=0) break; else continue; } nbCalc++;nbCalcK++;nbCalcH++; if(storePredictedHKL) { dhkl.mvPredictedHKL.push_back(PeakList::hkl(0,0,0,0,h,sk*k,sl*l,d2)); //continue; } for(pos=first;pos!=last;++pos) { const float tmp=d2-pos->d2obs; if(tmp<.1) { if(tmp<-.1) break; if(fabs(tmp)d2diff)) { pos->d2diff=tmp; if(storehkl) { pos->h=h; pos->k=sk*k; pos->l=sl*l; pos->isIndexed=true; pos->d2calc=d2; } } /* if((verbose)&&(fabs(tmp)<.01)) cout<<__FILE__<<":"<<__LINE__<<" hkl: "< epsilon="<="< >::iterator pos=vRUC.begin();pos!=vRUC.end();++pos) { if(pos==bestpos) continue; for(unsigned int k=0;kfirst.par[k]=mMin[k]+mAmp[k]*rand()/(float)RAND_MAX; } } } /* for(vector >::iterator pos=vRUC.begin();pos!=vRUC.end();++pos) { // Final cost vector par=pos->first.DirectUnitCell(); cout<<__FILE__<<":"<<__LINE__<<" Trial: a="<mMinScoreReport*.5) { // Now, do a least-squares refinement on best mRecUnitCell=bestpos->first; this->LSQRefine(10,true,true); par=mRecUnitCell.DirectUnitCell(); score=Score(*mpPeakList,mRecUnitCell,mNbSpurious,false,true); cout<<__FILE__<<":"<<__LINE__<<" Best-LSQ: a="<RefinableObj::Print(); } unsigned int CellExplorer::GetNbLSQFunction() const {return 1;} const CrystVector_REAL& CellExplorer::GetLSQCalc(const unsigned int) const { VFN_DEBUG_ENTRY("CellExplorer::GetLSQCalc()",2) unsigned int j=0; for(vector::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) { if(pos->isIndexed) mCalc(j++)=mRecUnitCell.hkl2d(pos->h,pos->k,pos->l); } //cout<<__FILE__<<":"<<__LINE__<<"LSQCalc : Score:"<::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) { VFN_DEBUG_MESSAGE("CellExplorer::GetLSQDeriv():"<GetPeakList().size(),2) VFN_DEBUG_MESSAGE("CellExplorer::GetLSQDeriv():"<h<<","<k<<","<l,2) if(pos->isIndexed) mDeriv(j++)=mRecUnitCell.hkl2d(pos->h,pos->k,pos->l,par); } VFN_DEBUG_EXIT("CellExplorer::GetLSQDeriv()",2) return mDeriv; } void CellExplorer::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { VFN_DEBUG_ENTRY("CellExplorer::BeginOptimization()",5) Score(*mpPeakList,mRecUnitCell,mNbSpurious,false,true,false); const unsigned int nb=mpPeakList->GetPeakList().size(); mCalc.resize(nb-mNbSpurious); mObs.resize(nb-mNbSpurious); mWeight.resize(nb-mNbSpurious); mDeriv.resize(nb-mNbSpurious); int j=0; float thres=0.0; for(vector::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) if(thresiobs) thres=pos->iobs; thres/=10;// weight=1 for intensities up to Imax/10 //cout <<"Beginning optimization with reflexions:"<::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) { if(pos->isIndexed) { mObs(j)=pos->d2obs; if(mObs(j)>thres) mWeight(j)=1; else mWeight(j)=mObs(j)/thres; /* sprintf(buf,"#%2d (%3d %3d %3d) dobs=%6.3f dcalc=%6.3f iobs=%6.3f weight=%6.4f", i,mpPeakList->mvHKL[i].h,mpPeakList->mvHKL[i].k,mpPeakList->mvHKL[i].l, 1/mpPeakList->mvdobs[i],1/sqrt(mRecUnitCell.hkl2d(mpPeakList->mvHKL[i].h,mpPeakList->mvHKL[i].k,mpPeakList->mvHKL[i].l)), mpPeakList->mviobs[i],mWeight(j)); */ j++; } /* else { sprintf(buf,"#%2d (%3d %3d %3d) dobs=%6.3f dcalc=%6.3f iobs=%6.3f SPURIOUS", i,mpPeakList->mvHKL[i].h,mpPeakList->mvHKL[i].k,mpPeakList->mvHKL[i].l, 1/mpPeakList->mvdobs[i],1/sqrt(mRecUnitCell.hkl2d(mpPeakList->mvHKL[i].h,mpPeakList->mvHKL[i].k,mpPeakList->mvHKL[i].l)), mpPeakList->mviobs[i]); } cout<RefinableObj::BeginOptimization(allowApproximations,enableRestraints); VFN_DEBUG_EXIT("CellExplorer::BeginOptimization()",5) } void CellExplorer::LSQRefine(int nbCycle, bool useLevenbergMarquardt, const bool silent) { if(mNbLSQExcept>100) { if(!silent) cout<<"CellExplorer::LSQRefine(): LSQ was disabled, too many (>100) exceptions caught. Weird unit cell parameters ?"; return; } VFN_DEBUG_ENTRY("CellExplorer::LSQRefine()",5) mLSQObj.SetRefinedObj(*this); mLSQObj.PrepareRefParList(true); //this->BeginOptimization(); //cout<(this->GetLSQObs(0),this->GetLSQCalc(0),this->GetLSQWeight(0),this->GetLSQDeriv(0,this->GetPar((long)0)))<100) cout<<"WARNING CellExplorer::LSQRefine(): LSQ was disabled, too many (>100) exceptions caught. Weird unit cell parameters ?"<Print(cout); VFN_DEBUG_EXIT("CellExplorer::LSQRefine()",5) } /** Number of reflexions found in the intervals calculated between par+dpar and par-dpar * * \param useStoredHKL: * - if equal to 0, explore all possible hkl values to find possible Miller indices. * - if useStoredHKL=1, use the Miller indices already stored in hkl.vDicVolHKL * for each observed line as the only possible indices. * - if useStoredHKL=2, search all the possible Miller indices for all reflections * and store them in hkl.vDicVolHKL for each observed line. * \param maxNbMissingBelow5: the maximum number of lines that have been calculated before * the d-value of the 5th observed line, but which have not been observed. * If nbMissingBelow5>0 and more than nbMissingBelow5 lines have not been observed, * return false. Recommended to speed up triclinic, with nbMissingBelow5=5 */ bool DichoIndexed(const PeakList &dhkl, const RecUnitCell &par,const RecUnitCell &dpar, const unsigned int nbUnindexed=0,const bool verbose=false,unsigned int useStoredHKL=0, const unsigned int maxNbMissingBelow5=0) { const unsigned int nb=dhkl.GetPeakList().size(); int nbIndexed=nb-nbUnindexed;// Number of reflections we require to be indexed float d5=0; if(maxNbMissingBelow5>0) d5=dhkl.GetPeakList()[4].d2obs; // number of missing reflections calculated below 5th observed line unsigned int nbMissingBelow5=0; // List of indexed reflections vector::const_iterator pos,first,last,end; if(useStoredHKL==1) {// We already now possible Miller indices for all reflections unsigned int nbUnIx = 0; for(pos=dhkl.GetPeakList().begin();pos!=dhkl.GetPeakList().end();++pos) { pos->isIndexed=false; for(list::const_iterator phkl0=pos->vDicVolHKL.begin();phkl0!=pos->vDicVolHKL.end();++phkl0) { float d0,d1; par.hkl2d_delta(phkl0->h,phkl0->k,phkl0->l,dpar,d0,d1); if((pos->d2obsmax>=d0) && (d1>=pos->d2obsmin)) { pos->d2calc=(d0+d1)/2; pos->isIndexed=true; if(--nbIndexed==0) return true; break; } } if(!(pos->isIndexed)) if(++nbUnIx>nbUnindexed) return false; } return false; } const bool storePossibleHKL=(useStoredHKL==2); if(storePossibleHKL) for(pos=dhkl.GetPeakList().begin();pos!=dhkl.GetPeakList().end();++pos) { pos->isIndexed=false; pos->vDicVolHKL.clear(); } else for(pos=dhkl.GetPeakList().begin();pos!=dhkl.GetPeakList().end();++pos) pos->isIndexed=false; int h,k,l; float dmax=dhkl.GetPeakList()[nb-1].d2obs; float dmin=dhkl.GetPeakList()[0 ].d2obs; int sk0,sl0;// do we need >0 *and* <0 indices for k,l ? switch(par.mlattice) { case TRICLINIC: sk0=-1;sl0=-1; break; case MONOCLINIC: { sk0=1;sl0=-1; break; } case ORTHOROMBIC: sk0=1;sl0=1; break; case HEXAGONAL: sk0=-1;sl0=1; break; case RHOMBOEDRAL: sk0=-1;sl0=-1; break; case TETRAGONAL: sk0=1;sl0=1; break; case CUBIC: sk0=1;sl0=1; break; // This should never happen. Avoid using unitialized values. default: throw 0; } int stepk,stepl;// steps in k,l to use for centered lattices switch(par.mCentering) { case LATTICE_P:stepk=1;stepl=1;break; case LATTICE_I:stepk=1;stepl=2;break; case LATTICE_A:stepk=1;stepl=2;break; case LATTICE_B:stepk=1;stepl=2;break; case LATTICE_C:stepk=2;stepl=1;break; case LATTICE_F:stepk=2;stepl=2;break; // This should never happen. Avoid using unitialized values. default: throw 0; } //RecUnitCell par0(par),par1(par); //for(unsigned int i=0;i<7;++i) {par0.par[i]-=dpar.par[i];par1.par[i]+=dpar.par[i];} //currently first & last unindexed dhkl first=dhkl.GetPeakList().begin(),last=dhkl.GetPeakList().end(),end=dhkl.GetPeakList().end(); unsigned long nbCalcH,nbCalcK;// Number of calculated lines below dmax for each h,k for(h=0;;++h) { if(verbose) cout<<"H="< k odd else k=0; for(;;k+=stepk) { if(verbose) cout<<"K="<dmax) { if(par.mlattice==TRICLINIC) { // Must check that d is increasing with l, otherwise we still need to increase it if(verbose) cout<<"L?="<< par.hkl2d(h,sk*k,sl*l,NULL,3)*sl <<", dmax="<0) break; } else break; } bool missing=(d00); for(pos=first;pos!=end;++pos) { if(pos==last) break; if((!storePossibleHKL)&&(pos->isIndexed)&&missing) continue; const float d2obs=pos->d2obs,d2obsmin=pos->d2obsmin, d2obsmax=pos->d2obsmax; if((d2obsmax>=d0) && (d1>=d2obsmin)) { missing=false; if(!(pos->isIndexed)) { pos->d2calc=(d0+d1)/2; --nbIndexed; pos->isIndexed=true; } if(verbose) cout<vDicVolHKL.push_back(PeakList::hkl0(h,sk*k,sl*l)); else { if((!storePossibleHKL)&&(nbIndexed==0)) return true; if(pos==first){first++;dmin=first->d2obsmin;} if(pos==last){last--;dmax=last->d2obsmax;} } } } if(missing) if(++nbMissingBelow5>=maxNbMissingBelow5)return false; } } if(nbCalcK==0) break;// && ((par.hkl2d(h,sk*k,0,NULL,2)*sk)>0)) break; // k too large } } if(nbCalcH==0) break;//h too large } if(verbose) { dhkl.Print(cout); } return nbIndexed<=0; } float CellExplorer::GetBestScore()const{return mBestScore;} const std::list >& CellExplorer::GetSolutions()const {return mvSolution;} std::list >& CellExplorer::GetSolutions() {return mvSolution;} unsigned int CellExplorer::RDicVol(RecUnitCell par0,RecUnitCell dpar, unsigned int depth,unsigned long &nbCalc,const float minV,const float maxV,vector vdepth) { static bool localverbose=false; if(mlattice==TRICLINIC) { const float p1=par0.par[1] , p2=par0.par[2] , p3=par0.par[3] , p4=par0.par[4] , p5=par0.par[5] , p6=par0.par[6]; const float p1m=p1-dpar.par[1], p2m=p2-dpar.par[2], p3m=p3-dpar.par[3], p4m=p4-dpar.par[4], p5m=p5-dpar.par[5], p6m=p6-dpar.par[6]; const float p1p=p1+dpar.par[1], p2p=p2+dpar.par[2], p3p=p3+dpar.par[3], p4p=p4+dpar.par[4], p5p=p5+dpar.par[5], p6p=p6+dpar.par[6]; // a*p2p)||(p2m>p3p)) return 0; // max/min absolute values for p4,p5,p6 if((p4m>p1p)||(-p4p>p1p)) return 0;//abs(p4) b* < b*+/-a* if((p5m>p2p)||(-p5p>p2p)) return 0;//abs(p5) c* < c*+/-b* if((p6m>p1p)||(-p6p>p1p)) return 0;//abs(p6) c* < c*+/-a* const float max6=p1p+p2p-p4m-p5m; if((p6m>max6)||(-p6p>max6)) return 0;//abs(p6) c* < c*+/-a*+/-b* float p6mm,p6pp,p5mm,p5pp,p4mm,p4pp; // p6pp: smaller V*, larger V, etc.. // derivative of V*^2 with p6 if((p4*p5-2*p2*p6)>0) {p6pp=p6p;p6mm=p6m;} else{p6pp=p6m;p6mm=p6p;} // derivative of V*^2 with p5 if((p4*p6-2*p1*p5)>0) {p5pp=p5p;p5mm=p5m;} else{p5pp=p5m;p5mm=p5p;} // derivative of V*^2 with p5 if((p5*p6-2*p3*p4)>0) {p4pp=p4p;p4mm=p4m;} else{p4pp=p4m;p4mm=p4p;} //const float vmin0=1/sqrt(abs(p1p*p2p*p3p*(1-p5mm*p5mm/(4*p2p*p3p)-p6mm*p6mm/(4*p1p*p3p)-p4mm*p4mm/(4*p1p*p2p)+p4mm*p5mm*p6mm/(4*p1m*p2m*p3m)))); //const float vmax0=1/sqrt(abs(p1m*p2m*p3m*(1-p5pp*p5pp/(4*p2m*p3m)-p6pp*p6pp/(4*p1m*p3m)-p4pp*p4pp/(4*p1m*p2m)+p4pp*p5pp*p6pp/(4*p1m*p2m*p3m)))); const float vmin0=1/sqrt(abs(p1p*p2p*p3p*(1-p5mm*p5mm/(4*p2p*p3p)-p6mm*p6mm/(4*p1p*p3p)-p4mm*p4mm/(4*p1p*p2p)+p4mm*p5mm*p6mm/(4*p1m*p2m*p3m)))); const float vmax0=1/sqrt(abs(p1m*p2m*p3m*(1-p5pp*p5pp/(4*p2m*p3m)-p6pp*p6pp/(4*p1m*p3m)-p4pp*p4pp/(4*p1m*p2m)+p4pp*p5pp*p6pp/(4*p1m*p2m*p3m)))); if((vmin0>maxV)||(vmax00)&&(depth<=2))// test if volume is within range { RecUnitCell parm=par0,parp=par0; for(unsigned int i=0;i<6;++i) {parm.par[i]-=dpar.par[i];parp.par[i]+=dpar.par[i];} vector parmd=parm.DirectUnitCell(); vector parpd=parp.DirectUnitCell(); if((parpd[6]>maxV)||(parmd[6]=4, try adding a zero ? if( (!indexed) && (depth>=4)) {//:TODO: Check if this is OK ! Vary value with depth dpar.par[0]=.0001; indexed=DichoIndexed(*mpPeakList,par0,dpar,mNbSpurious,false,useStoredHKL,maxMissingBelow5); //if(indexed) cout<<"Added zero - SUCCESS !"<::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();) { if(pos->vDicVolHKL.size()==1) { const PeakList::hkl0 h0=pos->vDicVolHKL.front(); if(++pos==mpPeakList->GetPeakList().end()) break; if(pos->vDicVolHKL.size()==1) { const PeakList::hkl0 h1=pos->vDicVolHKL.front(); if((h0.h==h1.h)&&(h0.k==h1.k)&&(h0.l==h1.l)) nbident++; if(nbident>mNbSpurious) {indexed=false;break;} } } else ++pos; } } // if we can zoom in for one parameter directly, we need per-parameter depth if(vdepth.size()==0) { vdepth.resize(mnpar-1); for(vector::iterator pos=vdepth.begin();pos!=vdepth.end();) *pos++=depth; } else for(vector::iterator pos=vdepth.begin();pos!=vdepth.end();++pos) if(*pos > vq0(3); for(unsigned int i=0;i<3;++i) {vq0[i].first=0;vq0[i].second=0.0;} RecUnitCell par0orig=par0,dparorig=dpar; for(vector::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) { if(pos->vDicVolHKL.size()==1) { const PeakList::hkl0 h0=pos->vDicVolHKL.front(); if((h0.k==0)&&(h0.l==0)) {vq0[0].first+=1 ; vq0[0].second+=pos->dobs/h0.h;} else if((h0.h==0)&&(h0.l==0)) {vq0[1].first+=1 ; vq0[1].second+=pos->dobs/h0.k;} else if((h0.h==0)&&(h0.k==0)) {vq0[2].first+=1 ; vq0[2].second+=pos->dobs/h0.l;if(localverbose) cout<=2)) { vector shifts(mpPeakList->GetPeakList().size()); vector::const_iterator peakpos=mpPeakList->GetPeakList().begin(); for(vector::iterator spos=shifts.begin();spos!=shifts.end();) { *spos++ = peakpos->d2diff * (float)(peakpos->isIndexed&&(!peakpos->isSpurious));peakpos++;} sort(shifts.begin(),shifts.end()); par0.par[0]=shifts[mpPeakList->GetPeakList().size()/2];//use median value indexed=DichoIndexed(*mpPeakList,par0,dpar,mNbSpurious); if(indexed) cout<<"Failed Dicho ? Trying auto-zero shifting :Worked !"<=5) { RecUnitCell parm=par0,parp=par0; for(unsigned int i=0;i<6;++i) {parm.par[i]-=dpar.par[i];parp.par[i]+=dpar.par[i];} vector parmd=parm.DirectUnitCell(); vector parpd=parp.DirectUnitCell(); char buf[200]; sprintf(buf,"a=%5.2f-%5.2f b=%5.2f-%5.2f c=%5.2f-%5.2f alpha=%5.2f-%5.2f beta=%5.2f-%5.2f gamma=%5.2f-%5.2f V=%5.2f-%5.2f", parpd[0],parmd[0],parpd[1],parmd[1],parpd[2],parmd[2],parpd[3]*RAD2DEG,parmd[3]*RAD2DEG, parpd[4]*RAD2DEG,parmd[4]*RAD2DEG,parpd[5]*RAD2DEG,parmd[5]*RAD2DEG,parpd[6],parmd[6]); for(unsigned int i=0;idepth)); for(int i0=-1;i0<=1;i0+=2) { //:TODO: dichotomy on zero shift ? if(localverbose) cout<<__FILE__<<":"<<__LINE__<<":"<=mDicVolDepthReport)) { mRecUnitCell=par0; vector par=mRecUnitCell.DirectUnitCell(); float score=Score(*mpPeakList,mRecUnitCell,mNbSpurious,false,true,false); // If we already have enough reports at higher depths (depth+2), don't bother record this one bool report=true; if(depth<(mMaxDicVolDepth-1)) if(mvNbSolutionDepth[depth+2]>100)report=false; if(report && (((score>(mMinScoreReport*.5))&&(depth>=mDicVolDepthReport)) || (depth>=mMaxDicVolDepth))) { if(false)//score>) mBestScore//((score>mMinScoreReport)||(depth>=mDicVolDepthReport)) cout<<__FILE__<<":"<<__LINE__<<" Depth="<1100)&&(rand()%1000==0)) { cout<ReduceSolutions(true);// This will update the min report score cout<<"-> "< linspace(float min, float max,unsigned int nb) { vector v(nb); for(unsigned int i=0;iInit(); if(minDepth>mMaxDicVolDepth) mMaxDicVolDepth=minDepth; mvNbSolutionDepth.resize(mMaxDicVolDepth+1); for(unsigned int i=0;i<=mMaxDicVolDepth;++i) mvNbSolutionDepth[i]=0; float latstep=0.5, vstep=(mVolumeMax-mVolumeMin)/(ceil((mVolumeMax-mVolumeMin)/500)-0.0001); mCosAngMax=abs(cos(mAngleMax)); const float cosangstep=mCosAngMax/(ceil(mCosAngMax/.08)-.0001); if(((mVolumeMax-mVolumeMin)/vstep)>10) vstep=(mVolumeMax-mVolumeMin)/9.999; if(((mLengthMax-mLengthMin)/latstep)>25) latstep=(mLengthMax-mLengthMin)/24.9999; cout<"<"<"< >::iterator bestpos; bool breakDepth=false; // In the triclinic case, first try assigning a* and b* from the first reflections if(false) //mlattice==TRICLINIC) for(float minv=mVolumeMin;minvmVolumeMax)maxv=mVolumeMax; cout<<"Starting: V="<"<GetPeakList()[0].d2obs ;p2=mpPeakList->GetPeakList()[1].d2obs ; break; case 1: p1=mpPeakList->GetPeakList()[0].d2obs ;p2=mpPeakList->GetPeakList()[2].d2obs ; break; case 2: p1=mpPeakList->GetPeakList()[1].d2obs/2;p2=mpPeakList->GetPeakList()[0].d2obs ; break; case 3: p1=mpPeakList->GetPeakList()[1].d2obs/2;p2=mpPeakList->GetPeakList()[2].d2obs ; break; case 4: p1=mpPeakList->GetPeakList()[2].d2obs/2;p2=mpPeakList->GetPeakList()[0].d2obs ; break; case 5: p1=mpPeakList->GetPeakList()[2].d2obs/2;p2=mpPeakList->GetPeakList()[1].d2obs ; break; } //if(i>0) exit(0); if(p1>p2) continue; cout<<"Trying #"<0) for(unsigned int i=stopOnDepth; i1) {breakDepth=true;break;} if((mBestScore>stopOnScore)&&(breakDepth)) break; }//cases cout<<"Finished triclinic QUICK tests for: V="<"<"< v1=linspace(mLengthMin,mLengthMax,nbstep); const float lstep=v1[1]-v1[0]; for(unsigned int i1=0;i1<(nbstep-1);++i1) { const float p1 =(1/(v1[i1]*v1[i1])+1/(v1[i1+1]*v1[i1+1]))/2; const float dp1=(1/(v1[i1]*v1[i1])-1/(v1[i1+1]*v1[i1+1]))/2; //cout<<"p1="< v2=linspace(mLengthMin,v1[i1+1],nb2); //for(unsigned int i2=0;i2 v4=linspace(0,p1+dp1,nb4); for(unsigned int i4=0;i4<(nb4-1);++i4) { const float p4 =(v4[i4+1]+v4[i4])/2; const float dp4=(v4[i4+1]-v4[i4])/2; //cout<<" p4="< v5=linspace(0,p2+dp2,nb5); for(unsigned int i5=0;i5<(nb5-1);++i5) { const float p5 =(v5[i5+1]+v5[i5])/2; const float dp5=(v5[i5+1]-v5[i5])/2; //cout<<" p5="<(p1+dp1)) vmax6=p1+dp1; if(vmax6<0) continue; const unsigned int nb6=int((2*vmax6)/(4*dp1)+2.001); vector v6=linspace(-vmax6,vmax6,nb6); //cout<<" p6="< parlarged,parsmalld; latstep=(mLengthMax-mLengthMin)/24.999; for(float x4=0;x4x1) break;// | c * cos(beta) | maxv) break; const float largev=(x1+latstep)*(x2+latstep)*(x3+latstep)*(sinbeta+cosangstep); if(largevminv)) { //cout<mLengthMax) break; } break; } case RHOMBOEDRAL: //:TODO: { latstep=(mLengthMax-mLengthMin)/24.999; for(float x1=mLengthMin;x1<(mLengthMax+latstep);x1+=latstep) { for(float x2=0;x2 par=par0.DirectUnitCell(); if((par[6]minv)) { RDicVol(par0,dpar,0,nbCalc,minv,maxv); } } } break; } case TETRAGONAL: { vector parlarged,parsmalld;// Small & large UC in direct space latstep=(mLengthMax-mLengthMin)/24.999; for(float x1=mLengthMin;x1minv)) { RDicVol(par0,dpar,0,nbCalc,minv,maxv); } if(parsmalld[6]>maxv) break; } if((x1*mLengthMin*mLengthMin)>maxv) break; } break; } case CUBIC: { latstep=(mLengthMax-mLengthMin)/24.999; cout<maxv)break; if(vmax>minv) RDicVol(par0,dpar,0,nbCalc,minv,maxv); } break; } } cout<<"Finished: V="<"< >::iterator pos=mvSolution.begin();pos!=mvSolution.end();++pos) { const float score=pos->second;//Score(*mpPeakList,pos->first,mNbSpurious); if(score>bestscore) {bestscore=score;bestpos=pos;} } bool breakDepth=false; if(stopOnDepth>0) for(unsigned int i=stopOnDepth; i1) {breakDepth=true;break;} if((bestscore>stopOnScore)&&(breakDepth)) break; } /* {// Tag spurious lines vector vSpuriousScore; for(vector::const_iterator pos=mpPeakList->GetPeakList().begin();pos!=mpPeakList->GetPeakList().end();++pos) vSpuriousScore.push_back(pos->stats); sort(vSpuriousScore.begin(),vSpuriousScore.end()); const int threshold=vSpuriousScore[vSpuriousScore.size()/2]*5; for(vector::iterator pos=mpPeakList->mvHKL.begin();pos!=mpPeakList->mvHKL.end();++pos) if(pos->stats > threshold) pos->isSpurious=true; else pos->isSpurious=false; mpPeakList->Print(cout); } */ this->ReduceSolutions(true); bestscore=0;bestpos=mvSolution.end(); for(list >::iterator pos=mvSolution.begin();pos!=mvSolution.end();++pos) { const float score=Score(*mpPeakList,pos->first,mNbSpurious); if(score>bestscore) {bestpos=pos;bestscore=score;} vector par=pos->first.DirectUnitCell(); cout<<__FILE__<<":"<<__LINE__<<" Solution ? a="< par0=c0.DirectUnitCell(); vector par1=c1.DirectUnitCell(); float diff=0; for(unsigned int i=0;i<6;++i) diff += abs(par0[i]-par1[i]); return (diff/6) &p1, std::pair &p2) { return p1.second > p2.second; } void CellExplorer::ReduceSolutions(const bool updateReportThreshold) { const bool verbose=false; std::list > vSolution2; // TODO: take into account number of spurious lines for cutoff value. // keep only solutions above mBestScore/5 for(list >::iterator pos=mvSolution.begin();pos!=mvSolution.end();) { if(pos->second<(mBestScore/5)) pos=mvSolution.erase(pos); else ++pos; } if(updateReportThreshold&& ((mBestScore/5)>mMinScoreReport)) { cout<<"CellExplorer::ReduceSolutions(): update threshold for report from " <0) { vSolution2.push_back(mvSolution.front()); mvSolution.pop_front(); vector par=vSolution2.back().first.DirectUnitCell(); if(verbose) cout<<__FILE__<<":"<<__LINE__<<" SOLUTION: a="< >::iterator pos=mvSolution.begin();pos!=mvSolution.end();) { if(SimilarRUC(pos->first,vSolution2.back().first)) { par=pos->first.DirectUnitCell(); if(verbose) cout<<__FILE__<<":"<<__LINE__<<" 1: a="<first.mlattice) { if(pos->second>vSolution2.back().second) vSolution2.back()=*pos; } else if(vSolution2.back().first.mlatticefirst.mlattice) vSolution2.back()=*pos; pos=mvSolution.erase(pos); } else { par=pos->first.DirectUnitCell(); if(verbose) cout<<__FILE__<<":"<<__LINE__<<" 0: a="<100) { mvSolution.resize(100); if(updateReportThreshold && (mvSolution.back().second>mMinScoreReport)) { cout<<"CellExplorer::ReduceSolutions(): update threshold for report from " <nb;++i) // cout<<__FILE__<<":"<<__LINE__<<":d*="<mvdobs[i]<<", d*^2="<mvd2obs[i]< >::iterator pos; const float min_latt=1./mLengthMax; const float max_latt=1./mLengthMin; const float amp_crossp=abs(cos(mAngleMax)); //mMin[0]=-.002;mAmp[0]=.004; mMin[0]=.00;mAmp[0]=.00; switch(mlattice) { case TRICLINIC: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=min_latt;mAmp[2]=max_latt-min_latt; mMin[3]=min_latt;mAmp[3]=max_latt-min_latt; mMin[4]=0;mAmp[4]=amp_crossp; mMin[5]=0;mAmp[5]=amp_crossp; mMin[6]=0;mAmp[6]=amp_crossp; mnpar=7; break; case MONOCLINIC: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=min_latt;mAmp[2]=max_latt-min_latt; mMin[3]=min_latt;mAmp[3]=max_latt-min_latt; mMin[4]=0;mAmp[4]=amp_crossp; mnpar=5; break; case ORTHOROMBIC: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=min_latt;mAmp[2]=max_latt-min_latt; mMin[3]=min_latt;mAmp[3]=max_latt-min_latt; mnpar=4; break; case HEXAGONAL: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=min_latt;mAmp[2]=max_latt-min_latt; mnpar=3; break; case RHOMBOEDRAL: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=-amp_crossp;mAmp[2]=2*amp_crossp; mnpar=3; break; case TETRAGONAL: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mMin[2]=min_latt;mAmp[2]=max_latt-min_latt; mnpar=3; break; case CUBIC: mMin[1]=min_latt;mAmp[1]=max_latt-min_latt; mnpar=2; break; } //for(unsigned int k=0;k"<ResetParList(); { RefinablePar tmp("Zero",mRecUnitCell.par+0,-0.01,0.01,gpRefParTypeObjCryst,REFPAR_DERIV_STEP_ABSOLUTE, true,false,true,false); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } char buf [50]; string str="Reciprocal unit cell par #"; for(unsigned int i=0;iAddPar(tmp); } for(unsigned int i=nb1;i<(nb1+nb2);++i) { sprintf(buf,"%i",i); RefinablePar tmp(str+(string)buf,mRecUnitCell.par+i+1, 0.0,0.5,gpRefParTypeObjCryst,REFPAR_DERIV_STEP_ABSOLUTE, false,false,true,false); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Indexing.h000066400000000000000000000322201417150057700227610ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2006- Vincent Favre-Nicolin vincefn@users.sourceforge.net 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for Indexing classes & functions * */ #ifndef _OBJCRYST_INDEXING_H_ #define _OBJCRYST_INDEXING_H_ #include #include #include #include #include #include #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/RefinableObj/LSQNumObj.h" #include "ObjCryst/ObjCryst/PowderPattern.h" namespace ObjCryst { /** Different lattice types. * */ enum CrystalSystem { TRICLINIC, MONOCLINIC, ORTHOROMBIC, HEXAGONAL, RHOMBOEDRAL, TETRAGONAL, CUBIC}; enum CrystalCentering { LATTICE_P,LATTICE_I,LATTICE_A,LATTICE_B,LATTICE_C,LATTICE_F}; /** Estimate volume from number of peaks at a given dmin * See J. Appl. Cryst. 20 (1987), 161 * * \param dmin,dmax: 1/d limits between which the number of reflections has been observed * \param nbrefl: number of observed reflections * \param kappa: estimated percentage of reflections actually observed (default=1.0) */ float EstimateCellVolume(const float dmin, const float dmax, const float nbrefl, const CrystalSystem system,const CrystalCentering centering,const float kappa=1); /** Lightweight class describing the reciprocal unit cell, for the fast computation of d*_hkl^2. * * */ class RecUnitCell { public: RecUnitCell(const float zero=0,const float par0=0,const float par1=0,const float par2=0, const float par3=0,const float par4=0,const float par5=0,CrystalSystem lattice=CUBIC, const CrystalCentering cent=LATTICE_P, const unsigned int nbspurious=0); RecUnitCell(const RecUnitCell &old); void operator=(const RecUnitCell &rhs); // access to ith parameter //float operator[](const unsigned int i); /// Compute d*^2 for hkl reflection /// if deriv != -1, compute derivate versus the corresponding parameter /// /// If derivhkl=1,2,3, compute derivative versus h,k or l. float hkl2d(const float h,const float k,const float l,REAL *derivpar=NULL,const unsigned int derivhkl=0) const; /// Compute d*^2 for one hkl reflection: this functions computes a d*^2 range (min,max) /// for a given range of unit cell parameter (given in the delta parameter) around the /// current parameters. /// /// Used for DicVol algorithm void hkl2d_delta(const float h,const float k,const float l,const RecUnitCell &delta, float & dmin, float &dmax) const; /** Compute real space unit cell from reciprocal one * *\param equiv: if true, return real unit cell \e equivalent to the one computed from the reciprocal one, * so that alpha, beta and gamma are larger or equal to pi/2, and minimum. This is done * by adding multiples of \b a to \b b and multiples of \b a and \b b to \b c. */ std::vector DirectUnitCell(const bool equiv=false)const; /** The 6 parameters defining 1/d_hkl^2 = d*_hkl^2, for different crystal classes, from: * d*_hkl^2 = zero + a*^2 h^2 + b*^2 k^2 + c*^2 l^2 + 2 a*.b* hk + 2 b*.c* kl + 2 a*.c* hl * * for triclinic: * d*_hkl^2 = par[0] + par[1] h^2 + par[1] k^2 + par[2]^2 l^2 + par[3] hk + par[4] kl + par[5] hl * for monoclinic: * d*_hkl^2 = zero + par[0]^2 h^2 + par[1]^2 k^2 + par[2]^2 l^2 + par[0]*par[2]*par[3] hl * for orthorombic: * d*_hkl^2 = zero + par[0]^2 h^2 + par[1]^2 k^2 + par[2]^2 l^2 * for hexagonal: * d*_hkl^2 = zero + par[0]^2 h^2 + par[0]^2 k^2 + par[2]^2 l^2 + sqrt(3)/2*par[0]^2 hk * for rhomboedral: * d*_hkl^2 = zero + par[0]^2 h^2 + par[1]^2 k^2 + par[2]^2 l^2 + par[3] (hk + kl + hl) * for quadratic: * d*_hkl^2 = zero + par[0]^2 h^2 + par[0]^2 k^2 + par[1]^2 l^2 * for cubic * d*_hkl^2 = zero + par[0]^2 (h^2 + k^2 + l^2) */ REAL par[7]; CrystalSystem mlattice; CrystalCentering mCentering; /// The number of spurious lines used to match this RecUnitCell unsigned int mNbSpurious; }; /** Class to store positions of observed reflections. * * */ class PeakList { public: PeakList(); PeakList(const PeakList &old); void operator=(const PeakList &rhs); ~PeakList(); void ImportDhklDSigmaIntensity(std::istream &is,float defaultsigma=.001); void ImportDhklIntensity(std::istream &is); void ImportDhkl(std::istream &is); void Import2ThetaIntensity(std::istream &is, const float wavelength=1.5418); /** Generate a list of simulated peak positions, from given lattice parameters * * \param zero: the zero, given for d*^2 (in Angstroems^-2) * \param a,b,c,alpha,beta,gamma: lattice parameters * \param deg: if true, angles are in degrees instead of radians * \param nb: the number of peak positions to generate * \param nbspurious: number of spurious lines to be included in the list * \param sigma: the maximum relative error for d* - the d* values will be within [d_calc*(1-sigma) ;d_calc*(1+sigma)] * \param percentMissing: percentage (between 0 and 1) of missing reflections - maximum allowed 0.9 * \param verbose: print some info * \return: the volume of the simulated unit cell */ float Simulate(float zero, float a, float b, float c, float alpha, float beta, float gamma, bool deg, unsigned int nb=20, unsigned int nbspurious=0, float sigma=0, float percentMissing=0, const bool verbose=false); void ExportDhklDSigmaIntensity(std::ostream &out)const; /// Add one peak ///\param d: 1/d for this peak (Angstroem) void AddPeak(const float d, const float iobs=1.0,const float dobssigma=0.0,const float iobssigma=0.0, const int h=0,const int k=0, const int l=0,const float d2calc=0); void RemovePeak(unsigned int i); void Print(std::ostream &os) const; /// One set of Miller indices, a possible indexation for a reflection struct hkl0 { hkl0(const int h=0,const int k=0, const int l=0); /// Miller indices int h,k,l; }; /** One observed diffraction line, to be indexed * */ struct hkl { hkl(const float dobs=1.0,const float iobs=0.0,const float dobssigma=0.0,const float iobssigma=0.0, const int h=0,const int k=0, const int l=0,const float d2calc=0); /// Observed peak position 1/d float dobs; /// Error on peak position float dobssigma; /// Observed peak position 1/d^2 float d2obs; /// Min value for observed peak position 1/(d+disgma/2)^2 float d2obsmin; /// Min value for observed peak position 1/(d-disgma/2)^2 float d2obsmax; /// Observed peak intensity float iobs; /// Error on observed peak intensity float iobssigma; /// Miller indices, after line is indexed mutable int h,k,l; /// Possible Miller indices, stored during a dichotomy search. mutable std::list vDicVolHKL; /// Is this line indexed ? mutable bool isIndexed; /// Is this an impurity line ? mutable bool isSpurious; /// Indexing statistics mutable unsigned long stats; /// Calculated position, 1/d^2 mutable float d2calc; /// 1/d^2 difference, obs-calc mutable float d2diff; }; /// Get peak list vector & GetPeakList(); /// Get peak list const vector & GetPeakList()const ; /// Predict peak positions /// Best h,k,l for each observed peak (for least-squares refinement) /// This is stored by the Score function, optionnally. mutable vectormvHKL; /// Full list of calculated HKL positions for a given solution, up to a given resolution /// After finding a candidate solution, use score with pPredictedHKL=&mvPredictedHKL mutable list mvPredictedHKL; }; /// Compute score for a candidate RecUnitCell and a PeakList float Score(const PeakList &dhkl, const RecUnitCell &ruc, const unsigned int nbSpurious=0, const bool verbose=false,const bool storehkl=false, const bool storePredictedHKL=false); /** Algorithm class to find the correct indexing from observed peak positions. * */ class CellExplorer:public RefinableObj { public: CellExplorer(const PeakList &dhkl, const CrystalSystem lattice, const unsigned int nbSpurious); void Evolution(unsigned int ng,const bool randomize=true,const float f=0.7,const float cr=0.5,unsigned int np=100); void SetLengthMinMax(const float min,const float max); void SetAngleMinMax(const float min,const float max); void SetVolumeMinMax(const float min,const float max); void SetNbSpurious(const unsigned int nb); /// Allowed error on 1/d (squared!), used for dicvol void SetD2Error(const float err); void SetMinMaxZeroShift(const float min,const float max); void SetCrystalSystem(const CrystalSystem system); void SetCrystalCentering(const CrystalCentering cent); virtual const string& GetClassName() const; virtual const string& GetName() const; virtual void Print() const; virtual unsigned int GetNbLSQFunction() const; virtual const CrystVector_REAL& GetLSQCalc(const unsigned int) const; virtual const CrystVector_REAL & GetLSQObs(const unsigned int) const; virtual const CrystVector_REAL & GetLSQWeight(const unsigned int) const; virtual const CrystVector_REAL & GetLSQDeriv(const unsigned int, RefinablePar &); virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); void LSQRefine(int nbCycle=1, bool useLevenbergMarquardt=true, const bool silent=false); /// Run DicVOl algorithm, store only solutions with score >minScore or depth>=minDepth, /// stop at the end of one volume interval (~400 A^3) if best score>stopOnScore, /// or if one solution was found at depth>=stopOnDepth /// /// If stopOnDepth==0, do not stop for any depth void DicVol(const float minScore=10,const unsigned int minDepth=3,const float stopOnScore=50.0,const unsigned int stopOnDepth=6); /** Sort all solutions by score, remove duplicates * * \param updateReportThreshold: if true, when too many solutions are produced, * the threshold above which solutions are reported will be updated to get less solutions. */ void ReduceSolutions(const bool updateReportThreshold=false); float GetBestScore()const; const std::list >& GetSolutions()const; std::list >& GetSolutions(); private: unsigned int RDicVol(RecUnitCell uc0, RecUnitCell uc1, unsigned int depth,unsigned long &nbCalc,const float minV,const float maxV,vector vdepth=vector()); void Init(); /// Max number of obs reflections to use std::list > mvSolution; unsigned int mnpar; const PeakList *mpPeakList; float mLengthMin,mLengthMax; float mAngleMin,mAngleMax; float mVolumeMin,mVolumeMax; float mZeroShiftMin,mZeroShiftMax; /// Min values for all parameters (7=unit cell +zero) float mMin[7]; /// Max amplitude (max=min+amplitude) for all parameters /// All parameters are treated as periodic for DE (??) float mAmp[7]; /// Lattice type for which we search CrystalSystem mlattice; /// Centering type CrystalCentering mCentering; unsigned int mNbSpurious; float mD2Error; LSQNumObj mLSQObj; mutable CrystVector_REAL mObs; mutable CrystVector_REAL mCalc; mutable CrystVector_REAL mWeight; mutable CrystVector_REAL mDeriv; /// Reciprocal unit cell used for least squares refinement RecUnitCell mRecUnitCell; /// Current best score float mBestScore; /// Number of solutions found during dicvol search, at each depth. std::vector mvNbSolutionDepth; float mMinScoreReport; unsigned int mMaxDicVolDepth,mDicVolDepthReport; /// Stored value of cos(max ang) for tricilinic search - we do /// not want to recompute the cos at every dicvol iteration mutable float mCosAngMax; /// Number of exceptions caught during LSQ, in a given search - above 20 LSQ is disabled unsigned int mNbLSQExcept; }; }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Molecule.cpp000066400000000000000000011534741417150057700233340ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2009 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Molecule.cpp * Source file for the Molecule scatterer * */ #include #include #include #include #include #include #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/ObjCryst/Molecule.h" #include "ObjCryst/ObjCryst/ZScatterer.h" #include "ObjCryst/RefinableObj/GlobalOptimObj.h" #ifdef OBJCRYST_GL #ifdef __DARWIN__ #include #else #include #endif #endif #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxMolecule.h" #endif //#include // Try new approach for rigid bodies ? #define RIGID_BODY_STRICT_EXPERIMENTAL // Tighter restraints x**2+x**4+x**6 instead of just X**2 #undef RESTRAINT_X2_X4_X6 using namespace std; namespace ObjCryst { XYZ::XYZ(REAL x0,REAL y0,REAL z0):x(x0),y(y0),z(z0){}; REAL GetBondLength(const MolAtom&at1,const MolAtom&at2) { //TAU_PROFILE("GetBondLength()","REAL (...)",TAU_DEFAULT); /* __m128 m128=_mm_set_ps(0.0f, at1.GetZ()-at2.GetZ(), at1.GetY()-at2.GetY(), at1.GetX()-at2.GetX()); __m128 a = _mm_mul_ps(m128,m128); // horizontal add __m128 b = _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0,0,0,0)), _mm_add_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1,1,1,1)), _mm_shuffle_ps(a, a, _MM_SHUFFLE(2,2,2,2)))); union m128_float { __m128 m128; struct { float x, y, z, pad; }; }; union m128_float l; l.m128 = _mm_sqrt_ss(b); return l.x; */ return sqrt( (at1.GetX()-at2.GetX()) *(at1.GetX()-at2.GetX()) +(at1.GetY()-at2.GetY()) *(at1.GetY()-at2.GetY()) +(at1.GetZ()-at2.GetZ()) *(at1.GetZ()-at2.GetZ()) ); } REAL GetBondAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3) { //TAU_PROFILE("GetBondAngle()","REAL (...)",TAU_DEFAULT); const REAL x21=at1.GetX()-at2.GetX(); const REAL y21=at1.GetY()-at2.GetY(); const REAL z21=at1.GetZ()-at2.GetZ(); const REAL x23=at3.GetX()-at2.GetX(); const REAL y23=at3.GetY()-at2.GetY(); const REAL z23=at3.GetZ()-at2.GetZ(); const REAL norm21_norm23= sqrt( (x21*x21+y21*y21+z21*z21) *(x23*x23+y23*y23+z23*z23)+1e-6); const REAL angle=(x21*x23+y21*y23+z21*z23)/norm21_norm23; if(angle>=1) return 0; if(angle<=-1) return M_PI; return acos(angle); } REAL GetDihedralAngle(const MolAtom &at1,const MolAtom &at2,const MolAtom &at3,const MolAtom &at4) { //TAU_PROFILE("GetDihedralAngle()","REAL (...)",TAU_DEFAULT); const REAL x21=at1.GetX()-at2.GetX(); const REAL y21=at1.GetY()-at2.GetY(); const REAL z21=at1.GetZ()-at2.GetZ(); const REAL x34=at4.GetX()-at3.GetX(); const REAL y34=at4.GetY()-at3.GetY(); const REAL z34=at4.GetZ()-at3.GetZ(); const REAL x23=at3.GetX()-at2.GetX(); const REAL y23=at3.GetY()-at2.GetY(); const REAL z23=at3.GetZ()-at2.GetZ(); // v21 x v23 const REAL x123= y21*z23-z21*y23; const REAL y123= z21*x23-x21*z23; const REAL z123= x21*y23-y21*x23; // v32 x v34 (= -v23 x v34) const REAL x234= -(y23*z34-z23*y34); const REAL y234= -(z23*x34-x23*z34); const REAL z234= -(x23*y34-y23*x34); const REAL norm123_norm234= sqrt( (x123*x123+y123*y123+z123*z123) *(x234*x234+y234*y234+z234*z234)+1e-6); REAL angle=(x123*x234+y123*y234+z123*z234)/norm123_norm234; if(angle>= 1) angle=0; else { if(angle<=-1) angle=M_PI; else angle=acos(angle); } if((x21*x234 + y21*y234 + z21*z234)<0) return -angle; return angle; } void ExpandAtomGroupRecursive(MolAtom* atom, const map > &connect, set &atomlist,const MolAtom* finalAtom) { const pair::iterator,bool> status=atomlist.insert(atom); if(false==status.second) return; if(finalAtom==atom) return; map >::const_iterator c=connect.find(atom); set::const_iterator pos; for(pos=c->second.begin();pos!=c->second.end();++pos) { ExpandAtomGroupRecursive(*pos,connect,atomlist,finalAtom); } } void ExpandAtomGroupRecursive(MolAtom* atom, const map > &connect, map &atomlist,const unsigned long maxdepth,unsigned long depth) { if(atomlist.count(atom)>0) if(atomlist[atom]<=depth) return; atomlist[atom]=depth; if(depth==maxdepth) return;//maxdepth reached map >::const_iterator c=connect.find(atom); set::const_iterator pos; for(pos=c->second.begin();pos!=c->second.end();++pos) { ExpandAtomGroupRecursive(*pos,connect,atomlist,maxdepth,depth+1); } } //###################################################################### // // MolAtom // //###################################################################### MolAtom::MolAtom(const REAL x, const REAL y, const REAL z, const ScatteringPower *pPow, const string &name, Molecule &parent): mName(name),mX(x),mY(y),mZ(z),mOccupancy(1.),mpScattPow(pPow),mpMol(&parent),mIsInRing(false),mIsNonFlipAtom(false) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_MESSAGE("MolAtom::MolAtom()",4) } MolAtom::~MolAtom() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } void MolAtom::SetName(const string &name) { mName=name; // Set parameter's name in the parent molecule // The atom should already be part of a Molecule, but just in case be careful if((mName!="") && (mpMol!=0)) { try { mpMol->GetPar(&mX).SetName(mpMol->GetName()+"_"+mName+"_x"); mpMol->GetPar(&mY).SetName(mpMol->GetName()+"_"+mName+"_y"); mpMol->GetPar(&mZ).SetName(mpMol->GetName()+"_"+mName+"_z"); } catch(const ObjCrystException &except) { cerr<<"MolAtom::SetName(): Atom parameters not yet declared in a Molecule ?"<GetAtomPositionClock().Click();} void MolAtom::SetY(const REAL a)const{ mY=a;mpMol->GetAtomPositionClock().Click();} void MolAtom::SetZ(const REAL a)const{ mZ=a;mpMol->GetAtomPositionClock().Click();} void MolAtom::SetOccupancy(const REAL a){ mOccupancy=a;} bool MolAtom::IsDummy()const{return mpScattPow==0;} const ScatteringPower& MolAtom::GetScatteringPower()const{return *mpScattPow;} void MolAtom::SetScatteringPower(const ScatteringPower& pow) { if(mpScattPow!=&pow) { mpScattPow=&pow; this->GetMolecule().GetAtomScattPowClock().Click(); } } void MolAtom::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("MolAtom::XMLOutput()",4) for(int i=0;iGetName()); if(!this->IsDummy())tag.AddAttribute("ScattPow",this->GetScatteringPower().GetName()); { stringstream ss; ss.precision(os.precision()); ss <GetCrystal().GetScatteringPower(tag.GetAttributeValue(i))); } if("x"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mX; } if("y"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mY; } if("z"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mZ; } if("Occup"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mOccupancy; } if("NonFlip"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mIsNonFlipAtom; } } this->SetName(name); VFN_DEBUG_EXIT("MolAtom::XMLInput()",7) } void MolAtom::SetIsInRing(const bool r)const{mIsInRing=r;} bool MolAtom::IsInRing()const{return mIsInRing;} void MolAtom::SetNonFlipAtom(const bool nonflip) { // :KLUDGE: should be using a specific clock ? if(mIsNonFlipAtom != nonflip) this->GetMolecule().GetRigidGroupClock().Click(); mIsNonFlipAtom = nonflip; } bool MolAtom::IsNonFlipAtom() const { return mIsNonFlipAtom; } size_t MolAtom::int_ptr() const {return (size_t)this;} #ifdef __WX__CRYST__ WXCrystObjBasic* MolAtom::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("MolAtom::WXCreate()",5) mpWXCrystObj=new WXMolAtom(parent,this); VFN_DEBUG_EXIT("MolAtom::WXCreate()",5) return mpWXCrystObj; } WXCrystObjBasic* MolAtom::WXGet(){return mpWXCrystObj;} void MolAtom::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;} void MolAtom::WXNotifyDelete(){mpWXCrystObj=0;} #endif //###################################################################### // // MolBond // //###################################################################### MolBond::MolBond(MolAtom &atom1, MolAtom &atom2, const REAL length0, const REAL sigma, const REAL delta, Molecule &parent,const REAL bondOrder): mAtomPair(make_pair(&atom1,&atom2)), mLength0(length0),mDelta(delta),mSigma(sigma), mBondOrder(bondOrder),mIsFreeTorsion(false),mpMol(&parent) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif {} MolBond::~MolBond() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } const Molecule& MolBond::GetMolecule()const{return *mpMol;} Molecule& MolBond::GetMolecule() {return *mpMol;} string MolBond::GetName()const {return this->GetAtom1().GetName()+"-"+this->GetAtom2().GetName();} void MolBond::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("MolBond::XMLOutput()",4) for(int i=0;iGetName()); tag.AddAttribute("Atom2",mAtomPair.second->GetName()); { stringstream ss; ss.precision(os.precision()); ss <GetAtom(tag.GetAttributeValue(i))); } if("Atom2"==tag.GetAttributeName(i)) { mAtomPair.second=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Length"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mLength0; } if("Delta"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mDelta; } if("Sigma"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mSigma; } if("BondOrder"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mBondOrder; } if("FreeTorsion"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mIsFreeTorsion; } } VFN_DEBUG_EXIT("MolBond::XMLInput():",7) } REAL MolBond::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);} REAL MolBond::GetLogLikelihood(const bool calcDeriv, const bool recalc)const { if(!recalc) return mLLK; VFN_DEBUG_ENTRY("MolBond::GetLogLikelihood():",2) //TAU_PROFILE("MolBond::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT); //const REAL length=this->GetLength(); const REAL x=this->GetAtom2().GetX()-this->GetAtom1().GetX(); const REAL y=this->GetAtom2().GetY()-this->GetAtom1().GetY(); const REAL z=this->GetAtom2().GetZ()-this->GetAtom1().GetZ(); const REAL length=sqrt(abs(x*x+y*y+z*z)); if(calcDeriv) { const REAL tmp2=1/(length+1e-10); mDerivAtom1.x=-x*tmp2; mDerivAtom1.y=-y*tmp2; mDerivAtom1.z=-z*tmp2; mDerivAtom2.x=-mDerivAtom1.x; mDerivAtom2.y=-mDerivAtom1.y; mDerivAtom2.z=-mDerivAtom1.z; } if(mSigma<1e-6) { if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; return 0; } mLLK=length-(mLength0+mDelta); if(mLLK>0) { mLLK /= mSigma; if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2) return mLLK; } mLLK=length-(mLength0-mDelta); if(mLLK<0) { mLLK /= mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2) return mLLK; } if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; VFN_DEBUG_EXIT("MolBond::GetLogLikelihood():",2) return mLLK; } REAL MolBond::GetDeriv(const map &m, const bool llk)const { //TAU_PROFILE("MolBond::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT); REAL d=0; map::const_iterator pos; pos=m.find(mAtomPair.first); if(pos!=m.end()) d+= pos->second.x*mDerivAtom1.x +pos->second.y*mDerivAtom1.y +pos->second.z*mDerivAtom1.z; pos=m.find(mAtomPair.second); if(pos!=m.end()) d+= pos->second.x*mDerivAtom2.x +pos->second.y*mDerivAtom2.y +pos->second.z*mDerivAtom2.z; if(llk) return mDerivLLKCoeff*d; return d; } void MolBond::CalcGradient(std::map &m)const { this->GetLogLikelihood(true,true); map::iterator pos; pos=m.find(mAtomPair.first); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z; } pos=m.find(mAtomPair.second); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z; } #if 0 // Display gradient - for tests cout<GetName()<<" :LLK"<::const_iterator pos=m.begin();pos!=m.end();++pos) { char buf[100]; sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)", pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z); cout<GetAtom2()); } REAL MolBond::GetLength0()const{return mLength0;} REAL MolBond::GetLengthDelta()const{return mDelta;} REAL MolBond::GetLengthSigma()const{return mSigma;} REAL MolBond::GetBondOrder()const{return mBondOrder;} REAL& MolBond::Length0(){return mLength0;} REAL& MolBond::LengthDelta(){return mDelta;} REAL& MolBond::LengthSigma(){return mSigma;} REAL& MolBond::BondOrder(){return mBondOrder;} void MolBond::SetLength0(const REAL a){mLength0=a;} void MolBond::SetLengthDelta(const REAL a){mDelta=a;} void MolBond::SetLengthSigma(const REAL a){mSigma=a;} void MolBond::SetBondOrder(const REAL a){mBondOrder=a;} bool MolBond::IsFreeTorsion()const{return mIsFreeTorsion;} void MolBond::SetFreeTorsion(const bool isFreeTorsion) { if(mIsFreeTorsion==isFreeTorsion) return; mIsFreeTorsion=isFreeTorsion; mpMol->GetBondListClock().Click(); } size_t MolBond::int_ptr() const {return (size_t)this;} #ifdef __WX__CRYST__ WXCrystObjBasic* MolBond::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("MolBond::WXCreate()",5) mpWXCrystObj=new WXMolBond(parent,this); VFN_DEBUG_EXIT("MolBond::WXCreate()",5) return mpWXCrystObj; } WXCrystObjBasic* MolBond::WXGet(){return mpWXCrystObj;} void MolBond::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;} void MolBond::WXNotifyDelete(){mpWXCrystObj=0;} #endif //###################################################################### // // MolBondAngle // //###################################################################### MolBondAngle::MolBondAngle(MolAtom &atom1,MolAtom &atom2,MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent): mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { mvpAtom.push_back(&atom1); mvpAtom.push_back(&atom2); mvpAtom.push_back(&atom3); } MolBondAngle::~MolBondAngle() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } const Molecule& MolBondAngle::GetMolecule()const{return *mpMol;} Molecule& MolBondAngle::GetMolecule() {return *mpMol;} string MolBondAngle::GetName()const { return this->GetAtom1().GetName()+"-" +this->GetAtom2().GetName()+"-" +this->GetAtom3().GetName(); } void MolBondAngle::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("MolBondAngle::XMLOutput()",4) for(int i=0;iGetAtom1().GetName()); tag.AddAttribute("Atom2",this->GetAtom2().GetName()); tag.AddAttribute("Atom3",this->GetAtom3().GetName()); { stringstream ss; ss.precision(os.precision()); ss <GetAtom(tag.GetAttributeValue(i))); } if("Atom2"==tag.GetAttributeName(i)) { mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Atom3"==tag.GetAttributeName(i)) { mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Angle"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mAngle0; mAngle0*=DEG2RAD; } if("Delta"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mDelta; mDelta*=DEG2RAD; } if("Sigma"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mSigma; mSigma*=DEG2RAD; } } VFN_DEBUG_EXIT("MolBondAngle::XMLInput():",4) } REAL& MolBondAngle::Angle0() { return mAngle0; } REAL& MolBondAngle::AngleDelta(){return mDelta;} REAL& MolBondAngle::AngleSigma(){return mSigma;} REAL MolBondAngle::GetAngle0()const{return mAngle0;} REAL MolBondAngle::GetAngleDelta()const{return mDelta;} REAL MolBondAngle::GetAngleSigma()const{return mSigma;} void MolBondAngle::SetAngle0(const REAL angle){mAngle0=angle;} void MolBondAngle::SetAngleDelta(const REAL delta){mDelta=delta;} void MolBondAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;} REAL MolBondAngle::GetAngle()const { return GetBondAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3()); } REAL MolBondAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);} REAL MolBondAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const { if(!recalc) return mLLK; VFN_DEBUG_ENTRY("MolBondAngle::GetLogLikelihood():",2) //TAU_PROFILE("MolBondAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT); //const REAL angle=this->GetAngle(); const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX(); const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY(); const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ(); const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX(); const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY(); const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ(); const REAL n1=sqrt(abs(x21*x21+y21*y21+z21*z21)); const REAL n3=sqrt(abs(x23*x23+y23*y23+z23*z23)); const REAL p=x21*x23+y21*y23+z21*z23; const REAL a0=p/(n1*n3+1e-10); REAL angle; if(a0>=1) angle=0; else { if(a0<=-1) angle=M_PI; else angle=acos(a0); } if(calcDeriv) { const REAL s=1/(sqrt(1-a0*a0+1e-6)); const REAL s0=-s/(n1*n3+1e-10); const REAL s1= s*p/(n3*n1*n1*n1+1e-10); const REAL s3= s*p/(n1*n3*n3*n3+1e-10); mDerivAtom1.x=s0*x23+s1*x21; mDerivAtom1.y=s0*y23+s1*y21; mDerivAtom1.z=s0*z23+s1*z21; mDerivAtom3.x=s0*x21+s3*x23; mDerivAtom3.y=s0*y21+s3*y23; mDerivAtom3.z=s0*z21+s3*z23; mDerivAtom2.x=-(mDerivAtom1.x+mDerivAtom3.x); mDerivAtom2.y=-(mDerivAtom1.y+mDerivAtom3.y); mDerivAtom2.z=-(mDerivAtom1.z+mDerivAtom3.z); } if(mSigma<1e-6) { if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; return 0; } mLLK=angle-(mAngle0+mDelta); if(mLLK>0) { mLLK/=mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2) return mLLK; } mLLK=angle-(mAngle0-mDelta); if(mLLK<0) { mLLK/=mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2) return mLLK; } VFN_DEBUG_EXIT("MolBondAngle::GetLogLikelihood():",2) if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; return mLLK; } REAL MolBondAngle::GetDeriv(const std::map &m,const bool llk)const { //TAU_PROFILE("MolBondAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT); REAL d=0; map::const_iterator pos; pos=m.find(mvpAtom[0]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom1.x +pos->second.y*mDerivAtom1.y +pos->second.z*mDerivAtom1.z; pos=m.find(mvpAtom[1]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom2.x +pos->second.y*mDerivAtom2.y +pos->second.z*mDerivAtom2.z; pos=m.find(mvpAtom[2]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom3.x +pos->second.y*mDerivAtom3.y +pos->second.z*mDerivAtom3.z; if(llk) return mDerivLLKCoeff*d; return d; } void MolBondAngle::CalcGradient(std::map &m)const { this->GetLogLikelihood(true,true); map::iterator pos; pos=m.find(mvpAtom[0]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z; } pos=m.find(mvpAtom[1]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z; } pos=m.find(mvpAtom[2]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z; } #if 0 // Display gradient - for tests cout<GetName()<<" :LLK"<::const_iterator pos=m.begin();pos!=m.end();++pos) { char buf[100]; sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)", pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z); cout<::const_iterator MolBondAngle::begin() const {return mvpAtom.begin();} vector::const_iterator MolBondAngle::end() const {return mvpAtom.end();} size_t MolBondAngle::int_ptr() const {return (size_t)this;} #ifdef __WX__CRYST__ WXCrystObjBasic* MolBondAngle::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("MolBondAngle::WXCreate()",5) mpWXCrystObj=new WXMolBondAngle(parent,this); VFN_DEBUG_EXIT("MolBondAngle::WXCreate()",5) return mpWXCrystObj; } WXCrystObjBasic* MolBondAngle::WXGet(){return mpWXCrystObj;} void MolBondAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;} void MolBondAngle::WXNotifyDelete(){mpWXCrystObj=0;} #endif //###################################################################### // // MolDihedralAngle // //###################################################################### MolDihedralAngle::MolDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent): mAngle0(angle),mDelta(delta),mSigma(sigma),mpMol(&parent) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_ENTRY("MolDihedralAngle::MolDihedralAngle()",5) mvpAtom.push_back(&atom1); mvpAtom.push_back(&atom2); mvpAtom.push_back(&atom3); mvpAtom.push_back(&atom4); // We want the angle in [-pi;pi] mAngle0=fmod((REAL)mAngle0,(REAL)(2*M_PI)); if(mAngle0<(-M_PI)) mAngle0+=2*M_PI; if(mAngle0>M_PI) mAngle0-=2*M_PI; VFN_DEBUG_EXIT("MolDihedralAngle::MolDihedralAngle()",5) } MolDihedralAngle::~MolDihedralAngle() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } const Molecule& MolDihedralAngle::GetMolecule()const{return *mpMol;} Molecule& MolDihedralAngle::GetMolecule() {return *mpMol;} string MolDihedralAngle::GetName()const { return this->GetAtom1().GetName()+"-" +this->GetAtom2().GetName()+"-" +this->GetAtom3().GetName()+"-" +this->GetAtom4().GetName(); } void MolDihedralAngle::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("MolDihedralAngle::XMLOutput()",4) for(int i=0;iGetAtom1().GetName()); tag.AddAttribute("Atom2",this->GetAtom2().GetName()); tag.AddAttribute("Atom3",this->GetAtom3().GetName()); tag.AddAttribute("Atom4",this->GetAtom4().GetName()); { stringstream ss; ss.precision(os.precision()); ss <GetAtom(tag.GetAttributeValue(i))); } if("Atom2"==tag.GetAttributeName(i)) { mvpAtom[1]=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Atom3"==tag.GetAttributeName(i)) { mvpAtom[2]=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Atom4"==tag.GetAttributeName(i)) { mvpAtom[3]=&(mpMol->GetAtom(tag.GetAttributeValue(i))); } if("Angle"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mAngle0; mAngle0*=DEG2RAD; } if("Delta"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mDelta; mDelta*=DEG2RAD; } if("Sigma"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mSigma; mSigma*=DEG2RAD; } } VFN_DEBUG_EXIT("MolDihedralAngle::XMLInput():",5) } REAL MolDihedralAngle::GetAngle()const { //Get the angle [2pi] closest to the restraint const REAL angle=GetDihedralAngle(this->GetAtom1(),this->GetAtom2(),this->GetAtom3(),this->GetAtom4()); if((angle-mAngle0)>M_PI) return angle-2*M_PI; else if((angle-mAngle0)<(-M_PI)) return angle+2*M_PI; return angle; } REAL& MolDihedralAngle::Angle0(){return mAngle0;} REAL& MolDihedralAngle::AngleDelta(){return mDelta;} REAL& MolDihedralAngle::AngleSigma(){return mSigma;} REAL MolDihedralAngle::GetAngle0()const{return mAngle0;} REAL MolDihedralAngle::GetAngleDelta()const{return mDelta;} REAL MolDihedralAngle::GetAngleSigma()const{return mSigma;} void MolDihedralAngle::SetAngle0(const REAL angle){mAngle0=angle;} void MolDihedralAngle::SetAngleDelta(const REAL delta){mDelta=delta;} void MolDihedralAngle::SetAngleSigma(const REAL sigma){mSigma=sigma;} REAL MolDihedralAngle::GetLogLikelihood()const{return this->GetLogLikelihood(false,true);} REAL MolDihedralAngle::GetLogLikelihood(const bool calcDeriv, const bool recalc)const { if(!recalc) return mLLK; VFN_DEBUG_ENTRY("MolDihedralAngle::GetLogLikelihood():",2) //TAU_PROFILE("MolDihedralAngle::GetLogLikelihood()","REAL (bool,bool)",TAU_DEFAULT); const REAL x21=this->GetAtom1().GetX()-this->GetAtom2().GetX(); const REAL y21=this->GetAtom1().GetY()-this->GetAtom2().GetY(); const REAL z21=this->GetAtom1().GetZ()-this->GetAtom2().GetZ(); const REAL x34=this->GetAtom4().GetX()-this->GetAtom3().GetX(); const REAL y34=this->GetAtom4().GetY()-this->GetAtom3().GetY(); const REAL z34=this->GetAtom4().GetZ()-this->GetAtom3().GetZ(); const REAL x23=this->GetAtom3().GetX()-this->GetAtom2().GetX(); const REAL y23=this->GetAtom3().GetY()-this->GetAtom2().GetY(); const REAL z23=this->GetAtom3().GetZ()-this->GetAtom2().GetZ(); // v21 x v23 const REAL x123= y21*z23-z21*y23; const REAL y123= z21*x23-x21*z23; const REAL z123= x21*y23-y21*x23; // v32 x v34 (= -v23 x v34) const REAL x234= -(y23*z34-z23*y34); const REAL y234= -(z23*x34-x23*z34); const REAL z234= -(x23*y34-y23*x34); const REAL n123= sqrt(x123*x123+y123*y123+z123*z123+1e-7); const REAL n234= sqrt(x234*x234+y234*y234+z234*z234+1e-6); const REAL p=x123*x234+y123*y234+z123*z234; const REAL a0=p/(n123*n234+1e-10); REAL angle; if(a0>= 1) angle=0; else { if(a0<=-1) angle=M_PI; else angle=acos(a0); } REAL sgn=1.0; if((x21*x34 + y21*y34 + z21*z34)<0) {angle=-angle;sgn=-1;} if(calcDeriv) { const REAL s=sgn/(sqrt(1-a0*a0+1e-6)); const REAL s0=-s/(n123*n234+1e-10); const REAL s1= s*p/(n234*n123*n123*n123+1e-10); const REAL s3= s*p/(n123*n234*n234*n234+1e-10); mDerivAtom1.x=s0*(-z23*y234+y23*z234)+s1*(-z23*y123+y23*z123); mDerivAtom1.y=s0*(-x23*z234+z23*x234)+s1*(-x23*z123+z23*x123); mDerivAtom1.z=s0*(-y23*x234+x23*y234)+s1*(-y23*x123+x23*y123); mDerivAtom4.x=s0*(-z23*y123+y23*z123)+s3*(-z23*y234+y23*z234); mDerivAtom4.y=s0*(-x23*z123+z23*x123)+s3*(-x23*z234+z23*x234); mDerivAtom4.z=s0*(-y23*x123+x23*y123)+s3*(-y23*x234+x23*y234); mDerivAtom2.x=s0*((z23-z21)*y234-y123*z34+(y21-y23)*z234+z123*y34)+s1*(y123*(z23-z21)+z123*(y21-y23))+s3*(-y234*z34+z234*y34); mDerivAtom2.y=s0*((x23-x21)*z234-z123*x34+(z21-z23)*x234+x123*z34)+s1*(z123*(x23-x21)+x123*(z21-z23))+s3*(-z234*x34+x234*z34); mDerivAtom2.z=s0*((y23-y21)*x234-x123*y34+(x21-x23)*y234+y123*x34)+s1*(x123*(y23-y21)+y123*(x21-x23))+s3*(-x234*y34+y234*x34); mDerivAtom3.x=-(mDerivAtom1.x+mDerivAtom2.x+mDerivAtom4.x); mDerivAtom3.y=-(mDerivAtom1.y+mDerivAtom2.y+mDerivAtom4.y); mDerivAtom3.z=-(mDerivAtom1.z+mDerivAtom2.z+mDerivAtom4.z); } if(mSigma<1e-6) { if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; return mLLK; } mLLK=angle-(mAngle0+mDelta); if(mLLK<(-M_PI)) mLLK += 2*M_PI; if(mLLK> M_PI ) mLLK -= 2*M_PI; if(mLLK>0) { mLLK/=mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2) return mLLK; } mLLK=angle-(mAngle0-mDelta); if(mLLK<(-M_PI)) mLLK += 2*M_PI; if(mLLK> M_PI ) mLLK -= 2*M_PI; if(mLLK<0) { mLLK/=mSigma; #ifdef RESTRAINT_X2_X4_X6 const float mLLK2=mLLK*mLLK; //if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2+6*mLLK2*mLLK2)/mSigma; //mLLK=mLLK2*(1+mLLK2+mLLK2*mLLK2); if(calcDeriv) mDerivLLKCoeff=(2*mLLK+4*mLLK2)/mSigma; mLLK=mLLK2*(1+mLLK2); #else if(calcDeriv) mDerivLLKCoeff=2*mLLK/mSigma; mLLK *= mLLK; #endif VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2) return mLLK; } VFN_DEBUG_EXIT("MolDihedralAngle::GetLogLikelihood():",2) if(calcDeriv) mDerivLLKCoeff=0; mLLK=0; return 0; } REAL MolDihedralAngle::GetDeriv(const std::map &m,const bool llk)const { //TAU_PROFILE("MolDihedralAngle::GetDeriv()","REAL (mak,bool)",TAU_DEFAULT); REAL d=0; map::const_iterator pos; pos=m.find(mvpAtom[0]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom1.x +pos->second.y*mDerivAtom1.y +pos->second.z*mDerivAtom1.z; pos=m.find(mvpAtom[1]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom2.x +pos->second.y*mDerivAtom2.y +pos->second.z*mDerivAtom2.z; pos=m.find(mvpAtom[2]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom3.x +pos->second.y*mDerivAtom3.y +pos->second.z*mDerivAtom3.z; pos=m.find(mvpAtom[3]); if(pos!=m.end()) d+= pos->second.x*mDerivAtom4.x +pos->second.y*mDerivAtom4.y +pos->second.z*mDerivAtom4.z; if(llk) return mDerivLLKCoeff*d; return d; } void MolDihedralAngle::CalcGradient(std::map &m)const { this->GetLogLikelihood(true,true); map::iterator pos; pos=m.find(mvpAtom[0]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom1.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom1.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom1.z; } pos=m.find(mvpAtom[1]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom2.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom2.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom2.z; } pos=m.find(mvpAtom[2]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom3.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom3.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom3.z; } pos=m.find(mvpAtom[3]); if(pos!=m.end()) { pos->second.x+=mDerivLLKCoeff*mDerivAtom4.x; pos->second.y+=mDerivLLKCoeff*mDerivAtom4.y; pos->second.z+=mDerivLLKCoeff*mDerivAtom4.z; } #if 0 // Display gradient - for tests cout<GetName()<<" :LLK"<::const_iterator pos=m.begin();pos!=m.end();++pos) { char buf[100]; sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)", pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z); cout<::const_iterator MolDihedralAngle::begin() const {return mvpAtom.begin();} vector::const_iterator MolDihedralAngle::end() const {return mvpAtom.end();} size_t MolDihedralAngle::int_ptr() const {return (size_t)this;} #ifdef __WX__CRYST__ WXCrystObjBasic* MolDihedralAngle::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("MolDihedralAngle::WXCreate()",5) mpWXCrystObj=new WXMolDihedralAngle(parent,this); VFN_DEBUG_EXIT("MolDihedralAngle::WXCreate()",5) return mpWXCrystObj; } WXCrystObjBasic* MolDihedralAngle::WXGet(){return mpWXCrystObj;} void MolDihedralAngle::WXDelete(){if(0!=mpWXCrystObj) delete mpWXCrystObj;mpWXCrystObj=0;} void MolDihedralAngle::WXNotifyDelete(){mpWXCrystObj=0;} #endif //###################################################################### // // RigidGroup // //###################################################################### string RigidGroup::GetName()const { set::const_iterator at=this->begin(); string name=(*at++)->GetName(); for(;at!=this->end();++at) name+=", "+(*at)->GetName(); return name; } size_t RigidGroup::int_ptr() const {return (size_t)this;} //###################################################################### // // MolRing // //###################################################################### MolRing::MolRing() {} const std::list& MolRing::GetAtomList()const {return mvpAtom;} std::list& MolRing::GetAtomList() {return mvpAtom;} size_t MolRing::int_ptr() const {return (size_t)this;} //###################################################################### // // Quaternion // //###################################################################### Quaternion::Quaternion(): mQ0(1),mQ1(0),mQ2(0),mQ3(0),mIsUniQuaternion(true) { VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5) } Quaternion::Quaternion(const REAL q0, const REAL q1, const REAL q2, const REAL q3, bool unit): mQ0(q0),mQ1(q1),mQ2(q2),mQ3(q3),mIsUniQuaternion(unit) { VFN_DEBUG_MESSAGE("Quaternion::Quaternion()",5) if(unit) this->Normalize(); } Quaternion::~Quaternion() { VFN_DEBUG_MESSAGE("Quaternion::~Quaternion()",5) } Quaternion Quaternion::RotationQuaternion(const REAL ang, const REAL v1, const REAL v2, const REAL v3) { VFN_DEBUG_MESSAGE("Quaternion::RotationQuaternion()",4) const REAL s=sin(ang/2.)/sqrt(v1*v1+v2*v2+v3*v3+1e-7); return Quaternion(cos(ang/2.),s*v1,s*v2,s*v3, true); } Quaternion Quaternion::GetConjugate()const { return Quaternion(mQ0,-mQ1,-mQ2,-mQ3); } Quaternion Quaternion::operator*(const Quaternion &q)const { // http://www.cs.berkeley.edu/~laura/cs184/quat/quaternion.html return Quaternion (this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3(), this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2(), this->Q0()*q.Q2()-this->Q1()*q.Q3()+this->Q2()*q.Q0()+this->Q3()*q.Q1(), this->Q0()*q.Q3()+this->Q1()*q.Q2()-this->Q2()*q.Q1()+this->Q3()*q.Q0(),false); } void Quaternion::operator*=(const Quaternion &q) { //cout<<"Quaternion::operator*= before:";this->XMLOutput(cout); //cout<<"Quaternion::operator*= by :";q.XMLOutput(cout); const REAL q1=this->Q0()*q.Q1()+this->Q1()*q.Q0()+this->Q2()*q.Q3()-this->Q3()*q.Q2(); const REAL q2=this->Q0()*q.Q2()+this->Q2()*q.Q0()-this->Q1()*q.Q3()+this->Q3()*q.Q1(); const REAL q3=this->Q0()*q.Q3()+this->Q3()*q.Q0()+this->Q1()*q.Q2()-this->Q2()*q.Q1(); this->Q0()= this->Q0()*q.Q0()-this->Q1()*q.Q1()-this->Q2()*q.Q2()-this->Q3()*q.Q3(); this->Q1()=q1; this->Q2()=q2; this->Q3()=q3; this->Normalize(); //cout<<"Quaternion::operator*= after :";this->XMLOutput(cout); } void Quaternion::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("Quaternion::XMLOutput()",4) for(int i=0;i>mQ0; } if("Q1"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mQ1; } if("Q2"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mQ2; } if("Q3"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mQ3; } if("IsUnitQuaternion"==tag.GetAttributeName(i)) { stringstream ss(tag.GetAttributeValue(i)); ss >>mIsUniQuaternion; } } if(mIsUniQuaternion) this->Normalize(); VFN_DEBUG_EXIT("Quaternion::XMLInput()",5) } void Quaternion::RotateVector(REAL &v1,REAL &v2, REAL &v3)const { #if 0 //#error P should not be a _UNIT_ quaternion... Quaternion P(0,v1,v2,v3,false); //cout<<"RotQuat:(n="<GetNorm()<<")";this->XMLOutput(cout); //cout<<"before :(n="<GetConjugate(); //cout<<"rotated:(n="<Q0()*this->Q0() +this->Q1()*this->Q1() +this->Q2()*this->Q2() +this->Q3()*this->Q3()); mQ0 /= norm; mQ1 /= norm; mQ2 /= norm; mQ3 /= norm; } REAL Quaternion::GetNorm()const {return sqrt( this->Q0()*this->Q0() +this->Q1()*this->Q1() +this->Q2()*this->Q2() +this->Q3()*this->Q3());} const REAL& Quaternion::Q0()const{return mQ0;} const REAL& Quaternion::Q1()const{return mQ1;} const REAL& Quaternion::Q2()const{return mQ2;} const REAL& Quaternion::Q3()const{return mQ3;} REAL& Quaternion::Q0(){return mQ0;} REAL& Quaternion::Q1(){return mQ1;} REAL& Quaternion::Q2(){return mQ2;} REAL& Quaternion::Q3(){return mQ3;} //###################################################################### // // Molecule Stretch Modes // //###################################################################### StretchMode::~StretchMode(){} StretchModeBondLength::StretchModeBondLength(MolAtom &at0,MolAtom &at1, const MolBond *pBond): mpAtom0(&at0),mpAtom1(&at1),mpBond(pBond) { mBaseAmplitude=0.1; mpMol = &(at1.GetMolecule()); } StretchModeBondLength::~StretchModeBondLength(){} void StretchModeBondLength::CalcDeriv(const bool derivllk)const { //TAU_PROFILE("StretchModeBondLength::CalcDeriv()","void ()",TAU_DEFAULT); // Derivative of the atom positions //mDerivXYZ.clear(); REAL dx=mpAtom1->GetX()-mpAtom0->GetX(); REAL dy=mpAtom1->GetY()-mpAtom0->GetY(); REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ(); const REAL n=sqrt(dx*dx+dy*dy+dz*dz+1e-7); if(n<1e-6) return;//:KLUDGE: ? dx/=n; dy/=n; dz/=n; for(set::const_iterator pos=mvTranslatedAtomList.begin(); pos!=mvTranslatedAtomList.end();++pos) { XYZ *const p=&(mDerivXYZ[*pos]); p->x=dx; p->y=dy; p->z=dz; } // Derivative of the LLK if(derivllk) { mLLKDeriv=0; for(map::const_iterator pos=this->mvpBrokenBond.begin(); pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenBondAngle.begin(); pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenDihedralAngle.begin(); pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); } } void StretchModeBondLength::Print(ostream &os,bool full)const { cout<GetName()<<"-"<GetName(); if(full) { cout<<", Translated Atoms:"; for(set::const_iterator atom=mvTranslatedAtomList.begin(); atom!=mvTranslatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } } } void StretchModeBondLength::Stretch(const REAL amplitude, const bool keepCenter) { REAL dx=mpAtom1->GetX()-mpAtom0->GetX(); REAL dy=mpAtom1->GetY()-mpAtom0->GetY(); REAL dz=mpAtom1->GetZ()-mpAtom0->GetZ(); const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7); if(l<1e-6) return;// :KLUDGE: const REAL change=amplitude/l; dx*=change; dy*=change; dz*=change; mpMol->TranslateAtomGroup(mvTranslatedAtomList,dx,dy,dz,keepCenter); } void StretchModeBondLength::RandomStretch(const REAL amplitude, const bool keepCenter) { mpMol->BondLengthRandomChange(*this,amplitude,keepCenter); } StretchModeBondAngle::StretchModeBondAngle(MolAtom &at0,MolAtom &at1,MolAtom &at2, const MolBondAngle *pBondAngle): mpAtom0(&at0),mpAtom1(&at1),mpAtom2(&at2),mpBondAngle(pBondAngle) { mBaseAmplitude=M_PI*0.02; mpMol = &(at1.GetMolecule()); } StretchModeBondAngle::~StretchModeBondAngle(){} void StretchModeBondAngle::CalcDeriv(const bool derivllk)const { //TAU_PROFILE("StretchModeBondAngle::CalcDeriv()","void ()",TAU_DEFAULT); // Derivative of the atomic positions const REAL x1=mpAtom1->GetX(), y1=mpAtom1->GetY(), z1=mpAtom1->GetZ(); const REAL dx10=mpAtom0->GetX()-x1, dy10=mpAtom0->GetY()-y1, dz10=mpAtom0->GetZ()-z1, dx12=mpAtom2->GetX()-x1, dy12=mpAtom2->GetY()-y1, dz12=mpAtom2->GetZ()-z1; REAL vx=dy10*dz12-dz10*dy12, vy=dz10*dx12-dx10*dz12, vz=dx10*dy12-dy10*dx12; //const REAL n=sqrt((dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12))+1e-10; const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10); vx/=n; vy/=n; vz/=n; if(n<1e-6) { mDerivXYZ.clear(); return;//:KLUDGE: ? } for(set::const_iterator pos=mvRotatedAtomList.begin(); pos!=mvRotatedAtomList.end();++pos) { XYZ *const p=&(mDerivXYZ[*pos]); const REAL x=(*pos)->GetX()-x1, y=(*pos)->GetY()-y1, z=(*pos)->GetZ()-z1; p->x=z*vy-y*vz; p->y=x*vz-z*vx; p->z=y*vx-x*vy; } // Derivative of the LLK if(derivllk) { mLLKDeriv=0; for(map::const_iterator pos=this->mvpBrokenBond.begin(); pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenBondAngle.begin(); pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenDihedralAngle.begin(); pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); } } void StretchModeBondAngle::Print(ostream &os,bool full)const { cout<GetName()<<"-"<GetName()<<"-"<GetName(); if(full) { cout<<", Rotated Atoms:"; for(set::const_iterator atom=mvRotatedAtomList.begin(); atom!=mvRotatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } } } void StretchModeBondAngle::Stretch(const REAL amplitude, const bool keepCenter) { REAL dx10=mpAtom0->GetX()-mpAtom1->GetX(); REAL dy10=mpAtom0->GetY()-mpAtom1->GetY(); REAL dz10=mpAtom0->GetZ()-mpAtom1->GetZ(); REAL dx12=mpAtom2->GetX()-mpAtom1->GetX(); REAL dy12=mpAtom2->GetY()-mpAtom1->GetY(); REAL dz12=mpAtom2->GetZ()-mpAtom1->GetZ(); const REAL vx=dy10*dz12-dz10*dy12; const REAL vy=dz10*dx12-dx10*dz12; const REAL vz=dx10*dy12-dy10*dx12; mpMol->RotateAtomGroup(*mpAtom1,vx,vy,vz,mvRotatedAtomList,amplitude,keepCenter); } void StretchModeBondAngle::RandomStretch(const REAL amplitude, const bool keepCenter) { mpMol->BondAngleRandomChange(*this,amplitude,keepCenter); } StretchModeTorsion::StretchModeTorsion(MolAtom &at1,MolAtom &at2, const MolDihedralAngle *pAngle): mpAtom1(&at1),mpAtom2(&at2),mpDihedralAngle(pAngle) { mBaseAmplitude=M_PI*0.02; mpMol = &(at1.GetMolecule()); } StretchModeTorsion::~StretchModeTorsion(){} void StretchModeTorsion::CalcDeriv(const bool derivllk)const { //TAU_PROFILE("StretchModeTorsion::CalcDeriv()","void ()",TAU_DEFAULT); // Derivative of the LLK //mDerivXYZ.clear(); const REAL x1=mpAtom1->GetX(), y1=mpAtom1->GetY(), z1=mpAtom1->GetZ(); REAL vx=mpAtom2->GetX()-x1, vy=mpAtom2->GetY()-y1, vz=mpAtom2->GetZ()-z1; const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10); vx/=n; vy/=n; vz/=n; for(set::const_iterator pos=mvRotatedAtomList.begin(); pos!=mvRotatedAtomList.end();++pos) { XYZ *const p=&(mDerivXYZ[*pos]); const REAL x=(*pos)->GetX()-x1, y=(*pos)->GetY()-y1, z=(*pos)->GetZ()-z1; p->x=z*vy-y*vz; p->y=x*vz-z*vx; p->z=y*vx-x*vy; } // Derivative of the LLK if(derivllk) { mLLKDeriv=0; for(map::const_iterator pos=this->mvpBrokenBond.begin(); pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenBondAngle.begin(); pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenDihedralAngle.begin(); pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); } } void StretchModeTorsion::Print(ostream &os,bool full)const { cout<GetName()<<"-"<GetName(); if(full) { cout<<", Rotated Atoms:"; for(set::const_iterator atom=mvRotatedAtomList.begin(); atom!=mvRotatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } } } void StretchModeTorsion::Stretch(const REAL amplitude, const bool keepCenter) { mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter); } void StretchModeTorsion::RandomStretch(const REAL amplitude, const bool keepCenter) { mpMol->DihedralAngleRandomChange(*this,amplitude,keepCenter); } //###################################################################### // // StretchModeTwist // //###################################################################### StretchModeTwist::StretchModeTwist(MolAtom &at1,MolAtom &at2): mpAtom1(&at1),mpAtom2(&at2) { mBaseAmplitude=M_PI*0.02; mpMol = &(at1.GetMolecule()); } StretchModeTwist::~StretchModeTwist(){} void StretchModeTwist::CalcDeriv(const bool derivllk)const {// Identical to StretchModeTorsion::CalcDeriv() // Derivative of the LLK //mDerivXYZ.clear(); const REAL x1=mpAtom1->GetX(), y1=mpAtom1->GetY(), z1=mpAtom1->GetZ(); REAL vx=mpAtom2->GetX()-x1, vy=mpAtom2->GetY()-y1, vz=mpAtom2->GetZ()-z1; const REAL n=sqrt(vx*vx+vy*vy+vz*vz+1e-10); vx/=n; vy/=n; vz/=n; for(set::const_iterator pos=mvRotatedAtomList.begin(); pos!=mvRotatedAtomList.end();++pos) { XYZ *const p=&(mDerivXYZ[*pos]); const REAL x=(*pos)->GetX()-x1, y=(*pos)->GetY()-y1, z=(*pos)->GetZ()-z1; p->x=z*vy-y*vz; p->y=x*vz-z*vx; p->z=y*vx-x*vy; } // Derivative of the LLK if(derivllk) { mLLKDeriv=0; for(map::const_iterator pos=this->mvpBrokenBond.begin(); pos!=this->mvpBrokenBond.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenBondAngle.begin(); pos!=this->mvpBrokenBondAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); for(map::const_iterator pos=this->mvpBrokenDihedralAngle.begin(); pos!=this->mvpBrokenDihedralAngle.end();++pos) mLLKDeriv += pos->first->GetDeriv(mDerivXYZ,true); } } void StretchModeTwist::Print(ostream &os,bool full)const { os<GetName()<<"/"<GetName()<<"-"<GetName(); if(full) { os<<", Rotated Atoms:"; for(set::const_iterator atom=mvRotatedAtomList.begin(); atom!=mvRotatedAtomList.end();++atom) { os<<(*atom)->GetName()<<","; } } } void StretchModeTwist::Stretch(const REAL amplitude, const bool keepCenter) { mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,amplitude,keepCenter); } void StretchModeTwist::RandomStretch(const REAL amplitude, const bool keepCenter) { const REAL dx=mpAtom2->GetX()-mpAtom1->GetX(); const REAL dy=mpAtom2->GetY()-mpAtom1->GetY(); const REAL dz=mpAtom2->GetZ()-mpAtom1->GetZ(); if((abs(dx)+abs(dy)+abs(dz))<1e-6) return;// :KLUDGE: const REAL change=(REAL)(2.*rand()-RAND_MAX)/(REAL)RAND_MAX*mBaseAmplitude*amplitude; mpMol->RotateAtomGroup(*mpAtom1,*mpAtom2,mvRotatedAtomList,change,keepCenter); } //###################################################################### // // MDAtomGroup // //###################################################################### MDAtomGroup::MDAtomGroup(){}; MDAtomGroup::MDAtomGroup(set &vat, set &vb, set &va, set &vd): mvpAtom(vat) { // Use vector instead of sets for MolecularDynamicsEvolve & general // storage in molecule compatibility for(set::iterator pos=vb.begin();pos!=vb.end();++pos) mvpBond.push_back(*pos); for(set::iterator pos=va.begin();pos!=va.end();++pos) mvpBondAngle.push_back(*pos); for(set::iterator pos=vd.begin();pos!=vd.end();++pos) mvpDihedralAngle.push_back(*pos); } void MDAtomGroup::Print(ostream &os,bool full)const { if(full) os<<"MDAtomGroup: "; for(set::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) os<<(*pos)->GetName()<<" "; if(full) { os<::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) os<<(*pos)->GetName()<<" "; os<::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) os<<(*pos)->GetName()<<" "; os<::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos) os<<(*pos)->GetName()<<" "; os<AddPar(tmp); } { RefinablePar tmp(name+"_y",&mXYZ(1),0,1, gpRefParTypeScattTranslY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(name+"_z",&mXYZ(2),0,1, gpRefParTypeScattTranslZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(name+"_Occ",&mOccupancy,0,1, gpRefParTypeScattOccup, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(name+"_Q0",&(mQuat.Q0()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(name+"_Q1",&(mQuat.Q1()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(name+"_Q2",&(mQuat.Q2()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(name+"_Q3",&(mQuat.Q3()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } this->SetName(name); mLocalParamSet=this->CreateParamSet("saved parameters for local minimization"); this->InitOptions(); mClockScatterer.AddChild(mClockAtomList); mClockScatterer.AddChild(mClockBondList); mClockScatterer.AddChild(mClockBondAngleList); mClockScatterer.AddChild(mClockDihedralAngleList); mClockScatterer.AddChild(mClockRingList); mClockScatterer.AddChild(mClockRigidGroup); mClockScatterer.AddChild(mClockAtomPosition); mClockScatterer.AddChild(mClockAtomScattPow); mClockScatterer.AddChild(mClockOrientation); } Molecule::Molecule(const Molecule &old): mDeleteSubObjInDestructor(old.mDeleteSubObjInDestructor), mIsSelfOptimizing(false), mpCenterAtom(0) { VFN_DEBUG_ENTRY("Molecule::Molecule(old&)",5) // a hack, but const-correct mpCryst=&(gCrystalRegistry.GetObj(gCrystalRegistry.Find(old.GetCrystal()))); { RefinablePar tmp(this->GetName()+"_x",&mXYZ(0),0.,1., gpRefParTypeScattTranslX, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"_y",&mXYZ(1),0,1, gpRefParTypeScattTranslY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"_z",&mXYZ(2),0,1, gpRefParTypeScattTranslZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"_Occ",&mOccupancy,0,1, gpRefParTypeScattOccup, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetDerivStep(1e-5); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"Q0",&(mQuat.Q0()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"Q1",&(mQuat.Q1()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"Q2",&(mQuat.Q2()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(this->GetName()+"Q3",&(mQuat.Q3()),0,1, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockScatterer); tmp.SetGlobalOptimStep(0.04); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } mLocalParamSet=this->CreateParamSet("saved parameters for local minimization"); this->InitOptions(); mClockScatterer.AddChild(mClockAtomList); mClockScatterer.AddChild(mClockBondList); mClockScatterer.AddChild(mClockBondAngleList); mClockScatterer.AddChild(mClockDihedralAngleList); mClockScatterer.AddChild(mClockRingList); mClockScatterer.AddChild(mClockRigidGroup); mClockScatterer.AddChild(mClockAtomPosition); mClockScatterer.AddChild(mClockAtomScattPow); mClockScatterer.AddChild(mClockOrientation); mClockRestraint.AddChild(mClockAtomList); mClockRestraint.AddChild(mClockBondList); mClockRestraint.AddChild(mClockBondAngleList); mClockRestraint.AddChild(mClockDihedralAngleList); mClockRestraint.AddChild(mClockRingList); mClockRestraint.AddChild(mClockRigidGroup); stringstream str; old.XMLOutput(str); XMLCrystTag tag(str); this->XMLInput(str,tag); VFN_DEBUG_EXIT("Molecule::Molecule(old&)",5) } Molecule::~Molecule() { VFN_DEBUG_ENTRY("Molecule::~Molecule()",5) if(mDeleteSubObjInDestructor) { { vector::iterator pos; for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++) delete *pos; } { vector::iterator pos; for(pos=mvpBond.begin();pos!=mvpBond.end();pos++) delete *pos; } { vector::iterator pos; for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();pos++) delete *pos; } { vector::iterator pos; for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();pos++) delete *pos; } } VFN_DEBUG_EXIT("Molecule::~Molecule()",5) } Molecule* Molecule::CreateCopy() const { VFN_DEBUG_MESSAGE("Molecule::CreateCopy()",5) return new Molecule(*this); } const string& Molecule::GetClassName() const { static const string className="Molecule"; return className; } void Molecule::SetName(const string &name) { if(mName==name) return; this->RefinableObj::SetName(name); // Set parameter's name including the Molecule's name try { this->GetPar(&mXYZ(0)).SetName(mName+"_x"); this->GetPar(&mXYZ(1)).SetName(mName+"_y"); this->GetPar(&mXYZ(2)).SetName(mName+"_z"); this->GetPar(&mOccupancy).SetName(mName+"_Occ"); this->GetPar(&(mQuat.Q0())).SetName(mName+"_Q0"); this->GetPar(&(mQuat.Q1())).SetName(mName+"_Q1"); this->GetPar(&(mQuat.Q2())).SetName(mName+"_Q2"); this->GetPar(&(mQuat.Q3())).SetName(mName+"_Q3"); } catch(const ObjCrystException &except) { cerr<<"Molecule::SetName(): parameters not yet declared in a Molecule ?"<GetNbComponent()==0) return ""; std::map velts; for(std::vector::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { if((*pos)->IsDummy()) continue; string p=(*pos)->GetScatteringPower().GetSymbol(); if(velts.count(p)==0) velts[p]=(*pos)->GetOccupancy(); else velts[p]+=(*pos)->GetOccupancy(); } stringstream s; s<::const_iterator pos=velts.begin();pos!=velts.end();++pos) { if(pos!=velts.begin()) s<<" "; float nb=pos->second; if(abs(round(nb)-nb)<0.005) { if(int(round(nb))==1) s<first; else s<first<first<XMLOutput(cout); } void Molecule::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("Molecule::XMLOutput()",4) // :KLUDGE: this may be dangerous if the molecule is beaing refined ! this->ResetRigidGroupsPar(); for(int i=0;iGetPar(mXYZ.data()+0).XMLOutput(os,"x",indent); os <GetPar(mXYZ.data()+1).XMLOutput(os,"y",indent); os <GetPar(mXYZ.data()+2).XMLOutput(os,"z",indent); os <GetPar(&mOccupancy).XMLOutput(os,"Occup",indent); os <GetNbOption();i++) { this->GetOption(i).XMLOutput(os,indent); os <::const_iterator pos; for(pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) (*pos)->XMLOutput(os,indent); } { vector::const_iterator pos; for(pos=mvpBond.begin();pos!=mvpBond.end();++pos) (*pos)->XMLOutput(os,indent); } { vector::const_iterator pos; for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) (*pos)->XMLOutput(os,indent); } { vector::const_iterator pos; for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos) (*pos)->XMLOutput(os,indent); } { vector::const_iterator pos; for(pos=mvRigidGroup.begin();pos!=mvRigidGroup.end();++pos) { XMLCrystTag tagg("RigidGroup",false,true); for(set::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at) tagg.AddAttribute("Atom",(*at)->GetName()); /* tagg.AddAttribute("Q0",(*pos)->mQuat.Q0()); tagg.AddAttribute("Q1",(*pos)->mQuat.Q1()); tagg.AddAttribute("Q2",(*pos)->mQuat.Q2()); tagg.AddAttribute("Q3",(*pos)->mQuat.Q3()); tagg.AddAttribute("dX",(*pos)->mX); tagg.AddAttribute("dY",(*pos)->mY); tagg.AddAttribute("dZ",(*pos)->mZ); */ for(int i=0;iGetCenterAtom()!=0) { XMLCrystTag tagg("CenterAtom",false,true); tagg.AddAttribute("Name",this->GetCenterAtom()->GetName()); for(int i=0;iXMLOutput(cout); this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::XMLInput():"<GetName(),5) return; } if("Quaternion"==tagg.GetName()) { mQuat.XMLInput(is,tagg); } if("Atom"==tagg.GetName()) { this->AddAtom(0.,0.,0.,(ScatteringPower *)0,"",false); mvpAtom.back()->XMLInput(is,tagg); } if("Bond"==tagg.GetName()) { this->AddBond(this->GetAtom(0),this->GetAtom(1),1.5,.01,.05,1.,false); mvpBond.back()->XMLInput(is,tagg); } if("BondAngle"==tagg.GetName()) { this->AddBondAngle(this->GetAtom(0),this->GetAtom(1),this->GetAtom(2),1.5,.01,.05,false); mvpBondAngle.back()->XMLInput(is,tagg); } if("DihedralAngle"==tagg.GetName()) { this->AddDihedralAngle(this->GetAtom(0),this->GetAtom(1), this->GetAtom(2),this->GetAtom(3),1.5,.01,.05,false); mvpDihedralAngle.back()->XMLInput(is,tagg); } if("RigidGroup"==tagg.GetName()) { RigidGroup s; for(unsigned int i=0;iGetAtom(tagg.GetAttributeValue(i)))); this->AddRigidGroup(s); } if("CenterAtom"==tagg.GetName()) { RigidGroup s; for(unsigned int i=0;iSetCenterAtom(this->GetAtom(tagg.GetAttributeValue(i))); } if("Option"==tagg.GetName()) { for(unsigned int i=0;iGetPar(mXYZ.data()+0).XMLInput(is,tagg); break; } if("y"==tagg.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+1).XMLInput(is,tagg); break; } if("z"==tagg.GetAttributeValue(i)) { this->GetPar(mXYZ.data()+2).XMLInput(is,tagg); break; } if("Occup"==tagg.GetAttributeValue(i)) { this->GetPar(&mOccupancy).XMLInput(is,tagg); break; } } } } } VFN_DEBUG_EXIT("Molecule::XMLInput()",5) } void Molecule::UpdateDisplay()const { this->ResetRigidGroupsPar(); this->RefinableObj::UpdateDisplay(); } void Molecule::BeginOptimization(const bool allowApproximations,const bool enableRestraints) { if(this->IsBeingRefined()) { // RefinableObj::BeginOptimization() will increase the optimization depth this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); return; } TAU_PROFILE("Molecule::BeginOptimization()","void (bool,bool)",TAU_DEFAULT); #if 1 // Is doing this automatically too dangerous ? if( (!mIsSelfOptimizing) &&(mAutoOptimizeConformation.GetChoice()==0)) { if(this->GetLogLikelihood()>(mvpRestraint.size()*500)) { (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName()); this->OptimizeConformation(100000,(REAL)(mvpRestraint.size())); (*fpObjCrystInformUser)("Finished optimizing initial conformation of Molecule:"+this->GetName()); } mAutoOptimizeConformation.SetChoice(1); } #endif RefinableObjClock clockConf, clockMode; clockConf=mClockAtomList; if(clockConfBuildRotorGroup(); #endif if(mFlexModel.GetChoice()!=1) { this->BuildFlipGroup(); this->BuildRingList(); this->BuildStretchModeBondLength(); this->BuildStretchModeBondAngle(); this->BuildStretchModeTorsion(); //this->BuildStretchModeTwist(); this->TuneGlobalOptimRotationAmplitude(); this->BuildStretchModeGroups(); this->BuildMDAtomGroups(); } } if(mOptimizeOrientation.GetChoice()==1) { this->GetPar(&(mQuat.Q0())).SetIsFixed(true); this->GetPar(&(mQuat.Q1())).SetIsFixed(true); this->GetPar(&(mQuat.Q2())).SetIsFixed(true); this->GetPar(&(mQuat.Q3())).SetIsFixed(true); } else { this->GetPar(&(mQuat.Q0())).SetIsFixed(false); this->GetPar(&(mQuat.Q1())).SetIsFixed(false); this->GetPar(&(mQuat.Q2())).SetIsFixed(false); this->GetPar(&(mQuat.Q3())).SetIsFixed(false); } if(1==mFlexModel.GetChoice()) {// Molecule is a rigid body - fix all individual atomic parameters for(vector::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at) { this->GetPar(&((*at)->X())).SetIsFixed(true); this->GetPar(&((*at)->Y())).SetIsFixed(true); this->GetPar(&((*at)->Z())).SetIsFixed(true); } } else {// Molecule is flexible - rigid groups are handled below for(vector::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at) { this->GetPar(&((*at)->X())).SetIsFixed(false); this->GetPar(&((*at)->Y())).SetIsFixed(false); this->GetPar(&((*at)->Z())).SetIsFixed(false); } } #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // Block individual refinable parameters from atoms in rigid groups // And create the index of the atoms for(vector::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { // Init the translation & rotation parameters (ignored outside an optimization) (*pos)->mX=0; (*pos)->mY=0; (*pos)->mZ=0; (*pos)->mQuat.Q0()=1; (*pos)->mQuat.Q1()=0; (*pos)->mQuat.Q2()=0; (*pos)->mQuat.Q3()=0; (*pos)->mvIdx.clear(); for(set::iterator at=(*pos)->begin();at!=(*pos)->end();++at) { this->GetPar(&((*at)->X())).SetIsFixed(true); this->GetPar(&((*at)->Y())).SetIsFixed(true); this->GetPar(&((*at)->Z())).SetIsFixed(true); for(int i = 0; i < this->GetNbComponent(); ++i) if(&(this->GetAtom(i))==*at) { (*pos)->mvIdx.insert(i); break; } } } #endif this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); mRandomConformChangeNbTest=0; mRandomConformChangeNbAccept=0; mRandomConformChangeTemp=1.;//(REAL)this->GetNbComponent(); } void Molecule::EndOptimization() { /* if(mOptimizationDepth>1) { this->RefinableObj::EndOptimization(); return; } */ #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // Un-block individual refinable parameters from atoms in rigid groups for(vector::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { for(set::iterator at=(*pos)->begin();at!=(*pos)->end();++at) { this->GetPar(&((*at)->X())).SetIsFixed(false); this->GetPar(&((*at)->Y())).SetIsFixed(false); this->GetPar(&((*at)->Z())).SetIsFixed(false); } } // Apply the translations & rotations of the rigid group parameters, and // use this as the newly stored atomic coordinates. this->ResetRigidGroupsPar(); #endif this->RefinableObj::EndOptimization(); } void Molecule::RandomizeConfiguration() { TAU_PROFILE("Molecule::RandomizeConfiguration()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("Molecule::RandomizeConfiguration()",4) if( (!mIsSelfOptimizing) &&(this->GetLogLikelihood()>(mvpRestraint.size()*500)) &&(mAutoOptimizeConformation.GetChoice()==0)) {// This is only done once, for a newly-created molecule with atoms not conforming to restraints (*fpObjCrystInformUser)("Optimizing initial conformation of Molecule:"+this->GetName()); this->OptimizeConformation(100000,(REAL)(mvpRestraint.size())); (*fpObjCrystInformUser)("Finished optimizing initial conformation of Molecule:"+this->GetName()); mAutoOptimizeConformation.SetChoice(1); } if( (!(this->IsBeingRefined())) &&( (mClockStretchModeTorsionBuildStretchModeTorsion(); //this->BuildStretchModeGroups(); this->BuildMDAtomGroups(); // WARNING: TuneGlobalOptimRotationAmplitude() will call RandomizeConfiguration(), // so make sure we do not enter this code again by calling first BuildStretchModeTorsion and BuildMDAtomGroups this->TuneGlobalOptimRotationAmplitude(); } } #if 0 this->BuildRotorGroup(); if((mFlexModel.GetChoice()==0)||(mFlexModel.GetChoice()==2)) for(list::const_iterator pos=mvRotorGroupTorsion.begin(); pos!=mvRotorGroupTorsion.end();++pos) { const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX; this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2), pos->mvRotatedAtomList,angle); } if(mFlexModel.GetChoice()==0) for(list::const_iterator pos=mvRotorGroupTorsionSingleChain.begin(); pos!=mvRotorGroupTorsionSingleChain.end();++pos) { const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX; this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2), pos->mvRotatedAtomList,angle); } if(mFlexModel.GetChoice()==0) for(list::const_iterator pos=mvRotorGroupInternal.begin(); pos!=mvRotorGroupInternal.end();++pos) { const REAL angle=(REAL)rand()*2.*M_PI/(REAL)RAND_MAX; this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2), pos->mvRotatedAtomList,angle); } #else for(list::const_iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();++pos) { const REAL amp=2*M_PI*rand()/(REAL)RAND_MAX; this->DihedralAngleRandomChange(*pos,amp,true); } // Molecular dynamics moves if((mvMDAtomGroup.size()>0)&&(mMDMoveFreq>0)&&(mMDMoveEnergy>0)) { // Random initial speed for all atoms map v0; for(vector::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at) v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5); const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size() +this->GetBondAngleList().size() +this->GetDihedralAngleList().size()); map > vr; this->MolecularDynamicsEvolve(v0, 5000,0.004, this->GetBondList(), this->GetBondAngleList(), this->GetDihedralAngleList(), vr,nrj0); } #endif // this will only change limited parameters i.e. translation this->RefinableObj::RandomizeConfiguration(); #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // Init rigid groups translation & rotation parameters to zero for(vector::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { // Init the translation & rotation parameters (ignored outside an optimization (*pos)->mX=0; (*pos)->mY=0; (*pos)->mZ=0; (*pos)->mQuat.Q0()=1; (*pos)->mQuat.Q1()=0; (*pos)->mQuat.Q2()=0; (*pos)->mQuat.Q3()=0; } #endif if(mOptimizeOrientation.GetChoice()==0) {//Rotate around an arbitrary vector const REAL amp=M_PI/RAND_MAX; mQuat *= Quaternion::RotationQuaternion ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp, (REAL)rand(),(REAL)rand(),(REAL)rand()); mQuat.Normalize(); mClockOrientation.Click(); } VFN_DEBUG_EXIT("Molecule::RandomizeConfiguration()",4) } void Molecule::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; if(mIsSelfOptimizing) { this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type); mQuat.Normalize(); VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4) return; } TAU_PROFILE("Molecule::GlobalOptRandomMove()","void (REAL,RefParType*)",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"Molecule::GlobalOptRandomMove 1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"Molecule::GlobalOptRandomMove 2","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"Molecule::GlobalOptRandomMove 3","", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"Molecule::GlobalOptRandomMove 4","", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"Molecule::GlobalOptRandomMove 5","", TAU_FIELD); VFN_DEBUG_ENTRY("Molecule::GlobalOptRandomMove()",4) mClockScatterer.Click(); #if 1 // From time to time, just do one flip if( (mFlexModel.GetChoice()!=1) &&(mFlipModel.GetChoice()==0) &&(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type)) &&(mvFlipGroup.size()>0) &&(((rand()%100)==0))) { this->SaveParamSet(mLocalParamSet); const REAL llk0=this->GetLogLikelihood()/mLogLikelihoodScale; const unsigned long i=rand() % mvFlipGroup.size(); list::iterator pos=mvFlipGroup.begin(); for(unsigned long j=0;jFlipAtomGroup(*pos,true); #if 0 static unsigned long ctflip1=0,ctflip2=0; if(pos->mvRotatedChainList.begin()->first==pos->mpAtom0) { cout <<"TRYING: Flip group from atom " <mpAtom0->GetName()<<",exchanging bonds with " <mpAtom1->GetName()<<" and " <mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : "; for(set::iterator pos1=pos->mvRotatedChainList.begin()->second.begin(); pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; } else { cout <<"TRYING: Flip group with respect to: " <mpAtom1->GetName()<<"-" <mpAtom0->GetName()<<"-" <mpAtom2->GetName()<<" : "; for(list > >::const_iterator chain=pos->mvRotatedChainList.begin(); chain!=pos->mvRotatedChainList.end();++chain) { cout<<" -"<first->GetName()<<":"; for(set::const_iterator pos1=chain->second.begin(); pos1!=chain->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; } } ctflip1++; if((this->GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0) { cout<<" FLIP REJECTED ("< "<GetLogLikelihood()/mLogLikelihoodScale<RestoreParamSet(mLocalParamSet); } else { ctflip2++; cout<<" FLIP ACCEPTED ("<GetLogLikelihood()/mLogLikelihoodScale-llk0)>.3*llk0) this->RestoreParamSet(mLocalParamSet); #endif } else #endif { TAU_PROFILE_START(timer1); if(mOptimizeOrientation.GetChoice()==0) {//Rotate around an arbitrary vector static const REAL amp=mBaseRotationAmplitude/(REAL)RAND_MAX; REAL mult=1.0; if((1==mFlexModel.GetChoice())||(mvRotorGroupTorsion.size()<2)) mult=2.0; mQuat *= Quaternion::RotationQuaternion ((2.*(REAL)rand()-(REAL)RAND_MAX)*amp*mutationAmplitude*mult, (REAL)rand(),(REAL)rand(),(REAL)rand()); mQuat.Normalize(); mClockOrientation.Click(); } // Occupancy if(gpRefParTypeScattOccup->IsDescendantFromOrSameAs(type)) this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattOccup); mRandomMoveIsDone=false; //translation if(gpRefParTypeScattTransl->IsDescendantFromOrSameAs(type)) this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,gpRefParTypeScattTransl); mRandomMoveIsDone=false; TAU_PROFILE_STOP(timer1); if(gpRefParTypeScattConform->IsDescendantFromOrSameAs(type)) { if(mFlexModel.GetChoice()!=1) { #if 1 // Move as many atoms as possible if((mvMDFullAtomGroup.size()>3)&&(rand()<(RAND_MAX*mMDMoveFreq))) { #if 0 // Use one center for the position of an impulsion, applied to all atoms with an exponential decrease // Determine extent of atom group REAL xmin=(*mvMDFullAtomGroup.begin())->GetX(); REAL xmax=(*mvMDFullAtomGroup.begin())->GetX(); REAL ymin=(*mvMDFullAtomGroup.begin())->GetY(); REAL ymax=(*mvMDFullAtomGroup.begin())->GetY(); REAL zmin=(*mvMDFullAtomGroup.begin())->GetZ(); REAL zmax=(*mvMDFullAtomGroup.begin())->GetZ(); for(set::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at) { if((*at)->GetX()GetX(); if((*at)->GetX()>xmax) xmax=(*at)->GetX(); if((*at)->GetY()GetY(); if((*at)->GetY()>ymax) ymax=(*at)->GetY(); if((*at)->GetZ()GetZ(); if((*at)->GetZ()>zmax) zmax=(*at)->GetZ(); } // Apply a gaussian impulsion to part of the atom group (FWHM=1/3 of group size) REAL dx=(xmax-xmin)/5.,dy=(ymax-ymin)/5.,dz=(zmax-zmin)/5.; if(dx<2) dx=2; if(dy<2) dy=2; if(dz<2) dz=2; const REAL xc=xmin+rand()/(REAL)RAND_MAX*(xmax-xmin); const REAL yc=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); const REAL zc=zmin+rand()/(REAL)RAND_MAX*(zmax-zmin); map v0; const REAL ax=-4.*log(2.)/(dx*dx); const REAL ay=-4.*log(2.)/(dy*dy); const REAL az=-4.*log(2.)/(dz*dz); for(set::iterator at=mvMDFullAtomGroup.begin();at!=mvMDFullAtomGroup.end();++at) v0[*at]=XYZ(exp(ax*((*at)->GetX()-xc)*((*at)->GetX()-xc)), exp(ay*((*at)->GetY()-yc)*((*at)->GetY()-yc)), exp(az*((*at)->GetZ()-zc)*((*at)->GetZ()-zc))); #else // Use one atom for the center of the impulsion, 'push' atoms depending on distance & connectivity table map v0; for(set::iterator at=this->mvMDFullAtomGroup.begin();at!=this->mvMDFullAtomGroup.end();++at) v0[*at]=XYZ(0,0,0); std::map pushedAtoms; unsigned long idx=rand()%v0.size(); set::iterator at0=this->mvMDFullAtomGroup.begin(); for(unsigned int i=0;iGetX(); const REAL yc=(*at0)->GetY(); const REAL zc=(*at0)->GetZ(); const map > *pConnect=&(this-> GetConnectivityTable()); ExpandAtomGroupRecursive(*at0,*pConnect,pushedAtoms,3); REAL ux,uy,uz,n=0; while(n<1) { ux=REAL(rand()-RAND_MAX/2); uy=REAL(rand()-RAND_MAX/2); uz=REAL(rand()-RAND_MAX/2); n=sqrt(ux*ux+uy*uy+uz*uz); } ux=ux/n;uy=uy/n;uz=uz/n; const REAL a=-4.*log(2.)/(2*2);//FWHM=2 Angstroems if(rand()%2==0) for(map::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at) v0[at->first]=XYZ(ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)), uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)), uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc))); else for(map::iterator at=pushedAtoms.begin() ;at!=pushedAtoms.end();++at) v0[at->first]=XYZ((at->first->GetX()-xc)*ux*exp(a*(at->first->GetX()-xc)*(at->first->GetX()-xc)), (at->first->GetY()-yc)*uy*exp(a*(at->first->GetY()-yc)*(at->first->GetY()-yc)), (at->first->GetZ()-zc)*uz*exp(a*(at->first->GetZ()-zc)*(at->first->GetZ()-zc))); #endif const REAL nrj0=mMDMoveEnergy*( this->GetBondList().size() +this->GetBondAngleList().size() +this->GetDihedralAngleList().size()); map > vr; this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004, this->GetBondList(), this->GetBondAngleList(), this->GetDihedralAngleList(), vr,nrj0); } #else // Move atoms belonging to a MD group if((mvMDAtomGroup.size()>0)&&(rand()<(RAND_MAX*mMDMoveFreq))) { const unsigned int n=rand()%mvMDAtomGroup.size(); list::iterator pos=mvMDAtomGroup.begin(); for(unsigned int i=0;i v0; for(set::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at) v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5); const REAL nrj0=mMDMoveEnergy*( pos->mvpBond.size() +pos->mvpBondAngle.size() +pos->mvpDihedralAngle.size()); map > vr; float nrjMult=1.0+mutationAmplitude*0.2; if((rand()%20)==0) nrjMult=4.0; this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.004, pos->mvpBond, pos->mvpBondAngle, pos->mvpDihedralAngle, vr,nrj0*nrjMult); } #endif else { #if 0 // For tests mLogLikelihood=0; for(vector::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); for(vector::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); for(vector::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); for(list::const_iterator mode=mvpStretchModeNotFree.begin(); mode!=mvpStretchModeNotFree.end();++mode) { //if((rand()%3)==0) { // 2) Get the derivative of the overall LLK for this mode (*mode)->CalcDeriv(); REAL llk=0; for(map::const_iterator pos=(*mode)->mvpBrokenBond.begin(); pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); for(map::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin(); pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); for(map::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin(); pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); // 3) Calculate MD move. base step =0.1 A (accelerated moves may go faster) REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX; // if llk>100, change has to be in the opposite direction // For a single restraint, sqrt(llk)=dx/sigma, so do not go above 10*sigma if((*mode)->mLLKDeriv>0) { change -= 0.3*sqrt(llk); if(change<-1) change=-1; } else { change += 0.3*sqrt(llk); if(change>1) change=1; } (*mode)->Print(cout); change *= mutationAmplitude * (*mode)->mBaseAmplitude; cout <<" Change="<"<mLLKDeriv*change<mBaseAmplitude; (*mode)->Stretch(change); llk=0; //(*mode)->RandomStretch(change * mutationAmplitude * (*mode)->mBaseAmplitude); for(map::const_iterator pos=(*mode)->mvpBrokenBond.begin(); pos!=(*mode)->mvpBrokenBond.end();++pos) { cout<<" "<first->GetName()<<", llk= "<first->GetLogLikelihood(false,false) <<" ?->"<first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change <<"? (deriv="<first->GetDeriv((*mode)->mDerivXYZ)<<", "<first->GetDeriv((*mode)->mDerivXYZ,true); cout<<") ->" <first->GetLogLikelihood()<first->GetLogLikelihood(false,false); } for(map::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin(); pos!=(*mode)->mvpBrokenBondAngle.end();++pos) { cout<<" "<first->GetName()<<", llk= "<first->GetLogLikelihood(false,false) <<" ?->"<first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change <<"? (deriv="<first->GetDeriv((*mode)->mDerivXYZ)<<", "<first->GetDeriv((*mode)->mDerivXYZ,true); cout<<") ->" <first->GetLogLikelihood()<first->GetLogLikelihood(false,false); } for(map::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin(); pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) { cout<<" "<first->GetName()<<", llk= "<first->GetLogLikelihood(false,false) <<" ?->"<first->GetLogLikelihood(false,false)+pos->first->GetDeriv((*mode)->mDerivXYZ,true)*change <<"? (deriv="<first->GetDeriv((*mode)->mDerivXYZ)<<", "<first->GetDeriv((*mode)->mDerivXYZ,true); cout<<") ->" <first->GetLogLikelihood()<first->GetLogLikelihood(false,false); } cout <<" -> "<::iterator mode=mvpStretchModeFree.begin(); mode!=mvpStretchModeFree.end();++mode) { if((rand()%2)==0) (*mode)->RandomStretch(mutationAmplitude); } TAU_PROFILE_STOP(timer2); if((rand()%3)==0) { // Now do an hybrid move for other modes, with a smaller amplitude (<=0.5) // 1) Calc LLK and derivatives for restraints mLogLikelihood=0; TAU_PROFILE_START(timer3); for(vector::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); for(vector::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); for(vector::const_iterator pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos) mLogLikelihood+=(*pos)->GetLogLikelihood(true,true); TAU_PROFILE_STOP(timer3); TAU_PROFILE_START(timer4); for(list::const_iterator mode=mvpStretchModeNotFree.begin(); mode!=mvpStretchModeNotFree.end();++mode) { // 2) Choose Stretch modes if((rand()%3)==0) { // 2) Get the derivative of the overall LLK for this mode (*mode)->CalcDeriv(); REAL llk=0; for(map::const_iterator pos=(*mode)->mvpBrokenBond.begin(); pos!=(*mode)->mvpBrokenBond.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); for(map::const_iterator pos=(*mode)->mvpBrokenBondAngle.begin(); pos!=(*mode)->mvpBrokenBondAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); for(map::const_iterator pos=(*mode)->mvpBrokenDihedralAngle.begin(); pos!=(*mode)->mvpBrokenDihedralAngle.end();++pos) llk+=pos->first->GetLogLikelihood(false,false); REAL change=(2.*(REAL)rand()-(REAL)RAND_MAX)/(REAL)RAND_MAX; // if llk>100, change has to be in the direction minimising the llk if((*mode)->mLLKDeriv>0) { change -= 0.01*llk; if(change<-1) change=-1; } else { change += 0.01*llk; if(change>1) change=1; } if(mutationAmplitude<0.5) change *= mutationAmplitude * (*mode)->mBaseAmplitude; else change *= 0.5 * (*mode)->mBaseAmplitude; (*mode)->Stretch(change); } } // Here we do not take mLogLikelihoodScale into account // :TODO: take into account cases where the lllk cannot go down to 0 because of // combined restraints. if( ((rand()%100)==0) && (mLogLikelihood>(mvpRestraint.size()*10))) this->OptimizeConformationSteepestDescent(0.02,5); TAU_PROFILE_STOP(timer4); } // Perform MD moves if there are MDAtomGroups #if 0 for(list::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos) { if((rand()%100)==0) { map v0; for(set::iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at) v0[*at]=XYZ(rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5,rand()/(REAL)RAND_MAX+0.5); const REAL nrj0=20*(pos->mvpBond.size()+pos->mvpBondAngle.size()+pos->mvpDihedralAngle.size()); map > vr; this->MolecularDynamicsEvolve(v0, int(100*sqrt(mutationAmplitude)),0.002, (const vector) (pos->mvpBond), (const vector) (pos->mvpBondAngle), (const vector) (pos->mvpDihedralAngle), vr,nrj0); } } #endif } // Do a steepest descent from time to time if((rand()%100)==0) this->OptimizeConformationSteepestDescent(0.02,1); mClockLogLikelihood.Click(); #endif } } } if((rand()%100)==0) {// From time to time, bring back average position to 0 REAL x0=0,y0=0,z0=0; for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { x0 += (*pos)->X(); y0 += (*pos)->Y(); z0 += (*pos)->Z(); } x0 /= mvpAtom.size(); y0 /= mvpAtom.size(); z0 /= mvpAtom.size(); for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { (*pos)->X() -= x0; (*pos)->Y() -= y0; (*pos)->Z() -= z0; } } mRandomMoveIsDone=true; VFN_DEBUG_EXIT("Molecule::GlobalOptRandomMove()",4) } REAL Molecule::GetLogLikelihood()const { if( (mClockLogLikelihood>mClockAtomList) &&(mClockLogLikelihood>mClockBondList) &&(mClockLogLikelihood>mClockBondAngleList) &&(mClockLogLikelihood>mClockDihedralAngleList) &&(mClockLogLikelihood>mClockAtomPosition) &&(mClockLogLikelihood>mClockScatterer)) return mLogLikelihood*mLogLikelihoodScale; TAU_PROFILE("Molecule::GetLogLikelihood()","REAL ()",TAU_DEFAULT); mLogLikelihood=this->RefinableObj::GetLogLikelihood(); mClockLogLikelihood.Click(); return mLogLikelihood*mLogLikelihoodScale; } unsigned int Molecule::GetNbLSQFunction()const { return 1; } const CrystVector_REAL& Molecule::GetLSQCalc(const unsigned int) const { mLSQCalc.resize(mvpRestraint.size()); REAL *p=mLSQCalc.data(); for(vector::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos) *p++=(*pos)->GetLength(); for(vector::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos) *p++=(*pos)->GetAngle(); for(vector::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos) *p++=(*pos)->GetAngle(); return mLSQCalc; } const CrystVector_REAL& Molecule::GetLSQObs(const unsigned int) const { mLSQObs.resize(mvpRestraint.size()); REAL *p=mLSQObs.data(); for(vector::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos) *p++=(*pos)->GetLength0(); for(vector::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos) *p++=(*pos)->GetAngle0(); for(vector::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos) *p++=(*pos)->GetAngle0(); return mLSQObs; } const CrystVector_REAL& Molecule::GetLSQWeight(const unsigned int) const { //:TODO: USe a clock to avoid re-computation mLSQWeight.resize(mvpRestraint.size()); REAL *p=mLSQWeight.data(); for(vector::const_iterator pos=this->GetBondList().begin();pos!=this->GetBondList().end();++pos) *p++=1/((*pos)->GetLengthSigma()* (*pos)->GetLengthSigma()+1e-6); for(vector::const_iterator pos=this->GetBondAngleList().begin();pos!=this->GetBondAngleList().end();++pos) *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6); for(vector::const_iterator pos=this->GetDihedralAngleList().begin();pos!=this->GetDihedralAngleList().end();++pos) *p++=1/((*pos)->GetAngleSigma()* (*pos)->GetAngleSigma()+1e-6); mLSQWeight*=mLogLikelihoodScale; return mLSQWeight; } const CrystVector_REAL& Molecule::GetLSQDeriv(const unsigned int n, RefinablePar&par) { //:TODO: return analytical derivatives return RefinableObj::GetLSQDeriv(n,par); } void Molecule::TagNewBestConfig()const { this->ResetRigidGroupsPar(); #if 0 cout<<"Molecule::TagNewBestConfig()"<::const_iterator pos; for(pos=mvpBond.begin();pos!=mvpBond.end();++pos) { cout<<"BondLength="<<(*pos)->GetLength(); (*pos)->XMLOutput(cout); } } { vector::const_iterator pos; for(pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) { cout<<"BondAngle="<<(*pos)->GetAngle(); (*pos)->XMLOutput(cout); } } { vector::const_iterator pos; for(pos=mvpDihedralAngle.begin();pos!=mvpDihedralAngle.end();++pos) { cout<<"DihedralAngle="<<(*pos)->GetAngle(); (*pos)->XMLOutput(cout); } } for(list::iterator pos=mvMDAtomGroup.begin();pos!=mvMDAtomGroup.end();++pos) { char buf[100]; for(set::iterator at1=pos->mvpAtom.begin();at1!=pos->mvpAtom.end();++at1) { sprintf(buf,"%5s : ",(*at1)->GetName().c_str()); cout<::iterator at2=at1;at2!=pos->mvpAtom.end();++at2) { if(at1==at2) continue; sprintf(buf,"%5s(%6.3f),",(*at2)->GetName().c_str(),GetBondLength(**at1,**at2)); cout<UpdateScattCompList(); VFN_DEBUG_EXIT("Molecule::GetScatteringComponentList()",3) return mScattCompList; } string Molecule::GetComponentName(const int i) const { //if(mvpAtom[i]->IsDummy()) return "Dummy"; return mvpAtom[i]->GetName(); } ostream& Molecule::POVRayDescription(ostream &os,const CrystalPOVRayOptions &options)const { VFN_DEBUG_ENTRY("Molecule::POVRayDescription()",3) const REAL xMin=options.mXmin; const REAL xMax=options.mXmax; const REAL yMin=options.mYmin; const REAL yMax=options.mYmax; const REAL zMin=options.mZmin; const REAL zMax=options.mZmax; if(mvpAtom.size()==0) { VFN_DEBUG_EXIT("Molecule::POVRayDescription():No atom to display !",4) return os; } this->UpdateScattCompList(); const REAL aa=this->GetCrystal().GetLatticePar(0); const REAL bb=this->GetCrystal().GetLatticePar(1); const REAL cc=this->GetCrystal().GetLatticePar(2); os << "// Description of Molecule :" << this->GetName() < vXYZCoords; { this->GetScatteringComponentList(); REAL x0,y0,z0; for(long i=0;iGetCrystal().GetSpaceGroup(). GetAllSymmetrics(x0,y0,z0,false,false,false)); } } CrystMatrix_int translate(27,3); translate= -1,-1,-1, -1,-1, 0, -1,-1, 1, -1, 0,-1, -1, 0, 0, -1, 0, 1, -1, 1,-1, -1, 1, 0, -1, 1, 1, 0,-1,-1, 0,-1, 0, 0,-1, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1, 0, 1,-1, 0, 1, 0, 0, 1, 1, 1,-1,-1, 1,-1, 0, 1,-1, 1, 1, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1,-1, 1, 1, 0, 1, 1, 1; REAL dx,dy,dz; CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size()); CrystVector_REAL xSave,ySave,zSave; const int nbSymmetrics=vXYZCoords[0].rows(); unsigned int ct=0; for(int i=0;i isinside(x.numElements()); CrystVector borderdist(x.numElements());//distance to display limit CrystVector x0,y0,z0; x0=x;y0=y;z0=z; if( ((x.min()xMin)) &&((y.min()yMin)) &&((z.min()zMin))) { os<<" //Symetric#"<<++ct<=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax)); if(isinside(k)) borderdist(k)=0; else { borderdist(k)=0; if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa; if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb; if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc; if(xMaxGetCrystal().GetDynPopCorr(this,k); this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k)); if((mvpAtom[k]->IsDummy()) || (fout<0.001)) continue; if(options.mShowHydrogens==false && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; // const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0]; // const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1]; // const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2]; const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy(); if(options.mShowLabel) { /* const float colour0[] = {0.0f, 0.0f, 0.0f, 0.0f}; GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } glMaterialfv(GL_FRONT, GL_AMBIENT, colour0); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS,colour0); glRasterPos3f(x(k), y(k), z(k)); crystGLPrint(mvpAtom[k]->GetName()); */ } os << " ObjCrystAtom(" <GetScatteringPower().GetRadius()/3.0<<"," <<"colour_"+mvpAtom[k]->GetScatteringPower().GetName()<<"," <GetAtom1().IsDummy()) ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue; if(options.mShowHydrogens==false && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5) ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue; unsigned long n1,n2; //:KLUDGE: Get the atoms for(n1=0;n1GetAtom1())) break; for(n2=0;n2GetAtom2())) break; REAL fout=1.0; if((isinside(n1)==false) || (isinside(n2)==false)) fout=exp(-(borderdist(n1)+borderdist(n2))/2)*(this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2; if(fout<0.001) continue; REAL x1=x(n1),y1=y(n1),z1=z(n1), x2=x(n2),y2=y(n2),z2=z(n2); REAL dx=x2-x1,dy=y2-y1,dz=z2-z1; const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6; const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0; const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0; x1+=dx/r*r1*sqrt(abs(1-0.1/r1)); y1+=dy/r*r1*sqrt(abs(1-0.1/r1)); z1+=dz/r*r1*sqrt(abs(1-0.1/r1)); x2-=dx/r*r2*sqrt(abs(1-0.1/r2)); y2-=dy/r*r2*sqrt(abs(1-0.1/r2)); z2-=dz/r*r2*sqrt(abs(1-0.1/r2)); const REAL f=this->GetOccupancy()*(mvpAtom[n1]->GetOccupancy()+mvpAtom[n2]->GetOccupancy())/2.0; os << " ObjCrystBond(" <IsFreeTorsion()) os<<"colour_freebond,"; else os<<"colour_nonfreebond,"; os<200) large=true; REAL en=1; if(displayEnantiomer==true) en=-1; this->UpdateScattCompList(); //this->BuildRingList(); //this->BuildStretchModeBondLength(); //this->BuildStretchModeBondAngle(); //this->BuildStretchModeTorsion(); const REAL aa=this->GetCrystal().GetLatticePar(0); const REAL bb=this->GetCrystal().GetLatticePar(1); const REAL cc=this->GetCrystal().GetLatticePar(2); const GLfloat colour0[] = {0.0f, 0.0f, 0.0f, 0.0f}; glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glPolygonMode(GL_FRONT, GL_FILL); GLUquadricObj* pQuadric = gluNewQuadric(); if(true==onlyIndependentAtoms)// { REAL xc=mXYZ(0),yc=mXYZ(1),zc=mXYZ(2); this->GetCrystal().FractionalToOrthonormalCoords(xc,yc,zc); vector::const_iterator pos; for(pos=mvpAtom.begin();pos!=mvpAtom.end();pos++) { if((*pos)->IsDummy())continue; if(hideHydrogens && ((*pos)->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; const float r=(*pos)->GetScatteringPower().GetColourRGB()[0]; const float g=(*pos)->GetScatteringPower().GetColourRGB()[1]; const float b=(*pos)->GetScatteringPower().GetColourRGB()[2]; const float f=(*pos)->GetOccupancy()*this->GetOccupancy(); glPushMatrix(); if(displayNames) { GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0}; GLfloat colourCharRing [] = {1.0, 1.0, 0.8, 1.0}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } if((*pos)->IsInRing()) glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing); else glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc); crystGLPrint((*pos)->GetName()); } else { const GLfloat colourAtom [] = {r, g, b, f}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colourAtom); glTranslatef((*pos)->X()*en+xc, (*pos)->Y()+yc, (*pos)->Z()+zc); gluSphere(pQuadric,(*pos)->GetScatteringPower().GetRadius()/3.,20,20); } glPopMatrix(); } }//Only independent atoms ? else { VFN_DEBUG_ENTRY("Molecule::GLInitDisplayList():Show all symmetrics",3) // Reverse index of atoms map rix; { long i=0; for(vector::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) rix[*pos]=i++; } vector vXYZCoords; { this->GetScatteringComponentList(); REAL x0,y0,z0; for(long i=0;iGetCrystal().GetSpaceGroup(). GetAllSymmetrics(x0,y0,z0,false,false,false)); } } CrystMatrix_int translate(27,3); translate= -1,-1,-1, -1,-1, 0, -1,-1, 1, -1, 0,-1, -1, 0, 0, -1, 0, 1, -1, 1,-1, -1, 1, 0, -1, 1, 1, 0,-1,-1, 0,-1, 0, 0,-1, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1, 0, 1,-1, 0, 1, 0, 0, 1, 1, 1,-1,-1, 1,-1, 0, 1,-1, 1, 1, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1,-1, 1, 1, 0, 1, 1, 1; REAL dx,dy,dz; CrystVector_REAL x(mvpAtom.size()),y(mvpAtom.size()),z(mvpAtom.size()); CrystVector_REAL xSave,ySave,zSave; const int nbSymmetrics=vXYZCoords[0].rows(); for(int i=0;i isinside(x.numElements()); CrystVector borderdist(x.numElements());//distance to display limit const bool molcenter_isinside =( ((x.sum()/x.size())>=xMin) && ((x.sum()/x.size())<=xMax) && ((y.sum()/y.size())>=yMin) && ((y.sum()/y.size())<=yMax) && ((z.sum()/z.size())>=zMin) && ((z.sum()/z.size())<=zMax)); if( ((x.min()<(xMax+fadeDistance/aa)) && (x.max()>(xMin-fadeDistance/aa))) &&((y.min()<(yMax+fadeDistance/bb)) && (y.max()>(yMin-fadeDistance/bb))) &&((z.min()<(zMax+fadeDistance/cc)) && (z.max()>(zMin-fadeDistance/cc)))) { for(unsigned int k=0;k=xMin) && (x(k)<=xMax)) && ((y(k)>=yMin) && (y(k)<=yMax)) && ((z(k)>=zMin) && (z(k)<=zMax)); if(isinside(k)) borderdist(k)=0; else { borderdist(k)=0; if(xMin>x(k)) borderdist(k)+=(xMin-x(k))*aa*(xMin-x(k))*aa; if(yMin>y(k)) borderdist(k)+=(yMin-y(k))*bb*(yMin-y(k))*bb; if(zMin>z(k)) borderdist(k)+=(zMin-z(k))*cc*(zMin-z(k))*cc; if(xMaxfadeDistance) fout = 0; else fout*=(fadeDistance-borderdist(k))/fadeDistance*this->GetCrystal().GetDynPopCorr(this,k); } #ifdef __DEBUG__ char ch[100]; sprintf(ch,"%d %d %d %s %5.2f %5.2f %5.2f d=%5.2f fout=%5.3f",i,j,k,mvpAtom[k]->GetName().c_str(),x(k),y(k),z(k),borderdist(k),fout); VFN_DEBUG_MESSAGE(ch,4) #endif this->GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k)); if(mvpAtom[k]->IsDummy()) continue; if(hideHydrogens && (mvpAtom[k]->GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; if(fout<0.01) continue; glPushMatrix(); const float r=mvpAtom[k]->GetScatteringPower().GetColourRGB()[0]; const float g=mvpAtom[k]->GetScatteringPower().GetColourRGB()[1]; const float b=mvpAtom[k]->GetScatteringPower().GetColourRGB()[2]; const float f=mvpAtom[k]->GetOccupancy()*this->GetOccupancy(); if(displayNames) { if((fout>0.99) || molcenter_isinside) { GLfloat colourChar [] = {1.0, 1.0, 1.0, f*fout}; GLfloat colourCharRing [] = {1.0, 1.0, 0.8, f*fout}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } if(mvpAtom[k]->IsInRing()) glMaterialfv(GL_FRONT, GL_EMISSION, colourCharRing); else glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glRasterPos3f(x(k)*en, y(k), z(k)); crystGLPrint(mvpAtom[k]->GetName()); } } else { if(!large) { const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom); glTranslatef(x(k)*en, y(k), z(k)); gluSphere(pQuadric, mvpAtom[k]->GetScatteringPower().GetRadius()/3.,20,20); } else { const GLfloat colourAtom [] = {r*fout, g*fout, b*fout, f*fout}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,colourAtom); glTranslatef(x(k)*en, y(k), z(k)); gluSphere(pQuadric,.15,10,10); } } glPopMatrix(); } if(displayNames==false) { if(large) { for(unsigned int k=0;kGetAtom1().IsDummy()) ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue; if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5) ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue; const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())], n2=rix[&(mvpBond[k]->GetAtom2())]; REAL fout=1.0; if(((isinside(n1)==false) || (isinside(n2)==false)) && ((molcenter_isinside==false) || (fullMoleculeInLimits==false))) { if((fadeDistance==0) || ((borderdist(n1)+borderdist(n2))/2)>fadeDistance) fout = 0; else fout*=(fadeDistance-(borderdist(n1)+borderdist(n2))/2)/fadeDistance* (this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2; } if(fout<0.01) continue; const float r1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[0]; const float g1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[1]; const float b1=mvpBond[k]->GetAtom1().GetScatteringPower().GetColourRGB()[2]; const float f1=mvpBond[k]->GetAtom1().GetOccupancy()*this->GetOccupancy(); const float r2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[0]; const float g2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[1]; const float b2=mvpBond[k]->GetAtom2().GetScatteringPower().GetColourRGB()[2]; const float f2=mvpBond[k]->GetAtom2().GetOccupancy()*this->GetOccupancy(); const GLfloat colourAtom1 [] = {r1, g1, b1, f1*fout}; const GLfloat colourAtom2 [] = {r2, g2, b2, f2*fout}; #if 0 glPushMatrix(); glBegin(GL_LINE_STRIP); glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom1); glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom1); glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom1); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f((x(n1)+x(n2))/2*en,(y(n1)+y(n2))/2,(z(n1)+z(n2))/2); glMaterialfv(GL_FRONT, GL_SPECULAR, colourAtom2); glMaterialfv(GL_FRONT, GL_EMISSION, colourAtom2); glMaterialfv(GL_FRONT, GL_SHININESS, colourAtom2); glVertex3f(x(n2)*en,y(n2),z(n2)); glEnd(); glPopMatrix(); #else const REAL height= sqrt(abs( (x(n2)-x(n1))*(x(n2)-x(n1)) +(y(n2)-y(n1))*(y(n2)-y(n1)) +(z(n2)-z(n1))*(z(n2)-z(n1)))); glPushMatrix(); glTranslatef(x(n1)*en, y(n1), z(n1)); GLUquadricObj *quadobj = gluNewQuadric(); glRotatef(180,(x(n2)-x(n1))*en,y(n2)-y(n1),z(n2)-z(n1)+height);// ?!?!?! glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom1); gluCylinder(quadobj,.1,.1,height/2,10,1 ); gluDeleteQuadric(quadobj); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colourAtom2); GLUquadricObj *quadobj2 = gluNewQuadric(); glTranslatef(0, 0, height/2); gluCylinder(quadobj2,.1,.1,height/2,10,1 ); gluDeleteQuadric(quadobj2); glPopMatrix(); #endif } } else { for(unsigned int k=0;kGetAtom1().IsDummy()) ||(mvpBond[k]->GetAtom2().IsDummy()) ) continue; if(hideHydrogens && ( (mvpBond[k]->GetAtom1().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5) ||(mvpBond[k]->GetAtom2().GetScatteringPower().GetForwardScatteringFactor(RAD_XRAY)<1.5))) continue; const unsigned long n1=rix[&(mvpBond[k]->GetAtom1())], n2=rix[&(mvpBond[k]->GetAtom2())]; REAL fout=1.0; //if((isinside(n1)==false) || (isinside(n2)==false)) fout=exp(-(borderdist(n1)+borderdist(n2))/2); if(((isinside(n1)==false) || (isinside(n2)==false)) && ((molcenter_isinside==false) || (fullMoleculeInLimits==false))) { if ((fadeDistance == 0) || ((borderdist(n1) + borderdist(n2)) / 2)>fadeDistance) fout = 0; else fout=(fadeDistance-(borderdist(n1)+borderdist(n2))/2)/fadeDistance* (this->GetCrystal().GetDynPopCorr(this,n1)+this->GetCrystal().GetDynPopCorr(this,n2))/2; } if(fout<0.01) continue; // Is the bond in a rigid group ? bool isRigidGroup=false; for(vector::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { if( ((*pos)->find(&(mvpBond[k]->GetAtom1()))!=(*pos)->end()) &&((*pos)->find(&(mvpBond[k]->GetAtom2()))!=(*pos)->end()) ) { isRigidGroup=true; break; } } const float f=(mvpBond[k]->GetAtom1().GetOccupancy()+mvpBond[k]->GetAtom2().GetOccupancy())/2*this->GetOccupancy(); const GLfloat colour_bondnonfree[]= { 0.2f*fout, .2f*fout, .2f*fout, f*fout }; const GLfloat colour_bondrigid[]= { 0.5f*fout, .3f*fout, .3f*fout, f*fout }; const GLfloat colour_bondfree[]= { 0.8f*fout, .8f*fout, .8f*fout, f*fout }; if(isRigidGroup) glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondrigid); else { if(mvpBond[k]->IsFreeTorsion()) glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondfree); else glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,colour_bondnonfree); } // Actually make the bond start/end at the surface of the spheres (matters when transparent) REAL x1=x(n1),y1=y(n1),z1=z(n1), x2=x(n2),y2=y(n2),z2=z(n2); REAL dx=x2-x1,dy=y2-y1,dz=z2-z1; const REAL r=sqrt(abs(dx*dx+dy*dy+dz*dz))+1e-6; const REAL r1=mvpAtom[n1]->GetScatteringPower().GetRadius()/3.0; const REAL r2=mvpAtom[n2]->GetScatteringPower().GetRadius()/3.0; x1+=dx/r*r1*sqrt(abs(1-0.1/r1)); y1+=dy/r*r1*sqrt(abs(1-0.1/r1)); z1+=dz/r*r1*sqrt(abs(1-0.1/r1)); x2-=dx/r*r2*sqrt(abs(1-0.1/r2)); y2-=dy/r*r2*sqrt(abs(1-0.1/r2)); z2-=dz/r*r2*sqrt(abs(1-0.1/r2)); glPushMatrix(); glTranslatef(x1*en, y1, z1); GLUquadricObj *quadobj = gluNewQuadric(); //glColor4f(1.0f,1.0f,1.0f,1.0); const REAL height= sqrt(abs( (x2-x1)*(x2-x1) +(y2-y1)*(y2-y1) +(z2-z1)*(z2-z1))); glRotatef(180,(x2-x1)*en,y2-y1,z2-z1+height);// ?!?!?! gluCylinder(quadobj,.1,.1,height,10,1 ); gluDeleteQuadric(quadobj); glPopMatrix(); } } } }//if in limits x=xSave; y=ySave; z=zSave; }//for translation VFN_DEBUG_EXIT("Molecule::GLInitDisplayList():Symmetric#"<GetName()==this->GetFormula(); string thename=name; if(thename==string("")) {// This should not be needed, the atom will reset the parameters name when its name is set char buf[100]; if(pPow!=0) sprintf(buf,"%s_%s_%lu",this->GetName().c_str(),pPow->GetName().c_str(),mvpAtom.size()+1); else sprintf(buf,"%s_X_%lu",this->GetName().c_str(),mvpAtom.size()+1); thename=buf; } mvpAtom.push_back(new MolAtom(x,y,z,pPow,thename,*this)); mClockAtomPosition.Click(); mClockAtomScattPow.Click(); ++mScattCompList; { RefinablePar tmp(thename+"_x",&(mvpAtom.back()->X()),0.,1., gpRefParTypeScattConformX, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(thename+"_y",&(mvpAtom.back()->Y()),0.,1., gpRefParTypeScattConformY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp(thename+"_z",&(mvpAtom.back()->Z()),0.,1., gpRefParTypeScattConformZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } mClockScatterer.Click(); if(molnameasformula || (this->GetName().size()==0)) this->SetName(this->GetFormula()); if(updateDisplay) this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::AddAtom()",5) } vector::iterator Molecule::RemoveAtom(MolAtom &atom, const bool del) { VFN_DEBUG_ENTRY("Molecule::RemoveAtom():"<::iterator pos=find(mvpAtom.begin(),mvpAtom.end(),&atom); if(pos==mvpAtom.end()) { throw ObjCrystException("Molecule::RemoveAtom():"+atom.GetName() +" is not in this Molecule:"+this->GetName()); } const bool molnameasformula= this->GetName()==this->GetFormula(); // Delete parameters this->RemovePar(&(this->GetPar(&(atom.X())))); this->RemovePar(&(this->GetPar(&(atom.Y())))); this->RemovePar(&(this->GetPar(&(atom.Z())))); // Delete relevant bonds, bond angles, dihedral angles... for(vector::iterator posb=mvpBond.begin();posb!=mvpBond.end();) { if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2())) ) { posb=this->RemoveBond(**posb, del); } else ++posb; } for(vector::iterator posb=mvpBondAngle.begin();posb!=mvpBondAngle.end();) { if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2())) ||(&atom==&((*posb)->GetAtom3()))) { posb=this->RemoveBondAngle(**posb, del); } else ++posb; } for(vector::iterator posb=mvpDihedralAngle.begin(); posb!=mvpDihedralAngle.end();) { if( (&atom==&((*posb)->GetAtom1())) || (&atom==&((*posb)->GetAtom2())) ||(&atom==&((*posb)->GetAtom3())) || (&atom==&((*posb)->GetAtom4()))) posb=this->RemoveDihedralAngle(**posb, del); else ++posb; } mClockAtomList.Click(); mClockScatterer.Click(); if(mpCenterAtom==*pos) mpCenterAtom=0; if(del) delete *pos; pos=mvpAtom.erase(pos); --mScattCompList; if(molnameasformula || (this->GetName().size()==0)) this->SetName(this->GetFormula()); this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::RemoveAtom()",6) return pos; } void Molecule::AddBond(MolAtom &atom1, MolAtom &atom2, const REAL length, const REAL sigma, const REAL delta, const REAL bondOrder, const bool updateDisplay) { VFN_DEBUG_ENTRY("Molecule::AddBond()",5) mvpBond.push_back(new MolBond(atom1,atom2,length,sigma,delta,*this,bondOrder)); this->AddRestraint(mvpBond.back()); mClockBondList.Click(); if(updateDisplay) this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::AddBond()",5) } vector::iterator Molecule::RemoveBond(const MolBond &bond, const bool del) { VFN_DEBUG_ENTRY("Molecule::RemoveBond():"<::iterator pos=find(mvpBond.begin(),mvpBond.end(),&bond); if(pos==mvpBond.end()) { throw ObjCrystException("Molecule::RemoveBond():"+bond.GetAtom1().GetName() +"-"+bond.GetAtom2().GetName() +" is not in this Molecule:"+this->GetName()); } this->RemoveRestraint(*pos); mClockBondList.Click(); if(del) delete *pos; pos= mvpBond.erase(pos); this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::RemoveBond():",6) return pos; } vector::const_iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2)const { for(vector::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) { if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2)) ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1))) return pos; } return mvpBond.end(); } vector::iterator Molecule::FindBond(const MolAtom &at1,const MolAtom &at2) { for(vector::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) { if( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2)) ||((&((*pos)->GetAtom1())==&at2)&&(&((*pos)->GetAtom2())==&at1))) return pos; } return mvpBond.end(); } void Molecule::AddBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay) { VFN_DEBUG_ENTRY("Molecule::AddBondAngle()",5) mvpBondAngle.push_back(new MolBondAngle(atom1,atom2,atom3,angle,sigma,delta,*this)); this->AddRestraint(mvpBondAngle.back()); mClockBondAngleList.Click(); if(updateDisplay) this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::AddBondAngle()",5) } vector::iterator Molecule::RemoveBondAngle(const MolBondAngle &angle, const bool del) { VFN_DEBUG_ENTRY("Molecule::RemoveBondAngle():"<::iterator pos=find(mvpBondAngle.begin(),mvpBondAngle.end(),&angle); if(pos==mvpBondAngle.end()) { throw ObjCrystException("Molecule::RemoveBondAngle():"+angle.GetAtom1().GetName() +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName() +" is not in this Molecule:"+this->GetName()); } this->RemoveRestraint(*pos); mClockBondAngleList.Click(); if(del) delete *pos; pos=mvpBondAngle.erase(pos); this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::RemoveBondAngle():",6) return pos; } vector::const_iterator Molecule::FindBondAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3)const { for(vector::const_iterator pos=mvpBondAngle.begin(); pos!=mvpBondAngle.end();++pos) { if( (&((*pos)->GetAtom2())==&at2) &&( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom3())==&at3)) ||((&((*pos)->GetAtom1())==&at3)&&(&((*pos)->GetAtom3())==&at1)))) return pos; } return mvpBondAngle.end(); } void Molecule::AddDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay) { VFN_DEBUG_ENTRY("Molecule::AddDihedralAngle()",5) mvpDihedralAngle.push_back(new MolDihedralAngle(atom1,atom2,atom3,atom4, angle,sigma,delta,*this)); this->AddRestraint(mvpDihedralAngle.back()); mClockDihedralAngleList.Click(); if(updateDisplay) this->UpdateDisplay(); VFN_DEBUG_EXIT("Molecule::AddDihedralAngle()",5) } vector::iterator Molecule::RemoveDihedralAngle(const MolDihedralAngle &angle, const bool del) { VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():"<::iterator pos=find(mvpDihedralAngle.begin(), mvpDihedralAngle.end(),&angle); if(pos==mvpDihedralAngle.end()) { throw ObjCrystException("Molecule::RemoveDihedralAngle():"+angle.GetAtom1().GetName() +"-"+angle.GetAtom2().GetName()+"-"+angle.GetAtom3().GetName() +"-"+angle.GetAtom4().GetName() +" is not in this Molecule:"+this->GetName()); } this->RemoveRestraint(*pos); mClockDihedralAngleList.Click(); if(del) delete *pos; pos=mvpDihedralAngle.erase(pos); this->UpdateDisplay(); VFN_DEBUG_ENTRY("Molecule::RemoveDihedralAngle():",6) return pos; } vector::const_iterator Molecule::FindDihedralAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3, const MolAtom &at4)const { for(vector::const_iterator pos=mvpDihedralAngle.begin(); pos!=mvpDihedralAngle.end();++pos) { if( ( ((&((*pos)->GetAtom1())==&at1)&&(&((*pos)->GetAtom2())==&at2)) &&((&((*pos)->GetAtom3())==&at3)&&(&((*pos)->GetAtom4())==&at4))) ||( ((&((*pos)->GetAtom4())==&at1)&&(&((*pos)->GetAtom3())==&at2)) &&((&((*pos)->GetAtom2())==&at3)&&(&((*pos)->GetAtom1())==&at4)))) return pos; } return mvpDihedralAngle.end(); } void Molecule::AddRigidGroup(const RigidGroup &group, const bool updateDisplay) { mvRigidGroup.push_back(new RigidGroup(group)); #ifdef RIGID_BODY_STRICT_EXPERIMENTAL char buf[50]; const unsigned int i=mvRigidGroup.size(); RigidGroup* p=this->GetRigidGroupList().back(); p->mX=0; p->mY=0; p->mZ=0; p->mQuat.Q0()=1; p->mQuat.Q1()=0; p->mQuat.Q2()=0; p->mQuat.Q3()=0; { sprintf(buf,"RigidGroup%d_x",i); RefinablePar tmp(buf,&(p->mX),0.,1., gpRefParTypeScattConformX, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { sprintf(buf,"RigidGroup%d_y",i); RefinablePar tmp(buf,&(p->mY),0.,1., gpRefParTypeScattConformY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { sprintf(buf,"RigidGroup%d_z",i); RefinablePar tmp(buf,&(p->mZ),0.,1., gpRefParTypeScattConformZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.05); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { sprintf(buf,"RigidGroup%d_Q1",i); RefinablePar tmp(buf,&(p->mQuat.Q1()),-1,1., gpRefParTypeScattConform, REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.01); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { sprintf(buf,"RigidGroup%d_Q2",i); RefinablePar tmp(buf,&(p->mQuat.Q2()),-1,1., gpRefParTypeScattConform, REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.01); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { sprintf(buf,"RigidGroup%d_Q3",i); RefinablePar tmp(buf,&(p->mQuat.Q3()),-1,1., gpRefParTypeScattConform, REFPAR_DERIV_STEP_ABSOLUTE,true,false,true,false,1.,1.); tmp.AssignClock(mClockAtomPosition); tmp.SetGlobalOptimStep(0.01); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } #endif mClockRigidGroup.Click(); if(updateDisplay) this->UpdateDisplay(); } vector::iterator Molecule::RemoveRigidGroup(const RigidGroup &g,const bool updateDisplay, const bool del) { vector::iterator pos=find(mvRigidGroup.begin(),mvRigidGroup.end(),&g); if(pos==mvRigidGroup.end()) return pos; #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // Remove the refinable parameters (even if del==False - used for python delayed deletion) // NOTE - this should only be done outside an optimization, since rigid group translationnal // and rotationnal parameters are resetted at the end of the optimization, and the atomic // parameters are directly the correct ones (thus deletion of the rigid group does not change // the final coordinates). this->RemovePar(&(this->GetPar(&((*pos)->mX)))); this->RemovePar(&(this->GetPar(&((*pos)->mY)))); this->RemovePar(&(this->GetPar(&((*pos)->mZ)))); this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q1())))); this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q2())))); this->RemovePar(&(this->GetPar(&((*pos)->mQuat.Q3())))); #endif if(del) delete *pos; pos=mvRigidGroup.erase(pos); if(updateDisplay) this->UpdateDisplay(); return pos; } MolAtom &Molecule::GetAtom(unsigned int i){return *mvpAtom[i];} const MolAtom &Molecule::GetAtom(unsigned int i)const{return *mvpAtom[i];} MolAtom &Molecule::GetAtom(const string &name){return **(this->FindAtom(name));} const MolAtom &Molecule::GetAtom(const string &name)const{return **(this->FindAtom(name));} void Molecule::OptimizeConformation(const long nbTrial,const REAL stopCost) { VFN_DEBUG_ENTRY("Molecule::OptimizeConformation()",5) MonteCarloObj globalOptObj(true); globalOptObj.AddRefinableObj(*this); globalOptObj.SetAlgorithmParallTempering(ANNEALING_EXPONENTIAL,10000.,1., ANNEALING_EXPONENTIAL,10,.1); long nb=nbTrial; mIsSelfOptimizing=true; globalOptObj.Optimize(nb,false,stopCost); mIsSelfOptimizing=false; // Must rebuild Flip & Rotor group, in case they were tested with an absurd conformation mClockFlipGroup.Reset(); mClockRotorGroup.Reset(); VFN_DEBUG_EXIT("Molecule::OptimizeConformation()",5) } void Molecule::OptimizeConformationSteepestDescent(const REAL maxStep,const unsigned nbStep) { //cout<<"LLK="<GetLogLikelihood()< grad; for(vector::iterator pos=this->GetAtomList().begin(); pos!=this->GetAtomList().end();++pos) grad[*pos]=XYZ(0,0,0); // :TODO: remove atoms that are in rigid groups ? for(vector::iterator pos=this->GetBondList().begin(); pos!=this->GetBondList().end();++pos) (*pos)->CalcGradient(grad); for(vector::iterator pos=this->GetBondAngleList().begin(); pos!=this->GetBondAngleList().end();++pos) (*pos)->CalcGradient(grad); for(vector::iterator pos=this->GetDihedralAngleList().begin(); pos!=this->GetDihedralAngleList().end();++pos) (*pos)->CalcGradient(grad); #if 0 // Display gradient - for tests for(map::const_iterator pos=grad.begin();pos!=grad.end();++pos) { char buf[100]; sprintf(buf,"%10s Grad LLK= (%8.3f %8.3f %8.3f)", pos->first->GetName().c_str(),pos->second.x,pos->second.y,pos->second.z); cout<::const_iterator pos=grad.begin();pos!=grad.end();++pos) { if(abs(pos->second.x)>f) f=abs(pos->second.x); if(abs(pos->second.y)>f) f=abs(pos->second.y); if(abs(pos->second.z)>f) f=abs(pos->second.z); } if(f>1e-6) f=maxStep/f; else break;//nothing to optimize ? // Average derivatives inside rigid groups //:TODO: still allow rotations of rigid groups ? //:TODO: Handle case when one atom belongs to several rigid groups... for(vector::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { if((*pos)->size()==0) continue; // Just in case... REAL dx=0,dy=0,dz=0; for(set::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at) { dx+=(*at)->GetX(); dy+=(*at)->GetY(); dz+=(*at)->GetZ(); } dx/=(*pos)->size(); dy/=(*pos)->size(); dz/=(*pos)->size(); for(set::const_iterator at=(*pos)->begin();at!=(*pos)->end();++at) { grad[*at].x=dx; grad[*at].y=dy; grad[*at].z=dz; } } // Move according to max step to minimize LLK for(map::const_iterator pos=grad.begin();pos!=grad.end();++pos) { pos->first->SetX(pos->first->GetX()-pos->second.x*f); pos->first->SetY(pos->first->GetY()-pos->second.y*f); pos->first->SetZ(pos->first->GetZ()-pos->second.z*f); } //this->RestraintStatus(cout); //cout<<"LLK="<GetLogLikelihood()< &v0,const unsigned nbStep,const REAL dt, const vector &vb,const vector &va, const vector &vd, map > &vr, REAL nrj0) { const vector *pvb=&vb; const vector *pva=&va; const vector *pvd=&vd; map > *pvr=&vr; if((pvb->size()==0)&&(pva->size()==0)&&(pvd->size()==0)) { pvb=&(this->GetBondList()); pva=&(this->GetBondAngleList()); pvd=&(this->GetDihedralAngleList()); for(vector::iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) (*pvr)[*pos]=make_pair(XYZ(0,0,0),XYZ(0,0,0)); } const REAL m=500;// mass const REAL im=1./m; // Try to keep total energy constant REAL e_v,e_k,v_r=1.0; for(unsigned i = 0; i < nbStep; ++i) { // Calc full gradient map grad; for(map::iterator pos=v0.begin();pos!=v0.end();++pos) grad[pos->first]=XYZ(0,0,0); // :TODO: handle rigid groups ? e_v=0; for(vector::const_iterator pos=pvb->begin();pos!=pvb->end();++pos) { (*pos)->CalcGradient(grad); e_v+=(*pos)->GetLogLikelihood(false,false); } for(vector::const_iterator pos=pva->begin();pos!=pva->end();++pos) { (*pos)->CalcGradient(grad); e_v+=(*pos)->GetLogLikelihood(false,false); } for(vector::const_iterator pos=pvd->begin();pos!=pvd->end();++pos) { (*pos)->CalcGradient(grad); e_v+=(*pos)->GetLogLikelihood(false,false); } //kinetic energy e_k=0; for(map::const_iterator pos=v0.begin();pos!=v0.end();++pos) e_k += 0.5*m*(pos->second.x*pos->second.x + pos->second.y*pos->second.y + pos->second.z*pos->second.z); if(nrj0==0) nrj0=e_k+e_v; else { // Apply a coefficient to the speed to keep the overall energy constant const REAL de=e_k+e_v-nrj0; if(de::iterator pos=v0.begin();pos!=v0.end();++pos) { sprintf(buf,"%10s xyz= (%8.3f %8.3f %8.3f) v= (%8.3f %8.3f %8.3f) m*a= (%8.3f %8.3f %8.3f)", pos->first->GetName().c_str(), pos->first->GetX(),pos->first->GetY(),pos->first->GetZ(), v0[*pos].x ,v0[*pos].y ,v0[*pos].z, -grad[*pos].x*im,-grad[*pos].y*im,-grad[*pos].z*im); //cout<::const_iterator pos=v0.begin();pos!=v0.end();++pos) { const XYZ *pa=&(grad[pos->first]); pos->first->SetX(pos->first->GetX()+pos->second.x*dt*v_r-0.5*im*dt*dt*pa->x); pos->first->SetY(pos->first->GetY()+pos->second.y*dt*v_r-0.5*im*dt*dt*pa->y); pos->first->SetZ(pos->first->GetZ()+pos->second.z*dt*v_r-0.5*im*dt*dt*pa->z); } // Compute new speed for(map::iterator pos=v0.begin();pos!=v0.end();++pos) { const XYZ *pa=&(grad[pos->first]); pos->second.x = v_r*pos->second.x - pa->x*dt*im; pos->second.y = v_r*pos->second.y - pa->y*dt*im; pos->second.z = v_r*pos->second.z - pa->z*dt*im; } } } const vector& Molecule::GetAtomList()const{return mvpAtom;} const vector& Molecule::GetBondList()const{return mvpBond;} const vector& Molecule::GetBondAngleList()const{return mvpBondAngle;} const vector& Molecule::GetDihedralAngleList()const{return mvpDihedralAngle;} vector& Molecule::GetAtomList(){return mvpAtom;} vector& Molecule::GetBondList(){return mvpBond;} vector& Molecule::GetBondAngleList(){return mvpBondAngle;} vector& Molecule::GetDihedralAngleList(){return mvpDihedralAngle;} list& Molecule::GetStretchModeBondLengthList(){return mvStretchModeBondLength;} list& Molecule::GetStretchModeBondAngleList(){return mvStretchModeBondAngle;} list& Molecule::GetStretchModeTorsionList(){return mvStretchModeTorsion;} const list& Molecule::GetStretchModeBondLengthList()const{return mvStretchModeBondLength;} const list& Molecule::GetStretchModeBondAngleList()const{return mvStretchModeBondAngle;} const list& Molecule::GetStretchModeTorsionList()const{return mvStretchModeTorsion;} const std::vector& Molecule::GetRigidGroupList()const{return mvRigidGroup;} std::vector& Molecule::GetRigidGroupList() {return mvRigidGroup;} void Molecule::RotateAtomGroup(const MolAtom &at1,const MolAtom &at2, const set &atoms, const REAL angle, const bool keepCenter) { const REAL vx=at2.X()-at1.X(); const REAL vy=at2.Y()-at1.Y(); const REAL vz=at2.Z()-at1.Z(); this->RotateAtomGroup(at1,vx,vy,vz,atoms,angle,keepCenter); } void Molecule::RotateAtomGroup(const MolAtom &at,const REAL vx,const REAL vy,const REAL vz, const set &atoms, const REAL angle, const bool keepCenter) { TAU_PROFILE("Molecule::RotateAtomGroup(MolAtom&,vx,vy,vz,...)","void (...)",TAU_DEFAULT); if(atoms.size()==0) return; const REAL x0=at.X(); const REAL y0=at.Y(); const REAL z0=at.Z(); // :KLUDGE: ? Refuse to do anything if vector is not well defined if((fabs(vx)+fabs(vy)+fabs(vz))<1e-6) return; REAL dx=0.,dy=0.,dz=0.; bool keepc=keepCenter; if(keepc) if( (this->GetPar(mXYZ.data() ).IsFixed()) ||(this->GetPar(mXYZ.data()+1).IsFixed()) ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false; #if 0 const REAL ca=cos(angle),sa=sin(angle); const REAL ca1=1-ca; const REAL vnorm=1/sqrt(vx*vx+vy*vy+vz*vz); const REAL ux=vx*vnorm,uy=vy*vnorm,uz=vz*vnorm; const REAL m00=ca+ux*ux*ca1;// See http://en.wikipedia.org/wiki/Rotation_matrix const REAL m01=ux*uy*ca1-uz*sa; const REAL m02=ux*uz*ca1+uy*sa; const REAL m10=uy*ux*ca1+uz*sa; // :TODO: Check formulas ! const REAL m11=ca+uy*uy*ca1; const REAL m12=uy*uz*ca1-ux*sa; const REAL m20=uz*ux*ca1-uy*sa; const REAL m21=uz*uy*ca1+ux*sa; const REAL m22=ca+uz*uz*ca1; for(set::const_iterator pos=atoms.begin();pos!=atoms.end();++pos) { if(keepc) { dx -= (*pos)->X(); dy -= (*pos)->Y(); dz -= (*pos)->Z(); } const REAL x=(*pos)->X() - x0; const REAL y=(*pos)->Y() - y0; const REAL z=(*pos)->Z() - z0; (*pos)->X() = m00*x+m01*y+m02*z+x0; (*pos)->Y() = m10*x+m11*y+m12*z+y0; (*pos)->Z() = m20*x+m21*y+m22*z+z0; if(keepc) { dx += (*pos)->X(); dy += (*pos)->Y(); dz += (*pos)->Z(); } } #else const Quaternion quat=Quaternion::RotationQuaternion(angle,vx,vy,vz); for(set::const_iterator pos=atoms.begin();pos!=atoms.end();++pos) { if(keepc) { dx -= (*pos)->X(); dy -= (*pos)->Y(); dz -= (*pos)->Z(); } (*pos)->X() -= x0; (*pos)->Y() -= y0; (*pos)->Z() -= z0; quat.RotateVector((*pos)->X(),(*pos)->Y(),(*pos)->Z()); (*pos)->X() += x0; (*pos)->Y() += y0; (*pos)->Z() += z0; if(keepc) { dx += (*pos)->X(); dy += (*pos)->Y(); dz += (*pos)->Z(); } } #endif // (dx,dy,dz) = vector of the translation of the center of the molecule due to the rotation if(keepc) { dx /= (REAL)(this->GetNbComponent()); dy /= (REAL)(this->GetNbComponent()); dz /= (REAL)(this->GetNbComponent()); mQuat.RotateVector(dx,dy,dz); this->GetCrystal().OrthonormalToFractionalCoords(dx,dy,dz); mXYZ(0) += dx; mXYZ(1) += dy; mXYZ(2) += dz; } mClockAtomPosition.Click(); mClockScatterer.Click(); } void Molecule::TranslateAtomGroup(const set &atoms, const REAL dx,const REAL dy,const REAL dz, const bool keepCenter) { for(set::const_iterator pos=atoms.begin();pos!=atoms.end();++pos) { (*pos)->X() += dx; (*pos)->Y() += dy; (*pos)->Z() += dz; } bool keepc=keepCenter; if(keepc) if( (this->GetPar(mXYZ.data() ).IsFixed()) ||(this->GetPar(mXYZ.data()+1).IsFixed()) ||(this->GetPar(mXYZ.data()+2).IsFixed())) keepc=false; if(keepc) { const REAL r= (REAL)(atoms.size())/(REAL)(this->GetNbComponent()); REAL dxc=dx*r,dyc=dy*r,dzc=dz*r; this->GetCrystal().OrthonormalToFractionalCoords(dxc,dyc,dzc); mXYZ(0) += dxc; mXYZ(1) += dyc; mXYZ(2) += dzc; } mClockAtomPosition.Click(); mClockScatterer.Click(); } void Molecule::RestraintExport(ostream &os)const { VFN_DEBUG_ENTRY("Molecule::RestraintExport()",5) os<<"BondName, IdealLength, Length, log(likelihood)"<::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) os <<(*pos)->GetName() <<", "<<(*pos)->GetLength0() <<", "<<(*pos)->GetLength() <<", "<<(*pos)->GetLogLikelihood()<::const_iterator pos=mvpBondAngle.begin(); pos!=mvpBondAngle.end();++pos) os <<(*pos)->GetName() <<", "<<(*pos)->Angle0()*180/M_PI <<", "<<(*pos)->GetAngle()*180/M_PI <<", "<<(*pos)->GetLogLikelihood()<::const_iterator pos=mvpDihedralAngle.begin(); pos!=mvpDihedralAngle.end();++pos) os <<(*pos)->GetName() <<", "<<(*pos)->Angle0()*180/M_PI <<", "<<(*pos)->GetAngle()*180/M_PI <<", "<<(*pos)->GetLogLikelihood()<::const_iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) cout <<"Bond "<<(*pos)->GetName() <<", IdealLength="<<(*pos)->GetLength0() <<", Length="<<(*pos)->GetLength() <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<::const_iterator pos=mvpBondAngle.begin(); pos!=mvpBondAngle.end();++pos) cout <<"Bond Angle "<<(*pos)->GetName() <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI <<", Angle="<<(*pos)->GetAngle()*180/M_PI <<", log(likelihood)="<<(*pos)->GetLogLikelihood()<::const_iterator pos=mvpDihedralAngle.begin(); pos!=mvpDihedralAngle.end();++pos) cout <<"Dihedral Angle "<<(*pos)->GetName() <<", IdealAngle="<<(*pos)->Angle0()*180/M_PI <<", Angle="<<(*pos)->GetAngle()*180/M_PI <<", log(likelihood)="<<(*pos)->GetLogLikelihood()< > &Molecule::GetConnectivityTable() { this->BuildConnectivityTable(); return mConnectivityTable; } RefinableObjClock& Molecule::GetBondListClock(){return mClockBondList;} const RefinableObjClock& Molecule::GetBondListClock()const{return mClockBondList;} RefinableObjClock& Molecule::GetAtomPositionClock(){return mClockAtomPosition;} const RefinableObjClock& Molecule::GetAtomPositionClock()const{return mClockAtomPosition;} const RefinableObjClock& Molecule::GetAtomScattPowClock()const { return mClockAtomScattPow;} RefinableObjClock& Molecule::GetAtomScattPowClock() { return mClockAtomScattPow;} RefinableObjClock& Molecule::GetRigidGroupClock(){return mClockRigidGroup;} const RefinableObjClock& Molecule::GetRigidGroupClock()const{return mClockRigidGroup;} void Molecule::RigidifyWithDihedralAngles() { this->BuildConnectivityTable(); for(vector::iterator bond=mvpBond.begin();bond!=mvpBond.end();++bond) { MolAtom* at2=&((*bond)->GetAtom1()); MolAtom* at3=&((*bond)->GetAtom2()); for(set::const_iterator c2=mConnectivityTable[at2].begin(); c2!=mConnectivityTable[at2].end();++c2) { //MolAtom* at1=mvpAtom[*c2]; if(*c2==at3) continue; if(GetBondAngle(**c2,*at2,*at3)<(10 *DEG2RAD)) continue; if(GetBondAngle(**c2,*at2,*at3)>(180*DEG2RAD)) continue; for(set::const_iterator c3=mConnectivityTable[at3].begin(); c3!=mConnectivityTable[at3].end();++c3) { //MolAtom* at4=mvpAtom[*c3]; if((*c3==at2)||(*c3==*c2)) continue; if(GetBondAngle(*at2,*at3,**c3)<(10 *DEG2RAD)) continue; if(GetBondAngle(*at2,*at3,**c3)>(180*DEG2RAD)) continue; if(this->FindDihedralAngle(**c2,*at2,*at3,**c3)==mvpDihedralAngle.end()) { const REAL dihed=GetDihedralAngle(**c2,*at2,*at3,**c3); this->AddDihedralAngle(**c2,*at2,*at3,**c3,dihed,.01,.05,false); } } } } this->UpdateDisplay(); } #if 0 /** x array for the Integral[0->x](exp(+t*t)dt) * */ static const REAL svGaussianIntX[51] ={0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. }; /** This is Integral[0->x](exp(+t*t)dt) * */ static const REAL svGaussianIntY[51] ={0.00000000e+00, 1.00285768e-01, 2.02498389e-01, 3.08782899e-01, 4.21537858e-01, 5.43577677e-01, 6.78339751e-01, 8.30161516e-01, 1.00466359e+00, 1.20929269e+00, 1.45410564e+00, 1.75292008e+00, 2.12502806e+00, 2.59778353e+00, 3.21056320e+00, 4.02091257e+00, 5.11421527e+00, 6.61911896e+00, 8.73249677e+00, 1.17604260e+01, 1.61864569e+01, 2.27870547e+01, 3.28297946e+01, 4.84189023e+01, 7.31071567e+01, 1.12996748e+02, 1.78751757e+02, 2.89337246e+02, 4.79080996e+02, 8.11232960e+02, 1.40443983e+03, 2.48531490e+03, 4.49461494e+03, 8.30539633e+03, 1.56790580e+04, 3.02354014e+04, 5.95525189e+04, 1.19793234e+05, 2.46080284e+05, 5.16182008e+05, 1.10556243e+06, 2.41765307e+06, 5.39775929e+06, 1.23033271e+07, 2.86288375e+07, 6.80050408e+07, 1.64899866e+08, 4.08157783e+08, 1.03122228e+09, 2.65938808e+09, 7.00012860e+09}; /** Spline giving x=f(y) for the Integral[0->x](exp(+t*t)dt) * */ static const CubicSpline sInvGaussianInt(svGaussianIntY,svGaussianIntX,51); REAL FlatGaussianProba(const REAL x, const REAL sigma, const REAL delta) { if(abs(x) delta)x= delta; if(x<-delta)x=-delta; return x; } // Compute xmin and xmax around x0 so that: // (x0-xmin)/(xmax-x0)=Integral[xmin->x0](P(x)dx)/Integral[x0->xmax](P(x)dx) REAL xmin; REAL xmax; #if 1 { REAL Pmax,Pmin; xmin=x0-amplitude; xmax=x0+amplitude; Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta); Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta); //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta); //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta); if(Pmin>Pmax) { for(int i=0;i<5;i++) { const REAL r=Pmax/Pmin; xmax=x0+r*amplitude; Pmax=FlatLorentzianProba((x0+xmax)/2,sigma,delta); //Pmax=FlatLorentzianIntegral(x0,xmax,sigma,delta); } } else { for(int i=0;i<5;i++) { const REAL r=Pmin/Pmax; xmin=x0-r*amplitude; Pmin=FlatLorentzianProba((x0+xmin)/2,sigma,delta); //Pmin=FlatLorentzianIntegral(xmin,x0,sigma,delta); } } } #else if(abs(x0)<=delta) { xmin=x0-amplitude; xmax=x0+amplitude; } else { REAL d=(abs(x0)-delta)/sigma; d=2*d*exp(-d*d); d=(1-amplitude*d/2)/(1+amplitude*d/2);//d<1 if(x0>0) { xmin=x0-amplitude*2/(1+d); xmax=x0+amplitude*2*d/(1+d); } else { xmax=x0+amplitude*2/(1+d); xmin=x0-amplitude*2*d/(1+d); } } #endif //xmin=x0-amplitude; //xmax=x0+amplitude; //Now get the biased move... if(xmax<=-delta) { REAL ymin=(abs(xmin)-delta)/sigma; ymin=atan(ymin); REAL ymax=(abs(xmax)-delta)/sigma; ymax=atan(ymax); const REAL y=ymin+(ymax-ymin)*r; return -tan(y)*sigma-delta; } if(xmin<=-delta) { if(xmax<=delta) { //probability of being in [xmin;-delta] rather than [-delta;xmax] REAL p0=atan((abs(xmin)-delta)/sigma)*sigma; REAL p1=xmax+delta; const REAL n=p0+p1; if(rdelta && xmin <= -delta { REAL p0=atan((abs(xmin)-delta)/sigma)*sigma;//probability of being in [xmin;-delta] REAL p1=2*delta;//probability of being in [-delta;delta] REAL p2=atan((xmax-delta)/sigma)*sigma;//probability of being in [delta;xmax] const REAL n=p0+p1+p2; if(r<(p0/n)) { REAL ymin=(abs(xmin)-delta)/sigma; ymin=atan(ymin);//exp(ymin*ymin); const REAL y=ymin*(REAL)rand()/(REAL)RAND_MAX; const REAL x=-delta-tan(y)*sigma; return x; } if(r<(p0+p1)/n) { const REAL x=-delta+(REAL)rand()/(REAL)RAND_MAX*2*delta; return x; } REAL ymax=(xmax-delta)/sigma; ymax=atan(ymax); const REAL y=ymax*(REAL)rand()/(REAL)RAND_MAX; const REAL x=delta+tan(y)*sigma; return x; } } if(xmindelta REAL ymin=(xmin-delta)/sigma; ymin=atan(ymin); REAL ymax=(xmax-delta)/sigma; ymax=atan(ymax); const REAL y=ymin+(ymax-ymin)*r; return tan(y)*sigma+delta; } void TestLorentzianBiasedRandomMove() { srand(time(NULL)); REAL x=0,sigma=0.1,delta=0.5,amplitude=0.05; ofstream f; f.open("test.dat"); for(long i=0;i<400000;i++) { f<hx[i])*(y<(hx[i]+step))) // return hx,hy // // //f=open("test.dat",'r') //ll=f.readlines() //f.close() //y=zeros(len(ll),Float) //for i in xrange(len(ll)): // y[i]=float(ll[i]) // //hx,hy=histogram(y) //gplt.plot(hx,hy) } REAL Molecule::BondLengthRandomChange(const StretchModeBondLength& mode, const REAL amplitude, const bool respectRestraint) { REAL dx=mode.mpAtom1->GetX()-mode.mpAtom0->GetX(); REAL dy=mode.mpAtom1->GetY()-mode.mpAtom0->GetY(); REAL dz=mode.mpAtom1->GetZ()-mode.mpAtom0->GetZ(); const REAL l=sqrt(dx*dx+dy*dy+dz*dz+1e-7); REAL change=0.0; if(l<1e-6) return change;// :KLUDGE: if(respectRestraint && mode.mpBond!=0) { const REAL d0=l-mode.mpBond->GetLength0(); const REAL sigma=mode.mpBond->GetLengthSigma(); const REAL delta=mode.mpBond->GetLengthDelta(); const REAL max=delta+sigma*5.0; if(sigma<1e-6) { REAL d1=d0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*0.1; if(d1> delta)d1= delta; if(d1<-delta)d1=-delta; change=d1-d0; } else change=LorentzianBiasedRandomMove(d0,sigma,delta,amplitude*0.1)-d0; if((d0+change)>max) change=max-d0; else if((d0+change)<(-max)) change=-max-d0; #if 0 if(rand()%10000==0) { cout<<"BOND LENGTH change("<GetName()<<"-" <GetName() <<"(Restraint="<"<TranslateAtomGroup(mode.mvTranslatedAtomList,dx,dy,dz,true); return change; } REAL Molecule::BondAngleRandomChange(const StretchModeBondAngle& mode, const REAL amplitude, const bool respectRestraint) { REAL dx10=mode.mpAtom0->GetX()-mode.mpAtom1->GetX(); REAL dy10=mode.mpAtom0->GetY()-mode.mpAtom1->GetY(); REAL dz10=mode.mpAtom0->GetZ()-mode.mpAtom1->GetZ(); REAL dx12=mode.mpAtom2->GetX()-mode.mpAtom1->GetX(); REAL dy12=mode.mpAtom2->GetY()-mode.mpAtom1->GetY(); REAL dz12=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ(); const REAL vx=dy10*dz12-dz10*dy12; const REAL vy=dz10*dx12-dx10*dz12; const REAL vz=dx10*dy12-dy10*dx12; REAL change=0.0; if((abs(vx)+abs(vy)+abs(vz))<1e-6) return change;// :KLUDGE: REAL angle0; if(respectRestraint && mode.mpBondAngle!=0) { const REAL norm= sqrt( (dx10*dx10+dy10*dy10+dz10*dz10)*(dx12*dx12+dy12*dy12+dz12*dz12)+1e-6); angle0=(dx10*dx12+dy10*dy12+dz10*dz12)/norm; if(angle0>=1) angle0=0; else { if(angle0<=-1) angle0=M_PI; else angle0= acos(angle0); } const REAL a0=angle0-mode.mpBondAngle->GetAngle0(); const REAL sigma=mode.mpBondAngle->GetAngleSigma(); const REAL delta=mode.mpBondAngle->GetAngleDelta(); if(sigma<1e-6) { REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude; if(a1> delta)a1= delta; if(a1<-delta)a1=-delta; change=a1-a0; } else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0; if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0; else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0; #if 0 if(rand()%1==0) { cout<<"ANGLE change("<GetName()<<"-" <GetName()<<"-" <GetName() <<"(Restraint="<<(angle0-a0)*RAD2DEG<<"s"<"<<(angle0+change)*RAD2DEG<RotateAtomGroup(*(mode.mpAtom1),vx,vy,vz,mode.mvRotatedAtomList,change,true); return change; } REAL Molecule::DihedralAngleRandomChange(const StretchModeTorsion& mode, const REAL amplitude, const bool respectRestraint) { const REAL dx=mode.mpAtom2->GetX()-mode.mpAtom1->GetX(); const REAL dy=mode.mpAtom2->GetY()-mode.mpAtom1->GetY(); const REAL dz=mode.mpAtom2->GetZ()-mode.mpAtom1->GetZ(); REAL change=0.0; if((abs(dx)+abs(dy)+abs(dz))<1e-6) return change;// :KLUDGE: if(respectRestraint && mode.mpDihedralAngle!=0) { const REAL angle0=mode.mpDihedralAngle->GetAngle(); const REAL a0=angle0-mode.mpDihedralAngle->GetAngle0(); const REAL sigma=mode.mpDihedralAngle->GetAngleSigma(); const REAL delta=mode.mpDihedralAngle->GetAngleDelta(); if(sigma<1e-6) { REAL a1=a0+(REAL)(2*rand()-RAND_MAX)/(REAL)RAND_MAX*amplitude*mode.mBaseAmplitude; if(a1> delta)a1= delta; if(a1<-delta)a1=-delta; change=a1-a0; } else change=LorentzianBiasedRandomMove(a0,sigma,delta,amplitude*mode.mBaseAmplitude)-a0; if((a0+change)>(delta+sigma*5.0)) change= delta+sigma*5.0-a0; else if((a0+change)<(-delta-sigma*5.0)) change=-delta-sigma*5.0-a0; #if 0 if(rand()%1==0) { cout<<"TORSION change (" <GetName()<<"-"<GetName()<<"):"<GetName()<<")=" <<(angle0-a0)*RAD2DEG<<"s"<0) { // Use the most recent atom in the z-matrix const long b=zconn[nc-1]; zmatrix[z].mBondAtom=b; zmatrix[z].mBondLength=GetBondLength(*vpAtom[vrZIndex[b]],*vpAtom[curr]); if(z>1) { const long a=zmatrix[b].mBondAtom; zmatrix[z].mBondAngleAtom=a; zmatrix[z].mBondAngle=GetBondAngle(*vpAtom[vrZIndex[a]],*vpAtom[vrZIndex[b]],*vpAtom[curr]); if(z>2) { const long d=zmatrix[b].mBondAngleAtom; zmatrix[z].mDihedralAtom=d; zmatrix[z].mDihedralAngle=fmod(GetDihedralAngle(*vpAtom[vrZIndex[d]],*vpAtom[vrZIndex[a]], *vpAtom[vrZIndex[b]],*vpAtom[curr])+2*M_PI, 2*M_PI); } else { zmatrix[z].mDihedralAtom=0; zmatrix[z].mDihedralAngle=0; } } else { zmatrix[z].mBondAngleAtom=0; zmatrix[z].mBondAngle=0; } } else { zmatrix[z].mBondAtom=0; zmatrix[z].mBondLength=0; } z++; // Continue filling up the zmatrix, beginning from thz first atoms not already in the zmatrix for(pos=conn.begin();pos!=conn.end();++pos) { if(*pos!=-1) { if(vZIndex[*pos]==-1) BuildZMatrixRecursive(z,*pos,vpAtom,connT,zmatrix,vIndex,vZIndex,vrZIndex); } } } const vector& Molecule::AsZMatrix(const bool keeporder)const { this->BuildConnectivityTable(); const long n=mvpAtom.size(); // index of the atoms in the list map vIndex; { long i=0; for(vector::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) vIndex[*pos]=i++; } mAsZMatrix.resize(n); if(keeporder) { for(long i=0;iGetScatteringPower()); if(i>0) { const set *pConn=&(mConnectivityTable.find(mvpAtom[i])->second); // Find a connected atom already in the mAsZMatrix, prefereably the most recent long b=-1; for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) if((vIndex[*pos]b)) b=vIndex[*pos]; // Did not find a connected atom already in the z-matrix ? Take the last one if(b==-1) b=i-1; mAsZMatrix[i].mBondAtom=b; mAsZMatrix[i].mBondLength=GetBondLength(*mvpAtom[b],*mvpAtom[i]); if(i>1) { const long a= (b==0)?1 : mAsZMatrix[b].mBondAtom; mAsZMatrix[i].mBondAngleAtom=a; mAsZMatrix[i].mBondAngle=GetBondAngle(*mvpAtom[a],*mvpAtom[b],*mvpAtom[i]); if(i>2) { long d= mAsZMatrix[a].mBondAtom; if(d==b) {// Dihedral atom is already bond atom, find another connected to angle atom d=-1; const set *pConn=&(mConnectivityTable.find(mvpAtom[a])->second); // Find a connected atom already in the mAsZMatrix, prefereably the most recent for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) if((vIndex[*pos]d)) d=vIndex[*pos]; } if(d==-1) {// Can't find an angle connected to angle atom, so find another with bond atom const set *pConn=&(mConnectivityTable.find(mvpAtom[b])->second); // Find a connected atom already in the mAsZMatrix, prefereably the most recent for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) if((vIndex[*pos]d)) d=vIndex[*pos]; } if(d==-1) {// Maybe another connected to this atom ?? const set *pConn=&(mConnectivityTable.find(mvpAtom[i])->second); // Find a connected atom already in the mAsZMatrix, prefereably the most recent for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) if( (vIndex[*pos]d)) d=vIndex[*pos]; } if(d==-1) {// OK, pick *any* (can this happen ? Really ?) for(long j=0;jd)) d=j; } mAsZMatrix[i].mDihedralAtom=d; mAsZMatrix[i].mDihedralAngle=fmod(GetDihedralAngle(*mvpAtom[d], *mvpAtom[a], *mvpAtom[b], *mvpAtom[i])+2*M_PI, 2*M_PI); } } } } } else { // vZIndex[i] tells where mvpAtom[i] is in the z-matrix vector vZIndex(n); // vrZIndex[i] tells where which index in vpAtom is ZAtom #i vector vrZIndex(n); for(long i=0;i > &connect, list &atomlist, map,list > &ringlist) { list::const_iterator f=find(atomlist.begin(),atomlist.end(),currentAtom); if(f!=atomlist.end()) {// This atom was already in the list ! We have found a ring ! #ifdef __DEBUG__ cout<GetName()<<" was already in the list : ring found !"<::const_iterator atom=atomlist.begin();atom!=atomlist.end();++atom) cout<<(*atom)->GetName()<<" "; cout< ring1; list ring2; for(list::const_iterator pos=f;pos!=atomlist.end();++pos) { ring1.insert(*pos); ring2.push_back(*pos); } ringlist.insert(make_pair(ring1,ring2)); } else { atomlist.push_back(currentAtom); map >::const_iterator c=connect.find(currentAtom); if(c != connect.end()) { set::const_iterator pos; for(pos=c->second.begin();pos!=c->second.end();++pos) { if(*pos==previousAtom) continue; BuildRingRecursive(*pos,currentAtom,connect,atomlist,ringlist); } } atomlist.pop_back(); //?? } } void Molecule::BuildRingList() { this->BuildConnectivityTable(); if(mClockRingList>mClockConnectivityTable) return; VFN_DEBUG_ENTRY("Molecule::BuildRingList()",7) for(vector::const_iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) (*pos)->SetIsInRing(false); list atomlist; // Use a map with a set for key to eliminate duplicate rings map,list > ringlist; for(unsigned long i=0;i,list >::const_iterator pos0=ringlist.begin();pos0!=ringlist.end();pos0++) { mvRing.resize(mvRing.size()+1); std::list *pList=&(mvRing.back().GetAtomList()); #if 1//def __DEBUG__ cout<<"Found ring:"; #endif for(list::const_iterator atom=pos0->second.begin();atom!=pos0->second.end();++atom) { pList->push_back(*atom); (*atom)->SetIsInRing(true); #if 1//def __DEBUG__ cout<<(*atom)->GetName()<<" "; #endif } #if 1//def __DEBUG__ cout<mClockBondList) &&(mClockConnectivityTable>mClockAtomList)) return; VFN_DEBUG_ENTRY("Molecule::BuildConnectivityTable()",5) TAU_PROFILE("Molecule::BuildConnectivityTable()","void ()",TAU_DEFAULT); mConnectivityTable.clear(); for(unsigned long i=0;iGetAtom1())].insert(&(mvpBond[i]->GetAtom2())); mConnectivityTable[&(mvpBond[i]->GetAtom2())].insert(&(mvpBond[i]->GetAtom1())); } #ifdef __DEBUG__ { map >::const_iterator pos; for(pos=mConnectivityTable.begin();pos!=mConnectivityTable.end();++pos) { cout<<"Atom "<first->GetName()<<" is connected to atoms: "; set::const_iterator pos1; for(pos1=pos->second.begin();pos1!=pos->second.end();++pos1) { cout<<(*pos1)->GetName()<<" "; } cout<second.size()>24) throw ObjCrystException("Molecule: one atom ("+pos->first->GetName()+") has more than 24 bonds !"); } } #endif mClockConnectivityTable.Click(); VFN_DEBUG_EXIT("Molecule::BuildConnectivityTable()",5) } Molecule::RotorGroup::RotorGroup(const MolAtom &at1,const MolAtom &at2): mpAtom1(&at1),mpAtom2(&at2),mBaseRotationAmplitude(M_PI*0.04) {} void Molecule::BuildRotorGroup() { if( (mClockRotorGroup>mClockBondList) &&(mClockRotorGroup>mClockAtomList) &&(mClockRotorGroup>mClockBondAngleList) &&(mClockRotorGroup>mClockDihedralAngleList)) return; VFN_DEBUG_ENTRY("Molecule::BuildRotorGroup()",5) TAU_PROFILE("Molecule::BuildRotorGroup()","void ()",TAU_DEFAULT); this->BuildConnectivityTable(); mvRotorGroupTorsion.clear(); mvRotorGroupTorsionSingleChain.clear(); mvRotorGroupInternal.clear(); // Build Rotation groups around bonds for(unsigned long i=0;iIsFreeTorsion())) continue; MolAtom *const atom1=&(mvpBond[i]->GetAtom1()), *const atom2=&(mvpBond[i]->GetAtom2()); for(unsigned int j=1;j<=2;++j) { const set *pConn; if(j==1) pConn=&(mConnectivityTable[atom1]); else pConn=&(mConnectivityTable[atom2]); mvRotorGroupTorsion.push_back(RotorGroup(mvpBond[i]->GetAtom1(), mvpBond[i]->GetAtom2())); mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom1); mvRotorGroupTorsion.back().mvRotatedAtomList.insert(atom2); for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if((j==1)&&(*pos==atom2)) continue; if((j==2)&&(*pos==atom1)) continue; ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvRotorGroupTorsion.back().mvRotatedAtomList); if(pConn->size()>2) { mvRotorGroupTorsionSingleChain.push_back(RotorGroup(mvpBond[i]->GetAtom1(), mvpBond[i]->GetAtom2())); mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom1); mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.insert(atom2); ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList); mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom1); mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.erase(atom2); if( (mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)) ||(mvRotorGroupTorsionSingleChain.back().mvRotatedAtomList.size()==0)) mvRotorGroupTorsionSingleChain.pop_back(); } } mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom1); mvRotorGroupTorsion.back().mvRotatedAtomList.erase(atom2); if( (mvRotorGroupTorsion.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)) ||(mvRotorGroupTorsion.back().mvRotatedAtomList.size()==0)) mvRotorGroupTorsion.pop_back(); } } #if 1 // Build 'internal' rotation groups between random atoms //:TODO: This should be tried for *random* configuration of free torsion angles... if(mFlexModel.GetChoice()==0) { for(vector::const_iterator atom1=this->GetAtomList().begin(); atom1!=this->GetAtomList().end();++atom1) { const set *pConn=&(mConnectivityTable[*atom1]); vector::const_iterator atom2=atom1; atom2++; for(;atom2!=this->GetAtomList().end();++atom2) { for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if(*pos==*atom2) continue; mvRotorGroupInternal.push_back(RotorGroup(**atom1,**atom2)); mvRotorGroupInternal.back().mvRotatedAtomList.insert(*atom1); ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvRotorGroupInternal.back().mvRotatedAtomList, *atom2); //Check if this chains leads to atom2 set::const_iterator check =find(mvRotorGroupInternal.back().mvRotatedAtomList.begin(), mvRotorGroupInternal.back().mvRotatedAtomList.end(),*atom2); if( (check==mvRotorGroupInternal.back().mvRotatedAtomList.end()) ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()<3) ||(mvRotorGroupInternal.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))) { mvRotorGroupInternal.pop_back(); } else { mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom1); mvRotorGroupInternal.back().mvRotatedAtomList.erase(*atom2); } } } } } #endif // Remove identical groups for(unsigned int i=1;i<=3;++i) { list *pRotorGroup1; switch(i) { case 1: pRotorGroup1=&mvRotorGroupTorsion;break; case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break; case 3: pRotorGroup1=&mvRotorGroupInternal;break; } for(list::iterator pos1=pRotorGroup1->begin(); pos1!=pRotorGroup1->end();++pos1) { for(unsigned int j=i;j<=3;++j) { list *pRotorGroup2; switch(j) { case 1: pRotorGroup2=&mvRotorGroupTorsion;break; case 2: pRotorGroup2=&mvRotorGroupTorsionSingleChain;break; case 3: pRotorGroup2=&mvRotorGroupInternal;break; } for(list::iterator pos2=pRotorGroup2->begin(); pos2!=pRotorGroup2->end();) { if(pos2==pos1) {++pos2;continue;} if(( ((pos1->mpAtom1 == pos2->mpAtom1) && (pos1->mpAtom2 == pos2->mpAtom2)) ||((pos1->mpAtom2 == pos2->mpAtom1) && (pos1->mpAtom1 == pos2->mpAtom2))) &&pos1->mvRotatedAtomList.size() == pos2->mvRotatedAtomList.size()) { bool ident=true; for(set::const_iterator pos=pos1->mvRotatedAtomList.begin(); pos!=pos1->mvRotatedAtomList.end();++pos) { set::const_iterator tmp=pos2->mvRotatedAtomList.find(*pos); if(tmp == pos2->mvRotatedAtomList.end()) { ident=false; break; } } if(ident) { #if 0 cout<<"Identical groups:"<mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<" : "; for(set::iterator pos=pos1->mvRotatedAtomList.begin(); pos!=pos1->mvRotatedAtomList.end();++pos) cout<<(*pos)->GetName()<<" "; cout<mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<" : "; for(set::iterator pos=pos2->mvRotatedAtomList.begin(); pos!=pos2->mvRotatedAtomList.end();++pos) cout<<(*pos)->GetName()<<" "; cout<erase(pos2); } else ++pos2; } else ++pos2; } } } } // Remove all rotations which break restraints and therefore are not "free torsion" this->SaveParamSet(mLocalParamSet); const REAL llk0=this->GetLogLikelihood(); for(unsigned int i=1;i<=3;++i) { list *pRotorGroup1; switch(i) { case 1: pRotorGroup1=&mvRotorGroupTorsion;break; case 2: pRotorGroup1=&mvRotorGroupTorsionSingleChain;break; case 3: pRotorGroup1=&mvRotorGroupInternal;break; } for(list::iterator pos=pRotorGroup1->begin(); pos!=pRotorGroup1->end();) { REAL llk=0; for(unsigned int j=0;j<36;++j) { const REAL angle=(REAL)j*M_PI/36.; this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2), pos->mvRotatedAtomList,angle); // use fabs in case we are not starting from the minimum of a restraint.. llk += fabs(this->GetLogLikelihood() - llk0); this->RestoreParamSet(mLocalParamSet); } #ifdef __DEBUG__ switch(i) { case 1: cout<<"Rotation Group around bond :";break; case 2: cout<<"Rotation Group (single chain) around bond :";break; case 3: cout<<"Rotation Group (internal) between :";break; } cout <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<" : "; for(set::iterator pos1=pos->mvRotatedAtomList.begin(); pos1!=pos->mvRotatedAtomList.end();++pos1) cout<<(*pos1)->GetName()<<" "; cout<<" ="<< llk/36.; #endif if((llk/50.)>100.) { pos = pRotorGroup1->erase(pos); //cout <<" -> NOT a free torsion"< free torsion"<::iterator pos=mvpBond.begin();pos!=mvpBond.end();++pos) (*pos)->SetFreeTorsion(false); for(list::iterator pos=mvRotorGroupTorsion.begin(); pos!=mvRotorGroupTorsion.end();++pos) { vector::iterator bd=this->FindBond((*pos->mpAtom1),(*pos->mpAtom2)); if(bd!=mvpBond.end()) (*bd)->SetFreeTorsion(true); } mClockRotorGroup.Click(); VFN_DEBUG_EXIT("Molecule::BuildRotorGroup()",5) } void Molecule::BuildStretchModeBondLength() { #if 0 if( (mClockStretchModeBondLength>mClockBondList) &&(mClockStretchModeBondLength>mClockAtomList) &&(mClockStretchModeBondLength>mClockBondAngleList) &&(mClockStretchModeBondLength>mClockDihedralAngleList)) return; #endif VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondLength()",7) this->BuildConnectivityTable(); TAU_PROFILE("Molecule::BuildStretchModeBondLength()","void ()",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondLength 1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondLength 2","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondLength 3","", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondLength 4","", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondLength 5","", TAU_FIELD); mvStretchModeBondLength.clear(); // Build list of atoms moved when stretching a bond length. Only keep the group // of atoms on the smaller side. TAU_PROFILE_START(timer1); for(unsigned long i=0;iIsFreeTorsion())) continue; MolAtom* const atom1=&(mvpBond[i]->GetAtom1()); MolAtom* const atom2=&(mvpBond[i]->GetAtom2()); for(unsigned int j=1;j<=2;++j) { const set *pConn; if(j==1) pConn=&(mConnectivityTable[atom1]); else pConn=&(mConnectivityTable[atom2]); if(j==1) mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom2(), mvpBond[i]->GetAtom1(), mvpBond[i])); else mvStretchModeBondLength.push_back(StretchModeBondLength(mvpBond[i]->GetAtom1(), mvpBond[i]->GetAtom2(), mvpBond[i])); if(j==1) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom1); if(j==2) mvStretchModeBondLength.back().mvTranslatedAtomList.insert(atom2); for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if((j==1)&&(*pos==atom2)) continue; if((j==2)&&(*pos==atom1)) continue; ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvStretchModeBondLength.back().mvTranslatedAtomList); } const unsigned long ct1=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom1), ct2=mvStretchModeBondLength.back().mvTranslatedAtomList.count(atom2); if( ((j==1)&&(ct2>0)) || ((j==2)&&(ct1>0)) ) { // We have found a ring. No use looking at the other side. // :TODO: handle this properly.. mvStretchModeBondLength.pop_back(); break; } if( (mvStretchModeBondLength.back().mvTranslatedAtomList.size()>((mvpAtom.size()+1)/2)) ||(mvStretchModeBondLength.back().mvTranslatedAtomList.size()==0)) { #ifdef __DEBUG__ cout<<"Rejecting StretchModeBondLength ";mvStretchModeBondLength.back().Print(cout);cout<::iterator pos=mvStretchModeBondLength.begin(); pos!=mvStretchModeBondLength.end();) { TAU_PROFILE_START(timer5); bool keep=true; for(vector::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group) { unsigned long ct=0; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) ct += pos->mvTranslatedAtomList.count(*at); if((ct>0)&&(ct!=(*group)->size())) { keep=false; #ifdef __DEBUG__ cout<<" Breaks Rigid Group:"; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) cout<<(*at)->GetName()<<" "; cout<SaveParamSet(mLocalParamSet); unsigned long paramSetRandom[5]; for(unsigned long i=0;i<5;++i) { for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { (*pos)->SetX(100.*rand()/(REAL) RAND_MAX); (*pos)->SetY(100.*rand()/(REAL) RAND_MAX); (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX); } paramSetRandom[i]=this->CreateParamSet(); } // find bond lengths broken by each mode for(list::iterator pos=mvStretchModeBondLength.begin(); pos!=mvStretchModeBondLength.end();) { TAU_PROFILE_START(timer2); bool keep=true; pos->mvpBrokenBond.clear(); for(vector::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvTranslatedAtomList.begin(); at!=pos->mvTranslatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; } // If we moved either both or non of the bond atom, the bond length is unchanged. if((ct!=0)&&(ct !=2)) pos->mvpBrokenBond.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { int nb=pos->mvpBrokenBond.size(); if(pos->mpBond!=0) nb -= 1; if(nb>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondLength.erase(pos); TAU_PROFILE_STOP(timer2); } // find bond angles broken by each mode for(list::iterator pos=mvStretchModeBondLength.begin(); pos!=mvStretchModeBondLength.end();) { TAU_PROFILE_START(timer3); bool keep=true; pos->mvpBrokenBondAngle.clear(); for(vector::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvTranslatedAtomList.begin(); at!=pos->mvTranslatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; } bool broken=true; if((ct==0)||(ct==3)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenBondAngle.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondLength.erase(pos); TAU_PROFILE_STOP(timer3); } // find dihedral angles broken by each mode for(list::iterator pos=mvStretchModeBondLength.begin(); pos!=mvStretchModeBondLength.end();) { TAU_PROFILE_START(timer4); bool keep=true; pos->mvpBrokenDihedralAngle.clear(); for(vector::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvTranslatedAtomList.begin(); at!=pos->mvTranslatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; if(*at==&((*r)->GetAtom4())) ct++; } bool broken=true; if((ct==0)||(ct==4)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenDihedralAngle.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondLength.erase(pos); TAU_PROFILE_STOP(timer4); } this->RestoreParamSet(mLocalParamSet); for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]); #if 1//def __DEBUG__ cout<<"List of Bond Length stretch modes"<::const_iterator pos=mvStretchModeBondLength.begin(); pos!=mvStretchModeBondLength.end();++pos) { cout<<" Bond:"<mpAtom0->GetName()<<"-"<mpAtom1->GetName()<<", Translated Atoms: "; for(set::const_iterator atom=pos->mvTranslatedAtomList.begin(); atom!=pos->mvTranslatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } if(pos->mpBond!=0) cout<< " ; restrained to length="<mpBond->GetLength0() <<", sigma="<mpBond->GetLengthSigma() <<", delta="<mpBond->GetLengthDelta(); if(pos->mvpBrokenBond.size()>0) { cout<::const_iterator bond=pos->mvpBrokenBond.begin(); bond!=pos->mvpBrokenBond.end();++bond) cout<first->GetName()<<", "; } if(pos->mvpBrokenBondAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenBondAngle.begin(); angle!=pos->mvpBrokenBondAngle.end();++angle) cout<first->GetName()<<", "; } if(pos->mvpBrokenDihedralAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenDihedralAngle.begin(); angle!=pos->mvpBrokenDihedralAngle.end();++angle) cout<first->GetName()<<", "; } cout<mClockBondList) &&(mClockStretchModeBondAngle>mClockAtomList) &&(mClockStretchModeBondAngle>mClockBondAngleList) &&(mClockStretchModeBondAngle>mClockDihedralAngleList)) return; #endif VFN_DEBUG_ENTRY("Molecule::BuildStretchModeBondAngle()",10) this->BuildConnectivityTable(); TAU_PROFILE("Molecule::BuildStretchModeBondAngle()","void ()",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeBondAngle 1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeBondAngle 2","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeBondAngle 3","", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeBondAngle 4","", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeBondAngle 5","", TAU_FIELD); mvStretchModeBondAngle.clear(); // Build list of atoms moved when stretching a bond angle. Only keep the group // of atoms on the smaller side. TAU_PROFILE_START(timer1); for(unsigned long i=0;iIsFreeTorsion())) continue; set *pConn0=&(mConnectivityTable[mvpAtom[i]]); if(pConn0->size()<2) continue; for(set::const_iterator pos1=pConn0->begin();pos1!=pConn0->end();++pos1) { set::const_iterator pos2=pos1; pos2++; for(;pos2!=pConn0->end();++pos2) { VFN_DEBUG_MESSAGE("Molecule::BuildStretchModeBondAngle():"<::const_iterator pos=mvpBondAngle.begin();pos!=mvpBondAngle.end();++pos) { if(&((*pos)->GetAtom2())==mvpAtom[i]) { if( ((&((*pos)->GetAtom1())==*pos1)&&(&((*pos)->GetAtom3())==*pos2)) ||((&((*pos)->GetAtom1())==*pos2)&&(&((*pos)->GetAtom3())==*pos1))) { pMolBondAngle=*pos; break; } } } for(unsigned int j=1;j<=2;++j) { const set *pConn; if(j==1) { pConn=&(mConnectivityTable[*pos1]); mvStretchModeBondAngle.push_back(StretchModeBondAngle(**pos2, *mvpAtom[i], **pos1, pMolBondAngle)); mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos1); } else { pConn=&(mConnectivityTable[*pos2]); mvStretchModeBondAngle.push_back(StretchModeBondAngle(**pos1, *mvpAtom[i], **pos2, pMolBondAngle)); mvStretchModeBondAngle.back().mvRotatedAtomList.insert(*pos2); } mvStretchModeBondAngle.back().mvRotatedAtomList.insert(mvpAtom[i]); for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if(*pos==mvpAtom[i]) continue; ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvStretchModeBondAngle.back().mvRotatedAtomList); } //if(j==1)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos2); //if(j==2)mvStretchModeBondAngle.back().mvRotatedAtomList.erase(*pos1); mvStretchModeBondAngle.back().mvRotatedAtomList.erase(mvpAtom[i]); if( (mvStretchModeBondAngle.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2)) ||(mvStretchModeBondAngle.back().mvRotatedAtomList.size()==0)) { #ifdef __DEBUG__ cout<<"Rejecting StretchModeBondAngle ";mvStretchModeBondAngle.back().Print(cout);cout<::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();) { TAU_PROFILE_START(timer5); bool keep=true; for(vector::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group) { unsigned long ct=0; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) ct += pos->mvRotatedAtomList.count(*at); if(ct>0) { // Add the origin atom, which does not move relatively to the rotated atoms ct += (*group)->count(pos->mpAtom1); if(ct!=(*group)->size()) { keep=false; #ifdef __DEBUG__ pos->Print(cout); cout<<" Breaks Rigid Group:"; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) cout<<(*at)->GetName()<<" "; cout<SaveParamSet(mLocalParamSet); unsigned long paramSetRandom[5]; for(unsigned long i=0;i<5;++i) { for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { (*pos)->SetX(100.*rand()/(REAL) RAND_MAX); (*pos)->SetY(100.*rand()/(REAL) RAND_MAX); (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX); } paramSetRandom[i]=this->CreateParamSet(); } // find bond lengths broken by each mode for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();) { TAU_PROFILE_START(timer2); bool keep=true; pos->mvpBrokenBond.clear(); for(vector::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; } bool broken=true; // If we moved either both or non of the bond atom, the bond length is unchanged. if((ct==0)||(ct==2)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenBond.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenBond.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondAngle.erase(pos); TAU_PROFILE_STOP(timer2); } // find bond angles broken by each mode for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();) { TAU_PROFILE_START(timer3); bool keep=true; pos->mvpBrokenBondAngle.clear(); for(vector::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; } bool broken=true; if(ct==0) broken=false; if(ct==3) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { int nb=pos->mvpBrokenBond.size(); if(pos->mpBondAngle!=0) nb -= 1; if(nb>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondAngle.erase(pos); TAU_PROFILE_STOP(timer3); } // find dihedral angles broken by each mode for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();) { TAU_PROFILE_START(timer4); bool keep=true; pos->mvpBrokenDihedralAngle.clear(); for(vector::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; if(*at==&((*r)->GetAtom4())) ct++; } bool broken=true; if(ct==0) broken=false; if(ct==4) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenDihedralAngle.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeBondAngle.erase(pos); TAU_PROFILE_STOP(timer4); } this->RestoreParamSet(mLocalParamSet); for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]); #ifdef __DEBUG__ cout<<"List of Bond Angle stretch modes"<::const_iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();++pos) { cout<<" Angle:"<mpAtom0->GetName()<<"-" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<", Rotated Atoms: "; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } if(pos->mpBondAngle!=0) cout<< " ; restrained to angle="<mpBondAngle->GetAngle0()*RAD2DEG <<"�, sigma="<mpBondAngle->GetAngleSigma()*RAD2DEG <<"�, delta="<mpBondAngle->GetAngleDelta()*RAD2DEG<<"�"; if(pos->mvpBrokenBond.size()>0) { cout<::const_iterator bond=pos->mvpBrokenBond.begin(); bond!=pos->mvpBrokenBond.end();++bond) cout<first->GetName()<<", "; } if(pos->mvpBrokenBondAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenBondAngle.begin(); angle!=pos->mvpBrokenBondAngle.end();++angle) cout<first->GetName()<<", "; } if(pos->mvpBrokenDihedralAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenDihedralAngle.begin(); angle!=pos->mvpBrokenDihedralAngle.end();++angle) cout<first->GetName()<<", "; } cout<mClockBondList) &&(mClockStretchModeTorsion>mClockAtomList) &&(mClockStretchModeTorsion>mClockBondAngleList) &&(mClockStretchModeTorsion>mClockDihedralAngleList)) return; #endif VFN_DEBUG_ENTRY("Molecule::BuildStretchModeTorsion()",7) TAU_PROFILE("Molecule::BuildStretchModeTorsion()","void ()",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"Molecule::BuildStretchModeTorsion 1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"Molecule::BuildStretchModeTorsion 2","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"Molecule::BuildStretchModeTorsion 3","", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"Molecule::BuildStretchModeTorsion 4","", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"Molecule::BuildStretchModeTorsion 5","", TAU_FIELD); this->BuildConnectivityTable(); mvStretchModeTorsion.clear(); // Build list of atoms moved when changing the angle. Only keep the group // of atoms on the smaller side. for(unsigned long i=0;iIsFreeTorsion())) continue; MolAtom* const atom1=&(mvpBond[i]->GetAtom1()); MolAtom* const atom2=&(mvpBond[i]->GetAtom2()); for(unsigned int j=1;j<=2;++j) { const set *pConn; if(j==1) pConn=&(mConnectivityTable[atom1]); else pConn=&(mConnectivityTable[atom2]); mvStretchModeTorsion.push_back(StretchModeTorsion(*atom1,*atom2,0)); mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom1); mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom2); for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if((*pos==atom2)||(*pos==atom1)) continue; ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvStretchModeTorsion.back().mvRotatedAtomList); } mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom1); mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom2); for(vector::const_iterator dih=mvpDihedralAngle.begin();dih!=mvpDihedralAngle.end();++dih) { // :TODO: There are some other weird cases to take into account, // for restraints with atoms *not* connected to another // More generally, should check the list of atoms rotated. if( ((&((*dih)->GetAtom2())==atom1) && (&((*dih)->GetAtom3())==atom2)) ||((&((*dih)->GetAtom3())==atom1) && (&((*dih)->GetAtom2())==atom2))) { const unsigned long ct1=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom1())); const unsigned long ct4=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom4())); if((ct1+ct4)==1)// One of the atom is rotated, not the other { mvStretchModeTorsion.back().mpDihedralAngle=*dih; //:TODO: Check sense of rotation ! if(ct4==1) { mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom2()); mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom3()); } else { mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom3()); mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom2()); } } } } if(mvStretchModeTorsion.size()>1) {//Duplicate ? // Does not work with a const_reverse_iterator ? // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729 list::reverse_iterator mode=mvStretchModeTorsion.rbegin(); ++mode; for(;mode!=mvStretchModeTorsion.rend();++mode) { if( ( ((mode->mpAtom1==atom1)&&(mode->mpAtom2==atom2)) ||((mode->mpAtom1==atom2)&&(mode->mpAtom2==atom1))) &&(mode->mvRotatedAtomList==mvStretchModeTorsion.back().mvRotatedAtomList)) { #ifdef __DEBUG__ cout<<"Duplicate StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<((mvpAtom.size()+1)/2)) ||(mvStretchModeTorsion.back().mvRotatedAtomList.size()==0)) { #ifdef __DEBUG__ cout<<"Rejecting StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<IsFreeTorsion())) continue; MolAtom* const atom1=&(mvpBond[i]->GetAtom1()); MolAtom* const atom2=&(mvpBond[i]->GetAtom2()); for(unsigned int j=1;j<=2;++j) { const set *pConn; if(j==1) pConn=&(mConnectivityTable[atom1]); else pConn=&(mConnectivityTable[atom2]); for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if((*pos==atom2)||(*pos==atom1)) continue; mvStretchModeTorsion.push_back(StretchModeTorsion(*atom1,*atom2,0)); mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom1); mvStretchModeTorsion.back().mvRotatedAtomList.insert(atom2); ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvStretchModeTorsion.back().mvRotatedAtomList); mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom1); mvStretchModeTorsion.back().mvRotatedAtomList.erase(atom2); for(vector::const_iterator dih=mvpDihedralAngle.begin();dih!=mvpDihedralAngle.end();++dih) { // :TODO: There are some other weird cases to take into account, // for restraints with atoms *not* connected to another // More generally, should check the list of atoms rotated. if( ((&((*dih)->GetAtom2())==atom1) && (&((*dih)->GetAtom3())==atom2)) ||((&((*dih)->GetAtom3())==atom1) && (&((*dih)->GetAtom2())==atom2))) { const unsigned long ct1=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom1())); const unsigned long ct4=mvStretchModeTorsion.back().mvRotatedAtomList.count(&((*dih)->GetAtom4())); if((ct1+ct4)==1)// One of the atom is rotated, not the other { mvStretchModeTorsion.back().mpDihedralAngle=*dih; //:TODO: Check sense of rotation ! if(ct4==1) { mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom2()); mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom3()); } else { mvStretchModeTorsion.back().mpAtom1=&((*dih)->GetAtom3()); mvStretchModeTorsion.back().mpAtom2=&((*dih)->GetAtom2()); } } } } if(mvStretchModeTorsion.size()>1) {//Duplicate ? // Does not work with a const_reverse_iterator ? // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729 list::reverse_iterator mode=mvStretchModeTorsion.rbegin(); ++mode; for(;mode!=mvStretchModeTorsion.rend();++mode) { if( ( ((mode->mpAtom1==atom1)&&(mode->mpAtom2==atom2)) ||((mode->mpAtom1==atom2)&&(mode->mpAtom2==atom1))) &&(mode->mvRotatedAtomList==mvStretchModeTorsion.back().mvRotatedAtomList)) { #ifdef __DEBUG__ cout<<"Duplicate StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<((mvpAtom.size()+1)/2)) ||(mvStretchModeTorsion.back().mvRotatedAtomList.size()==0)) { #ifdef __DEBUG__ cout<<"Rejecting StretchModeTorsion ";mvStretchModeTorsion.back().Print(cout);cout<::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();) { TAU_PROFILE_START(timer5); bool keep=true; for(vector::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group) { unsigned long ct=0; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) ct += pos->mvRotatedAtomList.count(*at); if(ct>0) { // Add the axis atoms, which do not move relatively to the rotated atoms ct += (*group)->count(pos->mpAtom1); ct += (*group)->count(pos->mpAtom2); if(ct!=(*group)->size()) { keep=false; #ifdef __DEBUG__ pos->Print(cout); cout<<" Breaks Rigid Group:"; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) cout<<(*at)->GetName()<<" "; cout<SaveParamSet(mLocalParamSet); unsigned long paramSetRandom[5]; for(unsigned long i=0;i<5;++i) { for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { (*pos)->SetX(100.*rand()/(REAL) RAND_MAX); (*pos)->SetY(100.*rand()/(REAL) RAND_MAX); (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX); } paramSetRandom[i]=this->CreateParamSet(); } // find bond lengths broken by each mode for(list::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();) { TAU_PROFILE_START(timer2); bool keep=true; pos->mvpBrokenBond.clear(); for(vector::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; } bool broken=true; // If we moved either both or non of the bond atom, the bond length is unchanged. if((ct==0)||(ct==2)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenBond.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenBond.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeTorsion.erase(pos); TAU_PROFILE_STOP(timer2); } // find bond angles broken by each mode for(list::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();) { TAU_PROFILE_START(timer3); bool keep=true; pos->mvpBrokenBondAngle.clear(); for(vector::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; } bool broken=true; if((ct==0)||(ct==3)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenBondAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { if(pos->mvpBrokenBond.size()>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeTorsion.erase(pos); TAU_PROFILE_STOP(timer3); } // find dihedral angles broken by each mode for(list::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();) { TAU_PROFILE_START(timer4); bool keep=true; pos->mvpBrokenDihedralAngle.clear(); for(vector::const_iterator r=mvpDihedralAngle.begin();r!=mvpDihedralAngle.end();++r) { unsigned int ct=0; for(set::const_iterator at=pos->mvRotatedAtomList.begin(); at!=pos->mvRotatedAtomList.end();++at) { if(*at==&((*r)->GetAtom1())) ct++; if(*at==&((*r)->GetAtom2())) ct++; if(*at==&((*r)->GetAtom3())) ct++; if(*at==&((*r)->GetAtom4())) ct++; } bool broken=true; if((ct==0)||(ct==4)) broken=false; if(broken) {// Make sure with derivatives REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); pos->CalcDeriv(false); (*r)->GetLogLikelihood(true,true); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); if(d>0.01) break; } if(abs(d)<=0.01) broken=false; } if(broken) pos->mvpBrokenDihedralAngle.insert(make_pair(*r,0)); } if(mFlexModel.GetChoice()==2) { int nb=pos->mvpBrokenDihedralAngle.size(); if(pos->mpDihedralAngle!=0) nb -= 1; if(nb>0) keep=false; } if(keep) ++pos; else pos=mvStretchModeTorsion.erase(pos); TAU_PROFILE_STOP(timer4); } for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]); this->RestoreParamSet(mLocalParamSet); #ifdef __DEBUG__ cout<<"List of Dihedral Angle stretch modes("<::const_iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();++pos) { cout<<" Dihedral Angle:" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<", Rotated Atoms: "; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } if(pos->mpDihedralAngle!=0) cout<restrained by dihedral angle "<mpDihedralAngle->GetName() <<"to :"<mpDihedralAngle->GetAngle0()*RAD2DEG <<"�, sigma="<mpDihedralAngle->GetAngleSigma()*RAD2DEG <<"�, delta="<mpDihedralAngle->GetAngleDelta()*RAD2DEG<<"�"; if(pos->mvpBrokenBond.size()>0) { cout<::const_iterator bond=pos->mvpBrokenBond.begin(); bond!=pos->mvpBrokenBond.end();++bond) cout<first->GetName()<<", "; } if(pos->mvpBrokenBondAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenBondAngle.begin(); angle!=pos->mvpBrokenBondAngle.end();++angle) cout<first->GetName()<<", "; } if(pos->mvpBrokenDihedralAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenDihedralAngle.begin(); angle!=pos->mvpBrokenDihedralAngle.end();++angle) cout<first->GetName()<<", "; } cout<mClockBondList) &&(mClockStretchModeTwist>mClockAtomList) &&(mClockStretchModeTwist>mClockBondAngleList) &&(mClockStretchModeTwist>mClockDihedralAngleList)) return; #endif VFN_DEBUG_ENTRY("Molecule::BuildStretchModeTwist()",7) this->BuildConnectivityTable(); mvStretchModeTwist.clear(); // For each pair of atoms, build an internal chain to twist. for(vector::const_iterator atom1=this->GetAtomList().begin(); atom1!=this->GetAtomList().end();++atom1) { const set *pConn=&(mConnectivityTable[*atom1]); vector::const_iterator atom2=atom1; atom2++; for(;atom2!=this->GetAtomList().end();++atom2) { for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) {// Start from one atom connected to atom1 if(*pos==*atom2) continue; mvStretchModeTwist.push_back(StretchModeTwist(**atom1,**atom2)); mvStretchModeTwist.back().mvRotatedAtomList.insert(*atom1); ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvStretchModeTwist.back().mvRotatedAtomList, *atom2); //Check if this chains actually leads to atom2 set::const_iterator check =find(mvStretchModeTwist.back().mvRotatedAtomList.begin(), mvStretchModeTwist.back().mvRotatedAtomList.end(),*atom2); bool keep =true; if( (check==mvStretchModeTwist.back().mvRotatedAtomList.end()) ||(mvStretchModeTwist.back().mvRotatedAtomList.size()<3) ||(mvStretchModeTwist.back().mvRotatedAtomList.size()>=((mvpAtom.size()+1)/2))) { keep=false; } if(keep) { mvStretchModeTwist.back().mvRotatedAtomList.erase(*atom1); mvStretchModeTwist.back().mvRotatedAtomList.erase(*atom2); if( (mvStretchModeTwist.back().mvRotatedAtomList.size()>=(mvpAtom.size()/2)) ||(mvStretchModeTwist.back().mvRotatedAtomList.size()==0)) { #ifdef __DEBUG__ cout<<"Rejecting StretchModeTwist ";mvStretchModeTwist.back().Print(cout);cout<1) {//Duplicate ? // Does not work with a const_reverse_iterator ? // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729 list::reverse_iterator mode=mvStretchModeTwist.rbegin(); ++mode; for(;mode!=mvStretchModeTwist.rend();++mode) { if( ( ((mode->mpAtom1==*atom1)&&(mode->mpAtom2==*atom2)) ||((mode->mpAtom1==*atom2)&&(mode->mpAtom2==*atom1))) &&(mode->mvRotatedAtomList==mvStretchModeTwist.back().mvRotatedAtomList)) { #ifdef __DEBUG__ cout<<"Duplicate StretchModeTwist ";mvStretchModeTwist.back().Print(cout);cout<0) // Torsion and twist modes can be identical for cycles. {//Duplicate ? // Does not work with a const_reverse_iterator ? // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729 list::reverse_iterator mode; for(mode=mvStretchModeTorsion.rbegin();mode!=mvStretchModeTorsion.rend();++mode) { if( ( ((mode->mpAtom1==*atom1)&&(mode->mpAtom2==*atom2)) ||((mode->mpAtom1==*atom2)&&(mode->mpAtom2==*atom1))) &&(mode->mvRotatedAtomList==mvStretchModeTwist.back().mvRotatedAtomList)) { #ifdef __DEBUG__ cout<<"Duplicate StretchModeTwist (with Torsion) ";mvStretchModeTwist.back().Print(cout);cout<SaveParamSet(mLocalParamSet); unsigned long paramSetRandom[5]; for(unsigned long i=0;i<5;++i) { for(vector::iterator pos=mvpAtom.begin();pos!=mvpAtom.end();++pos) { (*pos)->SetX(100.*rand()/(REAL) RAND_MAX); (*pos)->SetY(100.*rand()/(REAL) RAND_MAX); (*pos)->SetZ(100.*rand()/(REAL) RAND_MAX); } paramSetRandom[i]=this->CreateParamSet(); } // find bond, bond angles and dihedral angles broken by each mode for(list::iterator pos=mvStretchModeTwist.begin(); pos!=mvStretchModeTwist.end();) { pos->mvpBrokenBond.clear(); pos->mvpBrokenBondAngle.clear(); pos->mvpBrokenDihedralAngle.clear(); pos->CalcDeriv(); #ifdef __DEBUG__ cout<<" DerivLLK for Twist mode around:" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<": Moving atoms:"; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<","; cout<::const_iterator r=mvpBond.begin();r!=mvpBond.end();++r) { (*r)->GetLogLikelihood(true,true); REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); } if(abs(d)>0.1) { #ifdef __DEBUG__ cout<<" Bond "<<(*r)->GetName() <<": dLength/da="<mvpBrokenBond.insert(make_pair(*r,0.0)); } } for(vector::const_iterator r=mvpBondAngle.begin();r!=mvpBondAngle.end();++r) { (*r)->GetLogLikelihood(true,true); REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); } if(abs(d)>0.01) { #ifdef __DEBUG__ cout<<" BondAngle:"<<(*r)->GetName()<<": dAngle/da="<mvpBrokenBondAngle.insert(make_pair(*r,0.0)); } } for(vector::const_iterator r=mvpDihedralAngle.begin(); r!=mvpDihedralAngle.end();++r) { //if(*r==pos->mpDihedralAngle) continue; (*r)->GetLogLikelihood(true,true); REAL d=0; for(unsigned long i=0;i<5;++i) { this->RestoreParamSet(paramSetRandom[i]); d += abs((*r)->GetDeriv(pos->mDerivXYZ)); } if(abs(d)>0.01) { #ifdef __DEBUG__ cout<<" DihedralAngle:"<<(*r)->GetName()<<": dAngle/da="<mvpBrokenDihedralAngle.insert(make_pair(*r,0.0)); } } //Get rid of stretch modes that break rigid groups bool keep=true; for(vector::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group) { unsigned long ct=0; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) ct += pos->mvRotatedAtomList.count(*at); if(ct>0) { // Add atom1 and atom2 to the count only if they are in the group // They do not move in absolute or relatively to the group. ct += (*group)->count(pos->mpAtom1); ct += (*group)->count(pos->mpAtom2); if(ct!=(*group)->size()) { keep=false; #ifdef __DEBUG__ cout<<" Breaks Rigid Group:"<size()<<":"; for(set::const_iterator at=(*group)->begin();at!=(*group)->end();++at) cout<<(*at)->GetName()<<" "; cout<mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size()) keep=false; } if(keep) ++pos; else pos=mvStretchModeTwist.erase(pos); } for(unsigned long i=0;i<5;++i) this->ClearParamSet(paramSetRandom[i]); this->RestoreParamSet(mLocalParamSet); #ifdef __DEBUG__ cout<<"List of Twist stretch modes("<::const_iterator pos=mvStretchModeTwist.begin(); pos!=mvStretchModeTwist.end();++pos) { cout<<" Twist mode:" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<", Rotated Atoms: "; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) { cout<<(*atom)->GetName()<<","; } if(pos->mvpBrokenBond.size()>0) { cout<::const_iterator bond=pos->mvpBrokenBond.begin(); bond!=pos->mvpBrokenBond.end();++bond) cout<first->GetName()<<", "; } if(pos->mvpBrokenBondAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenBondAngle.begin(); angle!=pos->mvpBrokenBondAngle.end();++angle) cout<first->GetName()<<", "; } if(pos->mvpBrokenDihedralAngle.size()>0) { cout<::const_iterator angle=pos->mvpBrokenDihedralAngle.begin(); angle!=pos->mvpBrokenDihedralAngle.end();++angle) cout<first->GetName()<<", "; } cout<CreateParamSet("Initial Configuration"); const unsigned int nbTest=100; // First we store in mBaseRotationAmplitude the cumulated atomic displacement // for nbTest rotations of 0.01 rad for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();++pos) pos->mBaseAmplitude=0; for(list::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();++pos) pos->mBaseAmplitude=0; REAL displacement=0;//For the global Molecule rotation for(unsigned int j=0;jRandomizeConfiguration(); // Atomic positions, orthonormal coordinates vector x0(this->GetNbComponent()); vector y0(this->GetNbComponent()); vector z0(this->GetNbComponent()); // Center of molecule coords REAL xc=0.,yc=0.,zc=0.; for(long i=0;iGetNbComponent();++i) { x0[i]=mvpAtom[i]->GetX(); xc += x0[i]; y0[i]=mvpAtom[i]->GetY(); yc += y0[i]; z0[i]=mvpAtom[i]->GetZ(); zc += z0[i]; } xc /= (REAL)(this->GetNbComponent()); yc /= (REAL)(this->GetNbComponent()); zc /= (REAL)(this->GetNbComponent()); // Record displacement amplitude for torsion angles REAL dx,dy,dz; for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();++pos) { const REAL dx10=pos->mpAtom0->GetX()-pos->mpAtom1->GetX(); const REAL dy10=pos->mpAtom0->GetY()-pos->mpAtom1->GetY(); const REAL dz10=pos->mpAtom0->GetZ()-pos->mpAtom1->GetZ(); const REAL dx12=pos->mpAtom2->GetX()-pos->mpAtom1->GetX(); const REAL dy12=pos->mpAtom2->GetY()-pos->mpAtom1->GetY(); const REAL dz12=pos->mpAtom2->GetZ()-pos->mpAtom1->GetZ(); const REAL vx=dy10*dz12-dz10*dy12; const REAL vy=dz10*dx12-dx10*dz12; const REAL vz=dx10*dy12-dy10*dx12; this->RotateAtomGroup(*(pos->mpAtom1),vx,vy,vz,pos->mvRotatedAtomList,0.01,false); for(long i=0;iGetNbComponent();++i) { dx=x0[i]-mvpAtom[i]->GetX(); dy=y0[i]-mvpAtom[i]->GetY(); dz=z0[i]-mvpAtom[i]->GetZ(); pos->mBaseAmplitude+=sqrt(abs(dx*dx+dy*dy+dz*dz)); } this->RotateAtomGroup(*(pos->mpAtom1),vx,vy,vz,pos->mvRotatedAtomList,-0.01,false); } for(list::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();++pos) { this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),pos->mvRotatedAtomList,0.01,false); for(long i=0;iGetNbComponent();++i) { dx=x0[i]-mvpAtom[i]->GetX(); dy=y0[i]-mvpAtom[i]->GetY(); dz=z0[i]-mvpAtom[i]->GetZ(); pos->mBaseAmplitude+=sqrt(abs(dx*dx+dy*dy+dz*dz)); } this->RotateAtomGroup(*(pos->mpAtom1),*(pos->mpAtom2),pos->mvRotatedAtomList,-0.01,false); } // Record displacement amplitude for global rotation, for 10 random rot axis for(unsigned int k=0;k<10;++k) { Quaternion quat=Quaternion::RotationQuaternion (mBaseRotationAmplitude,(REAL)rand(),(REAL)rand(),(REAL)rand()); for(long i=0;iGetNbComponent();++i) { REAL x=x0[i]-xc; REAL y=y0[i]-yc; REAL z=z0[i]-zc; quat.RotateVector(x,y,z); dx=(x0[i]-xc)-x; dy=(y0[i]-yc)-y; dz=(z0[i]-zc)-z; displacement+=sqrt(abs(dx*dx+dy*dy+dz*dz)); } } } // Modify base rotation amplitudes, for an average 0.02 Angstroem displacement for(list::iterator pos=mvStretchModeBondAngle.begin(); pos!=mvStretchModeBondAngle.end();++pos) { pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent())); pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude; if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17; bool free=true; if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0) { pos->mBaseAmplitude/=10; free=false; } #if 1// def __DEBUG__ cout<<"ANGLE :" <mpAtom0->GetName()<<"-" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<":"; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<","; cout <<": base rotation="<mBaseAmplitude*RAD2DEG<<" free="<::iterator pos=mvStretchModeTorsion.begin(); pos!=mvStretchModeTorsion.end();++pos) { pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent())); pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude; if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17; bool free=true; if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0) { pos->mBaseAmplitude/=10; free=false; } #if 1// def __DEBUG__ cout<<"TORSION :" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<":"; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<","; cout <<": base rotation="<mBaseAmplitude*RAD2DEG<<" free="<::iterator pos=mvStretchModeTwist.begin(); pos!=mvStretchModeTwist.end();++pos) { pos->mBaseAmplitude/=(REAL)(nbTest*this->GetNbComponent());//(REAL)(nbTest*(0.5*pos->mvRotatedAtomList.size()+0.5*this->GetNbComponent())); pos->mBaseAmplitude=0.1*0.01/pos->mBaseAmplitude; if(pos->mBaseAmplitude>.17) pos->mBaseAmplitude=.17; bool free=true; if((pos->mvpBrokenBond.size()+pos->mvpBrokenBondAngle.size()+pos->mvpBrokenDihedralAngle.size())>0) { pos->mBaseAmplitude/=10; free=false; } #if 1// def __DEBUG__ cout<<"TWIST :" <mpAtom1->GetName()<<"-" <mpAtom2->GetName()<<":"; for(set::const_iterator atom=pos->mvRotatedAtomList.begin(); atom!=pos->mvRotatedAtomList.end();++atom) cout<<(*atom)->GetName()<<","; cout <<": base rotation="<mBaseAmplitude*RAD2DEG<<" free="<GetNbComponent()); //cout<<"Overall Atomic Displacement for Global Rotation:="<0) mBaseRotationAmplitude*=0.1/displacement; if(mBaseRotationAmplitude<(0.02*M_PI/20.)) { mBaseRotationAmplitude=0.02*M_PI/20.; //cout <<"WARNING - too low Global BaseRotationAmplitude - setting to: " // << mBaseAmplitude*RAD2DEG<< " �"<(0.02*M_PI*20.)) { mBaseRotationAmplitude=0.02*M_PI*20.; //cout <<"WARNING - too high Global BaseRotationAmplitude - setting to: " // << mBaseAmplitude*RAD2DEG<< " �"< Base rotation="<RestoreParamSet(initialConfig); VFN_DEBUG_EXIT("Molecule::TuneGlobalOptimRotationAmplitude()",5) } void Molecule::BuildFlipGroup() { this->BuildConnectivityTable(); if( (mClockFlipGroup>mClockConnectivityTable) &&(mClockFlipGroup>mClockRigidGroup)) return; VFN_DEBUG_ENTRY("Molecule::BuildFlipGroup()",5) TAU_PROFILE("Molecule::BuildFlipGroup()","void ()",TAU_DEFAULT); mvFlipGroup.clear(); for(vector::const_iterator atom0=this->GetAtomList().begin(); atom0!=this->GetAtomList().end();++atom0) { const set *pConn=&(mConnectivityTable[*atom0]); if(pConn->size()<3) continue; // Build all chains for(set::const_iterator pos1=pConn->begin();pos1!=pConn->end();++pos1) { for(set::const_iterator pos2=pos1;pos2!=pConn->end();++pos2) { if(*pos2==*pos1) continue; if(mFlexModel.GetChoice()==0) { mvFlipGroup.push_back(FlipGroup(**atom0,**pos1,**pos2)); bool foundRing=false; for(set::const_iterator pos=pConn->begin();pos!=pConn->end();++pos) { if((pos==pos1)||(pos==pos2)) continue; mvFlipGroup.back().mvRotatedChainList.push_back( make_pair(*pos,set())); mvFlipGroup.back().mvRotatedChainList.back().second.insert(*atom0); ExpandAtomGroupRecursive(*pos,mConnectivityTable, mvFlipGroup.back().mvRotatedChainList.back().second); mvFlipGroup.back().mvRotatedChainList.back().second.erase(*atom0); set::const_iterator ringdetect1,ringdetect2; ringdetect1=find(mvFlipGroup.back().mvRotatedChainList.back().second.begin(), mvFlipGroup.back().mvRotatedChainList.back().second.end(), *pos1); ringdetect2=find(mvFlipGroup.back().mvRotatedChainList.back().second.begin(), mvFlipGroup.back().mvRotatedChainList.back().second.end(), *pos2); if( (ringdetect1!=mvFlipGroup.back().mvRotatedChainList.back().second.end()) ||(ringdetect2!=mvFlipGroup.back().mvRotatedChainList.back().second.end())) foundRing=true; } unsigned long flipSize=0; for(list > >::const_iterator chain=mvFlipGroup.back().mvRotatedChainList.begin(); chain!=mvFlipGroup.back().mvRotatedChainList.end();++chain) flipSize+=chain->second.size(); if(((flipSize*2)>mvpAtom.size())||foundRing) mvFlipGroup.pop_back(); } // Add the entry which will exchange atom1 and atom2 (this entry can be a ring) mvFlipGroup.push_back(FlipGroup(**atom0,**pos1,**pos2)); mvFlipGroup.back().mvRotatedChainList.push_back( make_pair(*atom0,set())); mvFlipGroup.back().mvRotatedChainList.back().second.insert(*atom0); ExpandAtomGroupRecursive(*pos1,mConnectivityTable, mvFlipGroup.back().mvRotatedChainList.back().second); ExpandAtomGroupRecursive(*pos2,mConnectivityTable, mvFlipGroup.back().mvRotatedChainList.back().second); mvFlipGroup.back().mvRotatedChainList.back().second.erase(*atom0); if((mvFlipGroup.back().mvRotatedChainList.back().second.size()*2)>mvpAtom.size()) mvFlipGroup.pop_back(); } } } // Exclude flip groups that include only a part of any rigid group for(list::iterator pos=mvFlipGroup.begin(); pos!=mvFlipGroup.end();) { // This should not be necessary ? Why keep one list for each chain, and not one big ? set fullset; for(list > >::iterator chain=pos->mvRotatedChainList.begin(); chain!=pos->mvRotatedChainList.end();++chain) for(set::const_iterator at=chain->second.begin();at!=chain->second.end();++at) fullset.insert(*at); bool keep=true; for(vector::const_iterator group=mvRigidGroup.begin(); group!=mvRigidGroup.end();++group) { unsigned long ct=0; for(set::const_iterator at=fullset.begin();at!=fullset.end();++at) ct+=(*group)->count(*at); if((ct>0)&&(ct<(*group)->size())) {keep=false; break;} } if(!keep) { cout <<"EXCLUDING flip group (breaking a rigid group): " <mpAtom0->GetName()<<",exchanging bonds with " <mpAtom1->GetName()<<" and " <mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : "; for(set::iterator pos1=pos->mvRotatedChainList.begin()->second.begin(); pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; cout<::iterator pos=mvFlipGroup.begin(); pos!=mvFlipGroup.end();) { if(pos->mpAtom0->IsNonFlipAtom()) { cout <<"EXCLUDING flip group (central atom is in the non-flip list): " <mpAtom0->GetName()<<",exchanging bonds with " <mpAtom1->GetName()<<" and " <mpAtom2->GetName()<<", resulting in a 180deg rotation of atoms : "; for(set::iterator pos1=pos->mvRotatedChainList.begin()->second.begin(); pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; cout<SaveParamSet(mLocalParamSet); #if 1//def __DEBUG__ // const REAL llk0=this->GetLogLikelihood(); for(list::iterator pos=mvFlipGroup.begin(); pos!=mvFlipGroup.end();++pos) { if(pos->mvRotatedChainList.begin()->first==pos->mpAtom0) { cout <<"Flip group from atom " <mpAtom0->GetName()<<",exchanging bonds with " <mpAtom1->GetName()<<" and " <mpAtom2->GetName()<<", resulting in a 180� rotation of atoms : "; for(set::iterator pos1=pos->mvRotatedChainList.begin()->second.begin(); pos1!=pos->mvRotatedChainList.begin()->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; } else { cout <<"Flip group with respect to: " <mpAtom1->GetName()<<"-" <mpAtom0->GetName()<<"-" <mpAtom2->GetName()<<" : "; for(list > >::const_iterator chain=pos->mvRotatedChainList.begin(); chain!=pos->mvRotatedChainList.end();++chain) { cout<<" -"<first->GetName()<<":"; for(set::const_iterator pos1=chain->second.begin(); pos1!=chain->second.end();++pos1) cout<<(*pos1)->GetName()<<" "; } } #if 0 // test if they do not break something (dihedral angle restraint) ? // We seldom try flippping, so don't test - test is done during optimization this->FlipAtomGroup(*pos); const REAL dllk=this->GetLogLikelihood()-llk0; if(dllk>1000.) { pos = mvFlipGroup.erase(pos); --pos; cout <<" -> NOT a free flip, d(llk)="<RestraintStatus(cout); } else cout <<" -> free flip, d(llk)="<RestoreParamSet(mLocalParamSet); #endif cout< > vpBond; for(list::const_iterator mode=mvStretchModeBondLength.begin(); mode!=mvStretchModeBondLength.end();++mode) { if(mode->mpBond!=0) vpBond[mode->mpBond].insert(&(*mode)); for(map::const_iterator pos=mode->mvpBrokenBond.begin(); pos!=mode->mvpBrokenBond.end();++pos) vpBond[pos->first].insert(&(*mode)); } for(list::const_iterator mode=mvStretchModeBondAngle.begin(); mode!=mvStretchModeBondAngle.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBond.begin(); pos!=mode->mvpBrokenBond.end();++pos) vpBond[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeTorsion.begin(); mode!=mvStretchModeTorsion.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBond.begin(); pos!=mode->mvpBrokenBond.end();++pos) vpBond[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeTwist.begin(); mode!=mvStretchModeTwist.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBond.begin(); pos!=mode->mvpBrokenBond.end();++pos) vpBond[pos->first].insert(&(*mode)); map > vpAngle; for(list::const_iterator mode=mvStretchModeBondLength.begin(); mode!=mvStretchModeBondLength.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBondAngle.begin(); pos!=mode->mvpBrokenBondAngle.end();++pos) vpAngle[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeBondAngle.begin(); mode!=mvStretchModeBondAngle.end();++mode) { if(mode->mpBondAngle!=0) vpAngle[mode->mpBondAngle].insert(&(*mode)); for(map::const_iterator pos=mode->mvpBrokenBondAngle.begin(); pos!=mode->mvpBrokenBondAngle.end();++pos) vpAngle[pos->first].insert(&(*mode)); } for(list::const_iterator mode=mvStretchModeTorsion.begin(); mode!=mvStretchModeTorsion.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBondAngle.begin(); pos!=mode->mvpBrokenBondAngle.end();++pos) vpAngle[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeTwist.begin(); mode!=mvStretchModeTwist.end();++mode) for(map::const_iterator pos=mode->mvpBrokenBondAngle.begin(); pos!=mode->mvpBrokenBondAngle.end();++pos) vpAngle[pos->first].insert(&(*mode)); map > vpDihed; for(list::const_iterator mode=mvStretchModeBondLength.begin(); mode!=mvStretchModeBondLength.end();++mode) for(map::const_iterator pos=mode->mvpBrokenDihedralAngle.begin(); pos!=mode->mvpBrokenDihedralAngle.end();++pos) vpDihed[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeBondAngle.begin(); mode!=mvStretchModeBondAngle.end();++mode) for(map::const_iterator pos=mode->mvpBrokenDihedralAngle.begin(); pos!=mode->mvpBrokenDihedralAngle.end();++pos) vpDihed[pos->first].insert(&(*mode)); for(list::const_iterator mode=mvStretchModeTorsion.begin(); mode!=mvStretchModeTorsion.end();++mode) { if(mode->mpDihedralAngle!=0) vpDihed[mode->mpDihedralAngle].insert(&(*mode)); for(map::const_iterator pos=mode->mvpBrokenDihedralAngle.begin(); pos!=mode->mvpBrokenDihedralAngle.end();++pos) vpDihed[pos->first].insert(&(*mode)); } for(list::const_iterator mode=mvStretchModeTwist.begin(); mode!=mvStretchModeTwist.end();++mode) for(map::const_iterator pos=mode->mvpBrokenDihedralAngle.begin(); pos!=mode->mvpBrokenDihedralAngle.end();++pos) vpDihed[pos->first].insert(&(*mode)); #if 0 for(map >::const_iterator pos=vpBond.begin();pos!=vpBond.end();++pos) { cout<<"Bond "<first->GetName()<<" is modified by the stretch modes:"<::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode) { cout<<" "; (*mode)->Print(cout); cout< >::const_iterator pos=vpAngle.begin();pos!=vpAngle.end();++pos) { cout<<"Bond Angle "<first->GetName()<<" is modified by the stretch modes:"<::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode) { cout<<" "; (*mode)->Print(cout); cout< >::const_iterator pos=vpDihed.begin();pos!=vpDihed.end();++pos) { cout<<"Dihedral Angle "<first->GetName()<<" is modified by the stretch modes:"<::const_iterator mode=pos->second.begin();mode!=pos->second.end();++mode) { cout<<" "; (*mode)->Print(cout); cout<::iterator mode=mvStretchModeBondLength.begin(); mode!=mvStretchModeBondLength.end();++mode) { int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size(); if(mode->mpBond!=0) nb -= 1; if(nb==0) mvpStretchModeFree.push_back(&(*mode)); else mvpStretchModeNotFree.push_back(&(*mode)); } for(list::iterator mode=mvStretchModeBondAngle.begin(); mode!=mvStretchModeBondAngle.end();++mode) { int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size(); if(mode->mpBondAngle!=0) nb -= 1; if(nb==0) mvpStretchModeFree.push_back(&(*mode)); else mvpStretchModeNotFree.push_back(&(*mode)); } for(list::iterator mode=mvStretchModeTorsion.begin(); mode!=mvStretchModeTorsion.end();++mode) { int nb=mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size(); if(mode->mpDihedralAngle!=0) nb -= 1; if(nb==0) mvpStretchModeFree.push_back(&(*mode)); else mvpStretchModeNotFree.push_back(&(*mode)); } #if 1 for(list::iterator mode=mvStretchModeTwist.begin(); mode!=mvStretchModeTwist.end();++mode) if(mode->mvpBrokenDihedralAngle.size()+mode->mvpBrokenBondAngle.size()+mode->mvpBrokenBond.size()==0) mvpStretchModeFree.push_back(&(*mode)); else mvpStretchModeNotFree.push_back(&(*mode)); #endif } void Molecule::BuildMDAtomGroups() { // For each atom, list all atoms that are never moved relatively to it. // (not moved == distance cannot change) map > vBoundAtoms; set set0; for(vector::iterator pos=this->GetAtomList().begin();pos!=this->GetAtomList().end();++pos) set0.insert(*pos); for(vector::iterator pat1=this->GetAtomList().begin();pat1!=this->GetAtomList().end();++pat1) { vBoundAtoms[*pat1]=set0; for(vector::iterator pat2=this->GetAtomList().begin();pat2!=this->GetAtomList().end();++pat2) { bool cont=false; for(list::iterator pstretch=this->GetStretchModeBondLengthList().begin(); pstretch!=this->GetStretchModeBondLengthList().end();++pstretch) { set::iterator pos1=pstretch->mvTranslatedAtomList.find(*pat1), pos2=pstretch->mvTranslatedAtomList.find(*pat2); if( ((pos1==pstretch->mvTranslatedAtomList.end())&&(pos2!=pstretch->mvTranslatedAtomList.end())) ||((pos1!=pstretch->mvTranslatedAtomList.end())&&(pos2==pstretch->mvTranslatedAtomList.end()))) { vBoundAtoms[*pat1].erase(*pat2); //cout<<(*pat1)->GetName()<<" moves (b) relatively to "<<(*pat2)->GetName()<<" /"; //pstretch->Print(cout);cout<::iterator pstretch=this->GetStretchModeBondAngleList().begin(); pstretch!=this->GetStretchModeBondAngleList().end();++pstretch) { //pstretch->mpAtom1 does not move relatively to any atom if((*pat1==pstretch->mpAtom1)||(*pat2==pstretch->mpAtom1)) continue; set::iterator pos1=pstretch->mvRotatedAtomList.find(*pat1), pos2=pstretch->mvRotatedAtomList.find(*pat2); //:TODO: Take into account the special case of the atoms defining the bond angle if( ((pos1==pstretch->mvRotatedAtomList.end())&&(pos2!=pstretch->mvRotatedAtomList.end())) ||((pos1!=pstretch->mvRotatedAtomList.end())&&(pos2==pstretch->mvRotatedAtomList.end()))) { vBoundAtoms[*pat1].erase(*pat2); //cout<<(*pat1)->GetName()<<" moves (a) relatively to "<<(*pat2)->GetName()<<" /"; //pstretch->Print(cout);cout<::iterator pstretch=this->GetStretchModeTorsionList().begin(); pstretch!=this->GetStretchModeTorsionList().end();++pstretch) { set::iterator pos1=pstretch->mvRotatedAtomList.find(*pat1), pos2=pstretch->mvRotatedAtomList.find(*pat2); if( (pos1!=pstretch->mvRotatedAtomList.end())&&(pos2==pstretch->mvRotatedAtomList.end()) &&(*pat2!=pstretch->mpAtom1) &&(*pat2!=pstretch->mpAtom2) ) { vBoundAtoms[*pat1].erase(*pat2); //cout<<(*pat1)->GetName()<<" moves (d1) relatively to "<<(*pat2)->GetName()<<" /"; //pstretch->Print(cout);cout<mvRotatedAtomList.end())&&(pos2!=pstretch->mvRotatedAtomList.end()) &&(*pat1!=pstretch->mpAtom1) && (*pat1!=pstretch->mpAtom2) ) { vBoundAtoms[*pat1].erase(*pat2); //cout<<(*pat1)->GetName()<<" moves (d2) relatively to "<<(*pat2)->GetName()<<" /"; //pstretch->Print(cout);cout< > vBoundGroups; for(map >::iterator pos=vBoundAtoms.begin();pos!=vBoundAtoms.end();++pos) { #if 0 cout<<"Non-flexible group from "<first->GetName()<<": "; for(set::const_iterator atom=pos->second.begin();atom!=pos->second.end();++atom) cout<<(*atom)->GetName()<<","; cout<::iterator pr=this->GetRigidGroupList().begin();pr!=this->GetRigidGroupList().end();++pr) for(set::iterator at=(*pr)->begin();at!=(*pr)->end();++at) pos->second.erase(*at); if(pos->second.size()>1) vBoundGroups.insert(pos->second); } #if 0 for(set >::iterator pos=vBoundGroups.begin();pos!=vBoundGroups.end();++pos) { cout<<"Non-flexible group:"; for(set::const_iterator atom=pos->begin();atom!=pos->end();++atom) cout<<(*atom)->GetName()<<","; cout< >::iterator pos=vBoundGroups.begin();pos!=vBoundGroups.end();++pos) { set vb; for(vector::iterator pr=this->GetBondList().begin();pr!=this->GetBondList().end();++pr) if( (pos->find(&(*pr)->GetAtom1())!=pos->end()) ||(pos->find(&(*pr)->GetAtom2())!=pos->end())) vb.insert(*pr); set va; for(vector::iterator pr=this->GetBondAngleList().begin();pr!=this->GetBondAngleList().end();++pr) if( (pos->find(&(*pr)->GetAtom1())!=pos->end()) ||(pos->find(&(*pr)->GetAtom2())!=pos->end()) ||(pos->find(&(*pr)->GetAtom3())!=pos->end())) va.insert(*pr); set vd; for(vector::iterator pr=this->GetDihedralAngleList().begin();pr!=this->GetDihedralAngleList().end();++pr) if( (pos->find(&(*pr)->GetAtom1())!=pos->end()) ||(pos->find(&(*pr)->GetAtom2())!=pos->end()) ||(pos->find(&(*pr)->GetAtom3())!=pos->end()) ||(pos->find(&(*pr)->GetAtom4())!=pos->end())) vd.insert(*pr); set tmp= *pos;// Cannot pass *pos directly ? gcc bug evaluating const-ness? mvMDAtomGroup.push_back(MDAtomGroup(tmp,vb,va,vd)); mvMDAtomGroup.back().Print(cout); } // Create mvMDFullAtomGroup mvMDFullAtomGroup.clear(); #if 1 // All atoms except those in rigid groups for(vector::iterator at=this->GetAtomList().begin();at!=this->GetAtomList().end();++at) mvMDFullAtomGroup.insert(*at); for(vector::iterator pr=this->GetRigidGroupList().begin();pr!=this->GetRigidGroupList().end();++pr) for(set::iterator at=(*pr)->begin();at!=(*pr)->end();++at) mvMDFullAtomGroup.erase(*at); cout<<"Full MD atom group:"<::const_iterator pos=mvMDFullAtomGroup.begin();pos!=mvMDFullAtomGroup.end();++pos) cout<<(*pos)->GetName()<<" "; cout<::const_iterator pos= mvMDAtomGroup.begin();pos!= mvMDAtomGroup.end();++pos) for(set::const_iterator at=pos->mvpAtom.begin();at!=pos->mvpAtom.end();++at) mvMDFullAtomGroup.insert(*at); cout<<"Full MD atom group:"<::const_iterator pos=mvMDFullAtomGroup.begin();pos!=mvMDFullAtomGroup.end();++pos) cout<<(*pos)->GetName()<<" "; cout<GetCrystal().GetClockLatticePar()GetNbComponent(); // Get internal coords for(long i=0;iIsDummy()) mScattCompList(i).mpScattPow=0; else mScattCompList(i).mpScattPow=&(mvpAtom[i]->GetScatteringPower()); mScattCompList(i).mX=mvpAtom[i]->GetX(); mScattCompList(i).mY=mvpAtom[i]->GetY(); mScattCompList(i).mZ=mvpAtom[i]->GetZ(); mScattCompList(i).mOccupancy=mvpAtom[i]->GetOccupancy()*mOccupancy; } #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // During an optimization, apply the translations & rotations of the rigid group parameters if(true)//this->IsBeingRefined()) { for(vector::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { (*pos)->mQuat.Normalize(); // Center of the atom group REAL x0=0,y0=0,z0=0; for(set::iterator at=(*pos)->mvIdx.begin();at!=(*pos)->mvIdx.end();++at) { x0+=mvpAtom[*at]->GetX(); y0+=mvpAtom[*at]->GetY(); z0+=mvpAtom[*at]->GetZ(); } x0/=(*pos)->size(); y0/=(*pos)->size(); z0/=(*pos)->size(); // Apply rotation & translation to all atoms for(set::iterator at=(*pos)->mvIdx.begin();at!=(*pos)->mvIdx.end();++at) { REAL x=mvpAtom[*at]->GetX()-x0, y=mvpAtom[*at]->GetY()-y0, z=mvpAtom[*at]->GetZ()-z0; (*pos)->mQuat.RotateVector(x,y,z); mScattCompList(*at).mX=x+x0+(*pos)->mX; mScattCompList(*at).mY=y+y0+(*pos)->mY; mScattCompList(*at).mZ=z+z0+(*pos)->mZ; } } } #endif // translate center to (0,0,0) REAL x0=0,y0=0,z0=0; if((mMoleculeCenter.GetChoice()==0) || (mpCenterAtom==0)) { for(long i=0;iGetX(); y0=mpCenterAtom->GetY(); z0=mpCenterAtom->GetZ(); } for(long i=0;iGetCrystal().OrthonormalToFractionalCoords(mScattCompList(i).mX, mScattCompList(i).mY, mScattCompList(i).mZ); } // translate center to position in unit cell for(long i=0;i::reverse_iterator Molecule::FindAtom(const string &name) { VFN_DEBUG_ENTRY("Molecule::FindAtom():"<::reverse_iterator rpos; for(rpos=mvpAtom.rbegin();rpos!=mvpAtom.rend();++rpos) if(name==(*rpos)->GetName()) { VFN_DEBUG_EXIT("Molecule::FindAtom():"<::const_reverse_iterator Molecule::FindAtom(const string &name)const { vector::const_reverse_iterator rpos; rpos=mvpAtom.rbegin(); for(rpos=mvpAtom.rbegin();rpos!=mvpAtom.rend();++rpos) if(name==(*rpos)->GetName()) return rpos; return rpos; } void Molecule::InitOptions() { VFN_DEBUG_ENTRY("Molecule::InitOptions",7) static string Flexname; static string Flexchoices[3]; static string FlipName; static string FlipChoice[2]; static string autoOptimizeConformationName; static string autoOptimizeConformationChoices[2]; static string optimizeOrientationName; static string optimizeOrientationChoices[2]; static string moleculeCenterName; static string moleculeCenterChoices[2]; static bool needInitNames=true; if(true==needInitNames) { Flexname="Flexibility Model"; Flexchoices[0]="Automatic from Restraints, relaxed - RECOMMENDED"; Flexchoices[1]="Rigid Body"; Flexchoices[2]="Automatic from Restraints, strict"; //Flexchoices[3]="Molecular Dynamics"; FlipName="Enable Flipping"; FlipChoice[0]="Yes"; FlipChoice[1]="No"; autoOptimizeConformationName="Auto Optimize Starting Conformation"; autoOptimizeConformationChoices[0]="Yes"; autoOptimizeConformationChoices[1]="No"; optimizeOrientationName="Optimize Orientation"; optimizeOrientationChoices[0]="Yes"; optimizeOrientationChoices[1]="No"; moleculeCenterName="Rotation Center"; moleculeCenterChoices[0]="Geometrical center (recommended)"; moleculeCenterChoices[1]="User-chosen Atom"; needInitNames=false; } mFlexModel.Init(3,&Flexname,Flexchoices); mFlexModel.SetChoice(0); this->AddOption(&mFlexModel); mFlipModel.Init(2, &FlipName, FlipChoice); mFlipModel.SetChoice(0); this->AddOption(&mFlipModel); mAutoOptimizeConformation.Init(2,&autoOptimizeConformationName, autoOptimizeConformationChoices); this->AddOption(&mAutoOptimizeConformation); mOptimizeOrientation.Init(2,&optimizeOrientationName,optimizeOrientationChoices); this->AddOption(&mOptimizeOrientation); mMoleculeCenter.Init(2,&moleculeCenterName,moleculeCenterChoices); this->AddOption(&mMoleculeCenter); VFN_DEBUG_EXIT("Molecule::InitOptions",7) } Molecule::FlipGroup::FlipGroup(const MolAtom &at0,const MolAtom &at1,const MolAtom &at2): mpAtom0(&at0),mpAtom1(&at1),mpAtom2(&at2),mNbTest(0),mNbAccept(0) { } void Molecule::FlipAtomGroup(const FlipGroup& group, const bool keepCenter) { TAU_PROFILE("Molecule::FlipAtomGroup(FlipGroup&)","void (...)",TAU_DEFAULT); if(group.mpAtom0==group.mvRotatedChainList.back().first) {// We are doing a 180� rotation exchanging two bonds const REAL vx=group.mpAtom0->X()-(group.mpAtom1->X()+group.mpAtom2->X())/2.; const REAL vy=group.mpAtom0->Y()-(group.mpAtom1->Y()+group.mpAtom2->Y())/2.; const REAL vz=group.mpAtom0->Z()-(group.mpAtom1->Z()+group.mpAtom2->Z())/2.; this->RotateAtomGroup(*(group.mpAtom0),vx,vy,vz, group.mvRotatedChainList.back().second,M_PI,keepCenter); } else {// we are flipping bonds with respect to a plane defined by other bonds REAL v01x=group.mpAtom1->X()-group.mpAtom0->X(); REAL v01y=group.mpAtom1->Y()-group.mpAtom0->Y(); REAL v01z=group.mpAtom1->Z()-group.mpAtom0->Z(); const REAL norm01=sqrt(v01x*v01x+v01y*v01y+v01z*v01z+1e-7); v01x /= norm01;v01y /= norm01;v01z /= norm01; REAL v02x=group.mpAtom2->X()-group.mpAtom0->X(); REAL v02y=group.mpAtom2->Y()-group.mpAtom0->Y(); REAL v02z=group.mpAtom2->Z()-group.mpAtom0->Z(); const REAL norm02=sqrt(v02x*v02x+v02y*v02y+v02z*v02z+1e-7); v02x /= norm02;v02y /= norm02;v02z /= norm02; REAL v12x=group.mpAtom2->X()-group.mpAtom1->X(); REAL v12y=group.mpAtom2->Y()-group.mpAtom1->Y(); REAL v12z=group.mpAtom2->Z()-group.mpAtom1->Z(); const REAL norm12=sqrt(v12x*v12x+v12y*v12y+v12z*v12z+1e-7); v12x /= norm12;v12y /= norm12;v12z /= norm12; REAL v0mx=group.mpAtom0->X()-(group.mpAtom1->X()+group.mpAtom2->X())/2.; REAL v0my=group.mpAtom0->Y()-(group.mpAtom1->Y()+group.mpAtom2->Y())/2.; REAL v0mz=group.mpAtom0->Z()-(group.mpAtom1->Z()+group.mpAtom2->Z())/2.; const REAL norm0m=sqrt(v0mx*v0mx+v0my*v0my+v0mz*v0mz+1e-7); v0mx /= norm0m;v0my /= norm0m;v0mz /= norm0m; if(fabs(v01x*v02x+v01y*v02y+v01z*v02z) >0.05*sqrt(abs( (v01x*v01x+v01y*v01y+v01z*v01z) *(v02x*v02x+v02y*v02y+v02z*v02z)))) { REAL v012x=v01y*v02z-v01z*v02y; REAL v012y=v01z*v02x-v01x*v02z; REAL v012z=v01x*v02y-v01y*v02x; const REAL norm012=sqrt(v012x*v012x+v012y*v012y+v012z*v012z+1e-7); v012x /= norm012;v012y /= norm012;v012z /= norm012; for(list > >::const_iterator chain=group.mvRotatedChainList.begin(); chain!=group.mvRotatedChainList.end();++chain) { REAL v03x=chain->first->X()-group.mpAtom0->X(); REAL v03y=chain->first->Y()-group.mpAtom0->Y(); REAL v03z=chain->first->Z()-group.mpAtom0->Z(); const REAL norm03=sqrt( v03x*v03x + v03y*v03y + v03z*v03z +1e-7); v03x /= norm03;v03y /= norm03;v03z /= norm03; const REAL a1=v012x*v03x+v012y*v03y+v012z*v03z; const REAL a2= v0mx*v03x+ v0my*v03y+ v0mz*v03z; const REAL a3= v12x*v03x+ v12y*v03y+ v12z*v03z; REAL angle = -a1/sqrt(1-a3*a3+1e-7); if(angle>=1.) angle = M_PI/2.; else { if(angle<=-1.) { angle = -M_PI/2.; } else angle = asin(angle); } if(a2<0) angle=M_PI-angle; this->RotateAtomGroup(*(group.mpAtom0),v12x,v12y,v12z, chain->second,2*angle,keepCenter); } } } } void Molecule::SetDeleteSubObjInDestructor(const bool b) { mDeleteSubObjInDestructor=b; } void Molecule::ResetRigidGroupsPar()const { #ifdef RIGID_BODY_STRICT_EXPERIMENTAL // Apply the translations & rotations of all rigid group parameters, and // use this as the newly stored atomic coordinates. for(vector::const_iterator pos=this->GetRigidGroupList().begin();pos!=this->GetRigidGroupList().end();++pos) { (*pos)->mQuat.Normalize(); // Center of atom group REAL x0=0,y0=0,z0=0; for(set::iterator at=(*pos)->begin();at!=(*pos)->end();++at) { x0+=(*at)->GetX(); y0+=(*at)->GetY(); z0+=(*at)->GetZ(); } x0/=(*pos)->size(); y0/=(*pos)->size(); z0/=(*pos)->size(); // Apply rotation & translation to all atoms for(set::iterator at=(*pos)->begin();at!=(*pos)->end();++at) { REAL x=(*at)->GetX()-x0, y=(*at)->GetY()-y0, z=(*at)->GetZ()-z0; (*pos)->mQuat.RotateVector(x,y,z); (*at)->SetX(x+x0+(*pos)->mX); (*at)->SetY(y+y0+(*pos)->mY); (*at)->SetZ(z+z0+(*pos)->mZ); } // Reset the translation & rotation parameters, only useful during an optimization (*pos)->mX=0; (*pos)->mY=0; (*pos)->mZ=0; (*pos)->mQuat.Q0()=1; (*pos)->mQuat.Q1()=0; (*pos)->mQuat.Q2()=0; (*pos)->mQuat.Q3()=0; } #endif } #ifdef __WX__CRYST__ WXCrystObjBasic* Molecule::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("Molecule::WXCreate()",5) mpWXCrystObj=new WXMolecule(parent,this); VFN_DEBUG_EXIT("Molecule::WXCreate()",5) return mpWXCrystObj; } #endif Molecule *ZScatterer2Molecule(ZScatterer *scatt) { VFN_DEBUG_ENTRY("ZScatterer2Molecule()",6) Molecule *mol=new Molecule(scatt->GetCrystal(),scatt->GetName()); const unsigned long nb=scatt->GetZAtomRegistry().GetNb(); REAL x0=0,y0=0,z0=0; for(unsigned int i=0;iGetZAtomX(i); const REAL y=scatt->GetZAtomY(i); const REAL z=scatt->GetZAtomZ(i); x0+=x; y0+=y; z0+=z; mol->AddAtom(x,y,z,scatt->GetZAtomRegistry().GetObj(i).GetScatteringPower(), scatt->GetZAtomRegistry().GetObj(i).GetName()); #if 0 if(i>0) { const RefinablePar* pLength=&(scatt->GetPar(&(scatt->GetZAtomRegistry() .GetObj(i).GetZBondLength()))); if(pLength->IsFixed()) mol->AddBond(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)), pLength->GetValue(),.01,.02,false); else if(pLength->IsLimited()) mol->AddBond(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)), (pLength->GetMin()+pLength->GetMax())/2.,.01,.02,false); } if(i>1) { const RefinablePar* pAngle=&(scatt->GetPar(&(scatt->GetZAtomRegistry() .GetObj(i).GetZAngle()))); if(pAngle->IsFixed()) mol->AddBondAngle(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)), mol->GetAtom(scatt->GetZAngleAtom(i)), pAngle->GetValue(),.01,.02,false); else if(pAngle->IsLimited()) mol->AddBondAngle(mol->GetAtom(i),mol->GetAtom(scatt->GetZBondAtom(i)), mol->GetAtom(scatt->GetZAngleAtom(i)), (pAngle->GetMin()+pAngle->GetMax())/2.,.01,.02,false); } if(i>2) { const RefinablePar* pDihed=&(scatt->GetPar(&(scatt->GetZAtomRegistry() .GetObj(i).GetZDihedralAngle()))); MolAtom *p1=&(mol->GetAtom(i)); MolAtom *p2=&(mol->GetAtom(scatt->GetZBondAtom(i))); MolAtom *p3=&(mol->GetAtom(scatt->GetZAngleAtom(i))); MolAtom *p4=&(mol->GetAtom(scatt->GetZDihedralAngleAtom(i))); if( (fabs(GetBondAngle(*p1,*p2,*p3)-M_PI)>0.3) &&(fabs(GetBondAngle(*p1,*p2,*p4)-M_PI)>0.3) &&(fabs(GetBondAngle(*p1,*p3,*p4)-M_PI)>0.3) &&(fabs(GetBondAngle(*p2,*p3,*p4)-M_PI)>0.3)) { if(pDihed->IsFixed()) mol->AddDihedralAngle(*p1,*p2,*p3,*p4,pDihed->GetValue(),.01,.02,false); else if(((pDihed->GetMax()-pDihed->GetMax())<0.3)&&(i>2)&&(pDihed->IsLimited())) mol->AddDihedralAngle(*p1,*p2,*p3,*p4, (pDihed->GetMin()+pDihed->GetMax())/2.,.01,.02,false); } } #endif mol->GetAtom(i).SetOccupancy(scatt->GetZAtomRegistry().GetObj(i).GetOccupancy()); } CrystVector_REAL x(nb),y(nb),z(nb),radius(nb); vector > scattpow(nb); for(unsigned int i=0;iGetAtom(i).GetX(); y(i)=mol->GetAtom(i).GetY(); z(i)=mol->GetAtom(i).GetZ(); if(mol->GetAtom(i).IsDummy()) { radius(i)=-1; scattpow[i].first=0; } else { radius(i)=mol->GetAtom(i).GetScatteringPower().GetRadius(); scattpow[i].first=dynamic_cast (&(mol->GetAtom(i).GetScatteringPower())); scattpow[i].second=scattpow[i].first->GetAtomicNumber(); } } for(unsigned int i=0;i d="<AddBond(mol->GetAtom(i),mol->GetAtom(j),dist,.01,.02,false); } } } x += x1; y += y1; z += z1; } mol->BuildConnectivityTable(); for(map >::const_iterator pos=mol->GetConnectivityTable().begin(); pos!=mol->GetConnectivityTable().end();++pos) { for(set::const_iterator pos1=pos->second.begin(); pos1!=pos->second.end();++pos1) { for(set::const_iterator pos2=pos1; pos2!=pos->second.end();++pos2) { if(pos2==pos1) continue; if(mol->FindBondAngle(**pos1,*(pos->first),**pos2)== mol->GetBondAngleList().end()) mol->AddBondAngle(**pos1,*(pos->first),**pos2, GetBondAngle(**pos1,*(pos->first),**pos2),0.01,0.02,false); } } } x0 /= nb; y0 /= nb; z0 /= nb; mol->GetCrystal().OrthonormalToFractionalCoords(x0,y0,z0); mol->SetX(x0); mol->SetY(y0); mol->SetZ(z0); mol->UpdateDisplay(); VFN_DEBUG_EXIT("ZScatterer2Molecule()",6) return mol; } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Molecule.h000066400000000000000000001731071417150057700227730ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Molecule.h * header file for the Molecule scatterer * */ #ifndef _OBJCRYST_MOLECULE_H_ #define _OBJCRYST_MOLECULE_H_ #include #include #include #include #include #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/ObjCryst/Scatterer.h" namespace ObjCryst { class MolAtom; class MolBond; class Molecule; /// Structure holding 3 coordinates, or deriviatives with respect to each of these coordinates struct XYZ { XYZ(REAL x=0,REAL y=0,REAL z=0); REAL x,y,z; }; /** MolAtom : atom inside a Molecule * * This keeps coordinates, recorded in a cartesian frame (in Angstroem), * the associated scattering power * and it also keeps in a list of all bonds in which this atom is involved. * * \note maybe it's not a great idea to keep a reference of bonds for this * atom in here */ class MolAtom { public: /** Constructor for a MolAtom * */ MolAtom(const REAL x, const REAL y, const REAL z, const ScatteringPower *pPow, const string &name, Molecule &parent); /** Destructor * * Tells the parent Molecule and all Bond that it is being destroyed. */ virtual ~MolAtom(); void SetName(const string &name); const string& GetName()const; string& GetName(); const Molecule& GetMolecule()const; Molecule& GetMolecule(); const REAL& X()const; const REAL& Y()const; const REAL& Z()const; REAL& X(); REAL& Y(); REAL& Z(); REAL GetX()const; REAL GetY()const; REAL GetZ()const; REAL GetOccupancy()const; //@{ /// Set the X,Y,Z coordinate - this is const because sometimes their /// coordinate must be changed even though the atom does not move, /// if the atom is part of a rigid group (its position is then described /// by a combination of atomic cooordinates, plus a global /// translation and rotation... void SetX(const REAL)const; void SetY(const REAL)const; void SetZ(const REAL)const; //@} void SetOccupancy(const REAL); /** Returns true if this is a dummy atom, i.e. without an associated scattering power. * * Dummy atoms can be used to mark positions, or for restraints. */ bool IsDummy()const; const ScatteringPower& GetScatteringPower()const; void SetScatteringPower(const ScatteringPower&); virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); /// Flag this atom as being in a ring (or not). This is a const method /// because the existence of a ring is only a consequence of the connectivity /// of the Molecule. void SetIsInRing(const bool r)const; bool IsInRing()const; /** Set a flag to prevent the atom's absolute configuration to be changed. * \param nonflip: if true, the atom. * * \internal This should only be changed by Molecule::AddNonFlipAtom() and Molecule::RemoveNonFlipAtom() */ void SetNonFlipAtom(const bool nonflip); /// Can this atom be flipped (return=false) or should its absolute configuration be kept (return=true) bool IsNonFlipAtom() const; /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; private: /// Name for this atom string mName; /* Get the atom at the other end of bond #i MolAtom & GetBondedAtom(unsigned int i); */ /** Cartesian oordinates in the Molecule reference frame. * * mutable because they may need to be changed when in a rigid group, * even though the end position of the atom remains the same. */ mutable REAL mX,mY,mZ; /// Occupancy REAL mOccupancy; /// ScatteringPower const ScatteringPower* mpScattPow; /// Parent Molecule Molecule *mpMol; /// Is the atom in a ring ? mutable bool mIsInRing; /// Can the atom be flipped (this is used for optically active atom which should keep their absolute configuration bool mIsNonFlipAtom; #ifdef __WX__CRYST__ public: WXCrystObjBasic *mpWXCrystObj; virtual WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); #endif }; /// Get The Bond Length between two atoms REAL GetBondLength(const MolAtom&,const MolAtom&); /// Get The Bond Angle of 3 atoms REAL GetBondAngle(const MolAtom&,const MolAtom&,const MolAtom&); /// Get The dihedral angle defined by 4 atoms REAL GetDihedralAngle(const MolAtom&,const MolAtom&,const MolAtom&,const MolAtom&); /** Bond between two atoms, also a restraint on the associated bond length. * */ class MolBond:public Restraint { public: /** Constructor * * Both atoms of the bond are told of the creation of the bond, so that * they can keep a list of bonds they are involved in. * * \param atom1, atom2: the atoms of the bond * \param length: the expected bond length * \param sigma,delta: depending on the calculated length, the log(likelihood) is equal to: * - within \f$[length_{0}-\delta;length_{0}+\delta]\f$: * \f$ -\log(likelihood)= \log\left(2\delta+\sqrt{2\pi\sigma^2}\right)\f$ * - if \f$length > length_{0}+\delta\f$: * \f$ -\log(likelihood)= \log\left(2\delta+\sqrt{2\pi\sigma^2}\right) * + \left(\frac{(length-\delta)-length_{0}}{\sigma} \right)^2\f$ * - if \f$length < length_{0}-\delta\f$: * \f$ -\log(likelihood)= \log\left(2\delta+\sqrt{2\pi\sigma^2}\right) * + \left(\frac{(length+\delta)-length_{0}}{\sigma} \right)^2\f$ * */ MolBond(MolAtom &atom1, MolAtom &atom2, const REAL length, const REAL sigma, const REAL delta, Molecule &parent,const REAL bondOrder=1.); /** Destructor * * Notifies the atoms that the bond has disappeared. */ virtual ~MolBond(); const Molecule& GetMolecule()const; Molecule& GetMolecule(); /// Name of the bond, e.g. "C3-O4" string GetName()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual REAL GetLogLikelihood()const; REAL GetLogLikelihood(const bool calcDeriv, const bool recalc)const; /// Get the derivative of the bond length, given the derivatives of the atom positions /// This requires that GetLogLikelihood(calcDeriv=true) be called first. /// If llk=true, this will return the derivative of the llk rather than the derivative of the length or angle REAL GetDeriv(const std::map &m, const bool llk=false)const; /** Calc log(likelihood) gradient - versus all atomic coordinates * * \param m: this map should have been initialized by adding all possible atom * pointers as keys, with all XYZ values equal to zeros. On return, the derivative * of the log(likelihood) vs each atomic coordinates will \b added * to each coordinate of the corresponding atoms. */ void CalcGradient(std::map &m)const; const MolAtom& GetAtom1()const; const MolAtom& GetAtom2()const; MolAtom& GetAtom1(); MolAtom& GetAtom2(); void SetAtom1(MolAtom &at1); void SetAtom2(MolAtom &at2); REAL GetLength()const; REAL GetLength0()const; REAL GetLengthDelta()const; REAL GetLengthSigma()const; REAL GetBondOrder()const; REAL& Length0(); REAL& LengthDelta(); REAL& LengthSigma(); REAL& BondOrder(); void SetLength0(const REAL length); void SetLengthDelta(const REAL length); void SetLengthSigma(const REAL length); void SetBondOrder(const REAL length); bool IsFreeTorsion()const; void SetFreeTorsion(const bool isInRing); /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; private: pair mAtomPair; REAL mLength0,mDelta,mSigma; REAL mBondOrder; bool mIsFreeTorsion; /// Parent Molecule Molecule *mpMol; /// Stored log(likelihood) mutable REAL mLLK; /** Derivatives of the bond length with respect to the coordinates of the atoms * * The derivatives are calculated in MolBond::GetLogLikelihood(true) */ mutable XYZ mDerivAtom1,mDerivAtom2; /** The factor used to change the derivative of the length/angle, to the derivative * of the log(likelihood). e.g. (for mDelta=0) \f$ mDerivLLKCoeff = \frac{L-L_0}{\sigma^2} \f$ */ mutable REAL mDerivLLKCoeff; #ifdef __WX__CRYST__ public: WXCrystObjBasic *mpWXCrystObj; virtual WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); #endif }; /** Bond angle restraint between 3 atoms. * * The atoms involved need not be bonded. * * */ class MolBondAngle:public Restraint { public: /** Constructor * */ MolBondAngle(MolAtom &atom1,MolAtom &atom2,MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent); /** Destructor * */ virtual ~MolBondAngle(); const Molecule& GetMolecule()const; Molecule& GetMolecule(); string GetName()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual REAL GetLogLikelihood()const; REAL GetLogLikelihood(const bool calcDeriv, const bool recalc)const; /// Get the derivative of the angle, given the derivatives of the atom positions /// This requires that GetLogLikelihood(calcDeriv=true) be called first /// If llk=true, this will return the derivative of the llk rather than the derivative of the length or angle REAL GetDeriv(const std::map &m, const bool llk=false)const; /** Calc log(likelihood) gradient - versus all atomic coordinates * * \param m: this map should have been initialized by adding all possible atom * pointers as keys, with all XYZ values equal to zeros. On return, the derivative * of the log(likelihood) vs each atomic coordinates will \b added * to each coordinate of the corresponding atoms. */ void CalcGradient(std::map &m)const; REAL GetAngle()const; REAL& Angle0(); REAL& AngleDelta(); REAL& AngleSigma(); REAL GetAngle0()const; REAL GetAngleDelta()const; REAL GetAngleSigma()const; void SetAngle0(const REAL angle); void SetAngleDelta(const REAL delta); void SetAngleSigma(const REAL sigma); const MolAtom& GetAtom1()const; const MolAtom& GetAtom2()const; const MolAtom& GetAtom3()const; void SetAtom1(MolAtom &at); void SetAtom2(MolAtom &at); void SetAtom3(MolAtom &at); MolAtom& GetAtom1(); MolAtom& GetAtom2(); MolAtom& GetAtom3(); bool IsFlexible()const; void SetFlexible(const bool isInRing); std::size_t size() const; vector::const_iterator begin() const; vector::const_iterator end() const; /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; private: /// The vector of the 3 atoms involved in the bond angle. vector mvpAtom; REAL mAngle0,mDelta,mSigma; /// Parent Molecule Molecule *mpMol; /// When using the user-chosen flexibility model, this allows /// some flexibility for this bond angle, i.e. the bond angle /// does not remain strictly rigid, and is still restrained. bool mIsFlexible; /// Stored log(likelihood) mutable REAL mLLK; /** Partial derivatives of the angle with respect to the coordinates of the atoms * * The derivatives are calculated in MolBondAngle::GetLogLikelihood(true) */ mutable XYZ mDerivAtom1,mDerivAtom2,mDerivAtom3; /** The factor used to change the derivative of the length/angle, to the derivative * of the log(likelihood). e.g. (for mDelta=0) \f$ mDerivLLKCoeff = \frac{L-L_0}{\sigma^2} \f$ */ mutable REAL mDerivLLKCoeff; #ifdef __WX__CRYST__ public: WXCrystObjBasic *mpWXCrystObj; virtual WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); #endif }; /** Dihedral angle restraint between 4 atoms. * * The atoms involved need not be bonded. * * */ class MolDihedralAngle:public Restraint { public: /** Constructor * */ MolDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, Molecule &parent); /** Destructor * */ virtual ~MolDihedralAngle(); const Molecule& GetMolecule()const; Molecule& GetMolecule(); string GetName()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual REAL GetLogLikelihood()const; REAL GetLogLikelihood(const bool calcDeriv, const bool recalc)const; /// Get the derivative of the Angle, given the derivatives of the atom positions /// This requires that GetLogLikelihood(calcDeriv=true) be called first /// If llk=true, this will return the derivative of the llk rather than the derivative of the length or angle REAL GetDeriv(const std::map &m, const bool llk=false)const; /** Calc log(likelihood) gradient - versus all atomic coordinates * * \param m: this map should have been initialized by adding all possible atom * pointers as keys, with all XYZ values equal to zeros. On return, the derivative * of the log(likelihood) vs each atomic coordinates will \b added * to each coordinate of the corresponding atoms. */ void CalcGradient(std::map &m)const; REAL GetAngle()const; REAL& Angle0(); REAL& AngleDelta(); REAL& AngleSigma(); REAL GetAngle0()const; REAL GetAngleDelta()const; REAL GetAngleSigma()const; void SetAngle0(const REAL angle); void SetAngleDelta(const REAL delta); void SetAngleSigma(const REAL sigma); const MolAtom& GetAtom1()const; const MolAtom& GetAtom2()const; const MolAtom& GetAtom3()const; const MolAtom& GetAtom4()const; void SetAtom1(MolAtom& at); void SetAtom2(MolAtom& at); void SetAtom3(MolAtom& at); void SetAtom4(MolAtom& at); MolAtom& GetAtom1(); MolAtom& GetAtom2(); MolAtom& GetAtom3(); MolAtom& GetAtom4(); std::size_t size() const; vector::const_iterator begin() const; vector::const_iterator end() const; /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; private: /// The vector of the 4 atoms involved in the bond angle. vector mvpAtom; REAL mAngle0, mDelta, mSigma; /// Parent Molecule Molecule *mpMol; /// Stored log(likelihood) mutable REAL mLLK; /** Partial derivatives of the angle with respect to the coordinates of the atoms * * The derivatives are calculated in MolBondAngle::GetLogLikelihood(true) */ mutable XYZ mDerivAtom1,mDerivAtom2,mDerivAtom3,mDerivAtom4; /** The factor used to change the derivative of the length/angle, to the derivative * of the log(likelihood). e.g. (for mDelta=0) \f$ mDerivLLKCoeff = \frac{L-L_0}{\sigma^2} \f$ */ mutable REAL mDerivLLKCoeff; #ifdef __WX__CRYST__ public: WXCrystObjBasic *mpWXCrystObj; virtual WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); #endif }; /** Ring class * * \note This class could be used to restrain atom positions for * aromatic rings (planar restriction). * \note We could also store the aromatic status of the ring. */ class MolRing { public: MolRing(); const std::list& GetAtomList()const; std::list& GetAtomList(); /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; private: std::list mvpAtom; }; /** A quaternion class, used to represent the orientation of the molecule. * It may or may not be a unit quaternion. * */ class Quaternion { public: /// Default constructor, yields q=(1,0,0,0) Quaternion(); /// Creates a unit quaternion from its components (normalized automatically) Quaternion(const REAL q0,const REAL q1,const REAL q2,const REAL q3,bool unit=true); ~Quaternion(); /// Create a rotation quaternion around a given vector for a given angle static Quaternion RotationQuaternion(const REAL ang,const REAL v1,const REAL v2,const REAL v3); /// Get the conjugate of this quaternion (== the inverse if unit quaternion) Quaternion GetConjugate()const; /// Quaternion multiplication Quaternion operator*(const Quaternion &q)const; void operator*=(const Quaternion &q); void XMLOutput(ostream &os,int indent=0)const; void XMLInput(istream &is,const XMLCrystTag &tag); /// Rotate vector v=(v1,v2,v3). The rotated components are directly written void RotateVector(REAL &v1,REAL &v2, REAL &v3)const; /// Re-normalize the quaternion to unity. This should not be useful, except /// on individual component input, or after long calculations. And even /// if wrong, the rotation is independent of the norm of the quaternion. /// /// This is markerd const because we use only unit quaternions void Normalize()const ; REAL GetNorm()const; const REAL& Q0()const; const REAL& Q1()const; const REAL& Q2()const; const REAL& Q3()const; REAL& Q0(); REAL& Q1(); REAL& Q2(); REAL& Q3(); private: /// The components of the quaternion z=(q0,v) with v=(q1,q2,q3) /// /// These are mutable so that the quaternion can be normalized in a const method. mutable REAL mQ0,mQ1,mQ2,mQ3; bool mIsUniQuaternion; }; /** Rigid groups of atoms inside a molecule. * * These atoms can be moved as a group using * one rotation and one translation. * \warning: the rotation (quaternion) and translation parameters * are not saved or displayed, so any time this must be done * Molecule::ResetRigidGroupsPar() \b must be called beforehand - * this will use the rotation and translation parameters * to generate the final atomic coordinates, and reset mQuat,mX,mY and mZ. */ class RigidGroup:public std::set { public: std::string GetName()const; /// The unit quaternion defining the orientation - this is used /// during optimizations to rotate all atoms as a group. /// The quaternion does not give an absolute position - its value /// will be resetted whenever entering or leaving an optimization. mutable Quaternion mQuat; /// The translation of all the atoms as a group /// The values will be resetted whenever entering or leaving an optimization. mutable REAL mX,mY,mZ; /// Temporary list of the atoms indices in the molecule, used during optimization /// This is created in Molecule::BeginOptimization() mutable std::set mvIdx; /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; }; /** Abstract base Stretch Mode for Molecule objects * */ struct StretchMode { virtual ~StretchMode(); /** Calculate the derivative of the Molecule's Log(likelihood) and atomic positions * versus a change of the bond length. The result is stored in mLLKDeriv and mLLKDerivXYZ, * as well as in the various lists of restraints broken by this mode. * * \param derivllk: if false, the derivative of the overall llk will not be computed, only * the derivative of the atomic positions. **/ virtual void CalcDeriv(const bool derivllk=true)const=0; /// Print one-line list of atoms moved virtual void Print(ostream &os,bool full=true)const=0; /// Move the atoms according to this mode virtual void Stretch(const REAL change, const bool keepCenter=true)=0; /// Move the atoms according to this mode, randomly virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true)=0; /// List of bond restraints affected by this mode /// The key is the restraint, the value is the derivative of the LLK associated std::map mvpBrokenBond; /// List of bond angle restraints modified by this mode /// The key is the restraint, the value is the derivative of the LLK associated std::map mvpBrokenBondAngle; /// List of dihedral angle restraints modified by this mode /// The key is the restraint, the value is the derivative of the LLK associated std::map mvpBrokenDihedralAngle; /// Derivative of the Molecule's Log(likelihood) versus a change of the bond length. mutable REAL mLLKDeriv; /// Derivative of the atomic positions versus a change of the bond length. mutable std::map mDerivXYZ; /// The Molecule corresponding to this stretch mode Molecule *mpMol; /** The recommended change amplitude, for a base global optimization * displacement, to obtain an average 0.1 Angstroem displacement. * * This is learnt at the beginning of an optimization. * * This can be superseeded to respect any restraint. */ REAL mBaseAmplitude; }; /** Group of atoms for random moves changing a bond length. * * This should be merged (or have an inheritance relation) with MolBond. */ struct StretchModeBondLength:public StretchMode { /** Constructor * If pBond!=0, the bond length restraint is respected. */ StretchModeBondLength(MolAtom &at0,MolAtom &at1,const MolBond *pBond); virtual ~StretchModeBondLength(); virtual void CalcDeriv(const bool derivllk=true)const; /// Print one-line list of atoms moved virtual void Print(ostream &os,bool full=true)const; /// Move the atoms according to this mode virtual void Stretch(const REAL change, const bool keepCenter=true); /// Move the atoms according to this mode, randomly virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true); /// The first atom (fixed). MolAtom * mpAtom0; /// The second atom (first atom moved) MolAtom * mpAtom1; /// The (optional) bond length which this stretch mode should respect. const MolBond *mpBond; /// The set of atoms that are to be translated, including at1. set mvTranslatedAtomList; }; /** Atoms moved when changing a bond angle. * * This should be merged (or have an inheritance relation) with MolBondAngle. */ struct StretchModeBondAngle:public StretchMode { /** Constructor * If pBondAngle!=0, the bond angle length restraint is respected. */ StretchModeBondAngle(MolAtom &at0,MolAtom &at1,MolAtom &at2, const MolBondAngle *pBondAngle); virtual ~StretchModeBondAngle(); virtual void CalcDeriv(const bool derivllk=true)const; /// Print one-line list of atoms moved virtual void Print(ostream &os,bool full=true)const; /// Move the atoms according to this mode virtual void Stretch(const REAL change, const bool keepCenter=true); /// Move the atoms according to this mode, randomly virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true); /// The first atom MolAtom * mpAtom0; /// The second atom MolAtom * mpAtom1; /// The third atom MolAtom * mpAtom2; /// The (optional) bond angle restraint which this stretch mode should respect. const MolBondAngle *mpBondAngle; /// The set of atoms that are to be rotated around the direction going /// through at1 and perpendicular to the at0-at1-at2 plane. set mvRotatedAtomList; }; /** Atoms moved when rotated around a bond at0-at1-at2-at3 * * This should be merged (or have an inheritance relation) with MolDihedralAngle */ struct StretchModeTorsion:public StretchMode { /** Constructor * If pDihedralAngle!=0, the dihedral angle length restraint is respected. */ StretchModeTorsion(MolAtom &at1,MolAtom &at2, const MolDihedralAngle *pDihedralAngle); virtual ~StretchModeTorsion(); virtual void CalcDeriv(const bool derivllk=true)const; /// Print one-line list of atoms moved virtual void Print(ostream &os,bool full=true)const; /// Move the atoms according to this mode virtual void Stretch(const REAL change, const bool keepCenter=true); /// Move the atoms according to this mode, randomly virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true); /// The first atom MolAtom * mpAtom1; /// The second atom MolAtom * mpAtom2; /// The (optional) bond angle restraint which this stretch mode should respect. /// The mpAtom1 and mpAtom2 must be the central atoms of this restraint. const MolDihedralAngle *mpDihedralAngle; /// The set of atoms that are to be rotated around at1-at2 set mvRotatedAtomList; }; /** Atoms moved *between* two other atoms, using a "twist" *of their positions - only small twists of their positions * are allowed to avoid breaking restraints too much. Also, * the atoms in the middle between the two reference atoms are more * displaced than the one closer, to help avoid breaking restraints. */ struct StretchModeTwist:public StretchMode { /** Constructor * If pDihedralAngle!=0, the dihedral angle length restraint is respected. */ StretchModeTwist(MolAtom &at1,MolAtom &at2); virtual ~StretchModeTwist(); virtual void CalcDeriv(const bool derivllk=true)const; /// Print one-line list of atoms moved virtual void Print(ostream &os,bool full=true)const; /// Move the atoms according to this mode virtual void Stretch(const REAL change, const bool keepCenter=true); /// Move the atoms according to this mode, randomly virtual void RandomStretch(const REAL amplitude, const bool keepCenter=true); /// The first atom MolAtom * mpAtom1; /// The second atom MolAtom * mpAtom2; /// The set of atoms that are to be rotated around at1-at2 set mvRotatedAtomList; }; /** Groups of atoms that can be moved using molecular dynamics * principles, taking a list of restraints as ptential. * This is used to move group of atoms for which no adequate stretch mode * can be used, such as inside flexible rings. */ struct MDAtomGroup { /// Default constructor MDAtomGroup(); /** Constructor. * \param vat: list of atoms inside the group * \param vb,va,vd: list of bond, bond angle and dihedral angle restraints */ MDAtomGroup(std::set &vat, std::set &vb, std::set &va, std::set &vd); /// Print one-line list of atoms moved void Print(ostream &os,bool full=true)const; std::set mvpAtom; std::vector mvpBond; std::vector mvpBondAngle; std::vector mvpDihedralAngle; }; /** Light-weight representation of an atom in the molecule, as a part of a Z-matrix. * This is used to export the Molecule structure to a z-matrix. * * \todo: some flags could be added to mark the fixed/limited nature of the parameters. */ struct MolZAtom { const ScatteringPower *mpPow; unsigned long mBondAtom,mBondAngleAtom,mDihedralAtom; REAL mBondLength,mBondAngle,mDihedralAngle; }; /** Molecule : class for complex scatterer descriptions using * cartesian coordinates with bond length/angle restraints, and * moves either of individual atoms or using torsion bonds. * * This can also be used for non-organic compounds (polyhedras etc...) * \note the parametrization is very different from ZScatterer: we keep * a list of x,y,z which do not use limits (they must not), but the * coordinates must be restrained or constrained from the expected * bond lengths, angles and dihedral angles. The list of parameters is * re-created in BeginOptimization() (except for the global x y z parameters * for the global position of the Molecule, in fractionnal coordinates). * * \note : all atoms must be somehow connected */ class Molecule: public Scatterer { public: /** Constructor * */ Molecule(Crystal &cryst, const string &name=""); /** Copy constructor * */ Molecule(const Molecule &old); /** Destructor * */ ~Molecule(); virtual Molecule* CreateCopy() const; virtual const string& GetClassName() const; virtual void SetName(const string &name); /// Formula with atoms in alphabetic order std::string GetFormula() const; virtual void Print()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual void UpdateDisplay()const; virtual void BeginOptimization(const bool allowApproximations=false,const bool enableRestraints=false); virtual void EndOptimization(); virtual void RandomizeConfiguration(); virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type); virtual REAL GetLogLikelihood()const; virtual unsigned int GetNbLSQFunction()const; virtual const CrystVector_REAL& GetLSQCalc(const unsigned int) const; virtual const CrystVector_REAL& GetLSQObs(const unsigned int) const; virtual const CrystVector_REAL& GetLSQWeight(const unsigned int) const; virtual const CrystVector_REAL& GetLSQDeriv(const unsigned int n, RefinablePar&par); virtual void TagNewBestConfig()const; virtual int GetNbComponent() const; virtual const ScatteringComponentList& GetScatteringComponentList() const; virtual string GetComponentName(const int i) const; virtual ostream& POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const; #ifdef OBJCRYST_GL virtual void GLInitDisplayList(const bool onlyIndependentAtoms=false, const REAL xMin=-.1,const REAL xMax=1.1, const REAL yMin=-.1,const REAL yMax=1.1, const REAL zMin=-.1,const REAL zMax=1.1, const bool displayEnantiomer=false, const bool displayNames=false, const bool hideHydrogens=false, const REAL fadeDistance=0, const bool fullMoleculeInLimits=false)const; #endif // OBJCRYST_GL /** Add an atom * * */ void AddAtom(const REAL x, const REAL y, const REAL z, const ScatteringPower *pPow,const string &name, const bool updateDisplay=true); /** Remove an atom. Returns the iterator to the next atom in the list. * * This also removes all corresponding bonds, bond angles, etc... * If del is true (default), then the MolAtom object is deleted. The del * flag gets sent to the RemoveXXX functions for the corresponding * objects. */ vector::iterator RemoveAtom(MolAtom&, const bool del = true); /** Add a bond * * */ void AddBond(MolAtom &atom1, MolAtom &atom2, const REAL length, const REAL sigma, const REAL delta, const REAL bondOrder=1., const bool updateDisplay=true); /** Remove a bond. Returns the iterator to the next bond in the list. * * If del is true (default), then the MolBond object is deleted. * */ vector::iterator RemoveBond(const MolBond&, const bool del = true); /** Searches whether a bond between two atoms already exists. * * If no bond is found, returns Molecule::mvpAtom.end(). */ vector::const_iterator FindBond(const MolAtom&,const MolAtom&)const; /** Searches whether a bond between two atoms already exists. * * If no bond is found, returns Molecule::mvpAtom.end(). */ vector::iterator FindBond(const MolAtom&,const MolAtom&); /** Add a bond angle restraint * * */ void AddBondAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay=true); /** Remove a BondAngle * * If del is true (default), then the MolBondAngle object is deleted. */ vector::iterator RemoveBondAngle(const MolBondAngle&, const bool del = true); /** Searches whether a bond between three atoms already exists, * searching for either (at1,at2,at3) and (at3,at2,at1), as these are equivalent. * * If no bond angle is found, returns Molecule::mvpBondAngle.end(). */ vector::const_iterator FindBondAngle(const MolAtom& at1,const MolAtom&at0,const MolAtom&at2)const; /** Add a dihedral angle restraint * * */ void AddDihedralAngle(MolAtom &atom1, MolAtom &atom2, MolAtom &atom3, MolAtom &atom4, const REAL angle, const REAL sigma, const REAL delta, const bool updateDisplay=true); /** Remove a dihedral angle * * If del is true (default), then the MolDihedralAngle object is deleted. */ vector::iterator RemoveDihedralAngle(const MolDihedralAngle&, const bool del = true); /** Searches whether a dihedral between four atoms already exists, * searching for either (at1,at2,at3,at4) and (at4,at3,at2,at1), as these are equivalent. * * If no dihedral angle is found, returns Molecule::mvpDihedralAngle.end(). */ vector::const_iterator FindDihedralAngle(const MolAtom &at1, const MolAtom &at2, const MolAtom &at3, const MolAtom &at4)const; /** Add a rigid group of atoms. See Molecule::mvRigidGroup */ void AddRigidGroup(const RigidGroup&,const bool updateDisplay=true); /** Remove a rigid group of atoms. See Molecule::mvRigidGroup * * If del is true (default), then the RigidGroup object is deleted. */ std::vector::iterator RemoveRigidGroup(const RigidGroup &group,const bool updateDisplay=true, const bool del = true); MolAtom &GetAtom(unsigned int i); const MolAtom &GetAtom(unsigned int i)const; MolAtom &GetAtom(const string &name); const MolAtom &GetAtom(const string &name)const; /// Search a MolAtom from its name. Search begins at the end, and the /// first match is returned. returns mvAtom.rend() if no atom matches vector::reverse_iterator FindAtom(const string &name); /// Search a MolAtom from its name. Search begins at the end, and the /// first match is returned. returns mvAtom.rend() if no atom matches vector::const_reverse_iterator FindAtom(const string &name)const; /** Minimize configuration from internal restraints (bond lengths, angles * and dihedral angles). Useful when adding manually atoms to get an initial * reasonable configuration. */ void OptimizeConformation(const long nbTrial=10000,const REAL stopCost=0.); /** Optimize the conformation from internal restraints (bond lengths, angles * and dihedral angles), using a steepest descent algorithm. * *\param maxStep: maximum displacement allowed along any coordinate for all atoms. *\param nbStep: number of steps - the gradient is re-calculated after each step. */ void OptimizeConformationSteepestDescent(const REAL maxStep=0.1,const unsigned nbStep=1); /** Change the conformation of the molecule using molecular dynamics principles. * Optionnally, move only a subgroup of atoms and only take into account some restraints. * * The atoms actually moved are those included as keys in v0, and those part of the * rigid bodies in vr. * * \param v0: initial speed of all atoms. On return, includes the new speed coordinates. * Only the atoms used as keys in v0 will be moved, so this should be used to work * only on a subgroup of atoms. * \param nbStep: number of steps to perform. * \param dt: time step. Recommended value are such that v0[].xyz * dt = 0.001 * \param vb,va,vd: vector of bond, bond angle and dihedral angle restraints to * be taken into account. If these are empty, the full list of restraints of the Molecule * are taken into account, including rigid groups. If they are not empty, then * it is assumed that no atom moved belongs to a rigid group. * \param vr: initial speed for the angular and translation parameters of rigid groups * included in the evolution. For each entry of the map the first XYZ coordinates are the speed * for RigidGroup::mX,mY,mZ, and the second are the speed for the angular coordinates * of the quaternion Q1,Q2,Q3 * \param nrj0: the total energy the system should try to maintain. If equal to 0, * the initial energy will be used. The speed will be de/increased to compensate * any energy change. */ void MolecularDynamicsEvolve(std::map &v0,const unsigned nbStep,const REAL dt, const std::vector &vb,const std::vector &va, const std::vector &vd, std::map > &vr, REAL nrj0=0); const std::vector& GetAtomList()const; const std::vector& GetBondList()const; const std::vector& GetBondAngleList()const; const std::vector& GetDihedralAngleList()const; std::vector& GetAtomList(); std::vector& GetBondList(); std::vector& GetBondAngleList(); std::vector& GetDihedralAngleList(); std::list& GetStretchModeBondLengthList(); std::list& GetStretchModeBondAngleList(); std::list& GetStretchModeTorsionList(); const std::list& GetStretchModeBondLengthList()const; const std::list& GetStretchModeBondAngleList()const; const std::list& GetStretchModeTorsionList()const; /** List of rigid group of atoms. See Molecule::mvRigidGroup */ const std::vector& GetRigidGroupList()const; /** List of rigid group of atoms. See Molecule::mvRigidGroup */ std::vector& GetRigidGroupList(); /** Rotate a group of atoms around an axis defined by two atoms * * \param keepCenter: if true, the coordinates of the molecule are modified * so that only the rotated atoms are moved. */ void RotateAtomGroup(const MolAtom &at1,const MolAtom &at2, const set &atoms, const REAL angle, const bool keepCenter=true); /** Rotate a group of atoms around an axis defined by one atom and a vector * * \param keepCenter: if true, the coordinates of the molecule are modified * so that only the rotated atoms are moved. */ void RotateAtomGroup(const MolAtom &at,const REAL vx,const REAL vy,const REAL vz, const set &atoms, const REAL angle, const bool keepCenter=true); /** Translate a group of atoms in a given direction * * \param keepCenter: if true, the coordinates of the molecule are modified * so that only the translated atoms are moved. */ void TranslateAtomGroup(const set &atoms, const REAL dx,const REAL dy,const REAL dz, const bool keepCenter=true); /// Print the status of all restraints (bond length, angles...) void RestraintStatus(ostream &os)const; /// Print the restraints (bond length, angles...) as whole labels and number in column text format which accessible to other programs void RestraintExport(ostream &os)const; /// Get the connectivity table const map > & GetConnectivityTable(); /// get the clock associated to the list of bonds RefinableObjClock& GetBondListClock(); /// get the clock associated to the list of bonds const RefinableObjClock& GetBondListClock()const; /// Get the clock associated to the atomic positions RefinableObjClock& GetAtomPositionClock(); /// Get the clock associated to the atomic positions const RefinableObjClock& GetAtomPositionClock()const; /// Get the clock associated to the scattering powers const RefinableObjClock& GetAtomScattPowClock()const; /// Get the clock associated to the scattering powers RefinableObjClock& GetAtomScattPowClock(); /// Get the clock associated to the list of rigid groups ///(clicked also whenever a rigid group is modified) RefinableObjClock& GetRigidGroupClock(); /// Get the clock associated to the list of rigid groups ///(clicked also whenever a rigid group is modified) const RefinableObjClock& GetRigidGroupClock()const; /** Add dihedral angles so as to rigidify the Molecule. * * In practice, for every sequence of atoms A-B-C-D, add the dihedral angle * defined by these 4 atoms, unless either ABC or BCD are aligned (angle below 10�). * * No duplicate dihedral angle is generated. */ void RigidifyWithDihedralAngles(); /** Stretch a bond, while respecting the Restraint (if any). * *\return the \e actual change in bond length. *\param: the desired change in bond length. This will be the actual change \e if * there is no restraint \e or if the restraint is constant in this range. */ REAL BondLengthRandomChange(const StretchModeBondLength& mode, const REAL amplitude, const bool respectRestraint=true); /** change a bond angle, while respecting the Restraint (if any). * *\return the \e actual change in bond angle. *\param: the desired angular change. This will be the actual change \e if * there is no restraint \e or if the restraint is constant in this range. */ REAL BondAngleRandomChange(const StretchModeBondAngle& mode, const REAL amplitude, const bool respectRestraint=true); /** Change a dihedral angle, while respecting the Restraint (if any). * *\return the \e actual change in bond angle. *\param: the desired angular change. This will be the actual change \e if * there is no restraint \e or if the restraint is constant in this range. */ REAL DihedralAngleRandomChange(const StretchModeTorsion& mode, const REAL amplitude, const bool respectRestraint=true); /// Get the atom defining the origin of the Molecule /// Equal to 0 if no atom as been set. const MolAtom* GetCenterAtom()const; /// Get the atom defining the origin of the Molecule /// Equal to 0 if no atom as been set. void SetCenterAtom(const MolAtom &at); /** Molecule as Z-matrix * * \param keeporder: if true, the order of the atoms is exactly the same as in * the Molecule. */ const std::vector& AsZMatrix(const bool keeporder)const; /** Set whether to delete the MolAtoms, MolBonds, MolBondAngles and * MolDihedralAngles in the destructor. By default these sub-objects are * deleted. */ void SetDeleteSubObjInDestructor(const bool b); public: virtual void InitRefParList(); /** Build the list of rings in the molecule. * * The list is \e only rebuilt if the bond or atom list has changed,so * it should be safe to call again this function. * * \note So far this is a const method as the ring list just reflects the bond list * and therefore is mutable (see Molecule::mvRing)... but maybe this could * change... */ void BuildRingList(); /** Build the Connectivity table * */ void BuildConnectivityTable()const; /** Build the groups of atoms that will be rotated during global optimization. * * This is not const because we temporarily modify the molecule conformation * to test which RotorGroups are forbidden by restraints (but it should be const). */ void BuildRotorGroup(); /** Tune the rotation amplitude for free torsions and for the overall Molecule * Rotation. * * This should be done after Molecule::BuildRotorGroup(); */ void TuneGlobalOptimRotationAmplitude(); /** Build the groups of atoms that can be flipped. * * This is not const because we temporarily modify the molecule conformation * to test which FlipGroups are forbidden by restraints (but it should be const). */ void BuildFlipGroup(); /** Build the groups of atoms moved when stretching a bond length, while * respecting the Molecule restraints. */ void BuildStretchModeBondLength(); /** Build the groups of atoms moved when changing a bond angle, while * respecting the Molecule restraints. */ void BuildStretchModeBondAngle(); /** Build the groups of atoms moved when changing a dihedral angle, while * respecting the Molecule restraints. */ void BuildStretchModeTorsion(); /** Build the groups of atoms used to twist internally the Molecule, e.g. by * rotating one chain of atoms between 2 given atoms. */ void BuildStretchModeTwist(); /** Separate StretchMode that break more than their assigned restraint from others. * See Molecule::mvpStretchModeFree and Molecule::mvpStretchModeNotFree */ void BuildStretchModeGroups(); /** Find groups of atoms that cannot be moved relatively to each other * using the free or non-free stretch modes. Usually these will correspond * to atoms inside a flexible ring. * * These atoms (if they are not in a rigid group) are stored in a MDAtomGroup * so that they can still move using molecular dynamics. * *\b this should be called after BuildStretchModeGroups(), to make sure the * list of free/non-free stretch mode has been built. */ void BuildMDAtomGroups(); /** Update the Molecule::mScattCompList from the cartesian coordinates * of all atoms, and the orientation parameters. */ void UpdateScattCompList()const; /// Build options for this object void InitOptions(); /** Set the orientation & translation parameters of all rigid * groups to 0, after correcting the atomic positions. * This is \b required before saving the structure, as these * parameters are not saved. */ void ResetRigidGroupsPar()const; /** The list of scattering components * * this is mutable since it only reflects the list of atoms. */ mutable ScatteringComponentList mScattCompList; /** The list of atoms * */ vector mvpAtom; /** The list of bonds * */ vector mvpBond; /** The list of bond angles * */ vector mvpBondAngle; /** The list of dihedral angles * */ vector mvpDihedralAngle; /** List of Bonds for each atom. * * This duplicates the information in Molecule::mvBond */ map > mvAtomBond; /** Rigid groups of atoms. This group will be kept \e strictly rigid, * preventing the use of any stretch mode altering their relative position. * The entire group of atoms can however be rotated or translated. */ std::vector mvRigidGroup; /** The list of rings * * \note this only reflects the bond list, so it is mutable. */ mutable list mvRing; /** The unit quaternion defining the orientation * */ Quaternion mQuat; /** Base Rotation amplitude (in radians) for the Molecule, so that * the average atomic displacement is equal to 0.1 A * * Default=0.02*pi */ // Flag indicating whether to destroy MolAtoms, MolBonds, MolBondAngles, // and MolDihedralAngles in the destructor (default true). Mofified by // SetDeleteSubObjInDestructor. bool mDeleteSubObjInDestructor; REAL mBaseRotationAmplitude; // Clocks RefinableObjClock mClockAtomList; RefinableObjClock mClockBondList; RefinableObjClock mClockBondAngleList; RefinableObjClock mClockDihedralAngleList; RefinableObjClock mClockRigidGroup; /// This clock is the parent of mClockAtomList, mClockBondList, mClockBondAngleList, /// mClockDihedralAngleList and mClockRigidGroup. It can be used to determine if /// either the list of atoms or restraints have changed. RefinableObjClock mClockRestraint; RefinableObjClock mClockAtomPosition; RefinableObjClock mClockAtomScattPow; RefinableObjClock mClockOrientation; mutable RefinableObjClock mClockLogLikelihood; mutable RefinableObjClock mClockConnectivityTable; mutable RefinableObjClock mClockRingList; mutable RefinableObjClock mClockRotorGroup; mutable RefinableObjClock mClockFlipGroup; mutable RefinableObjClock mClockStretchModeBondLength; mutable RefinableObjClock mClockStretchModeBondAngle; mutable RefinableObjClock mClockStretchModeTorsion; mutable RefinableObjClock mClockStretchModeTwist; mutable RefinableObjClock mClockMDAtomGroup; // For local minimization (EXPERIMENTAL) unsigned long mLocalParamSet; mutable unsigned long mRandomConformChangeNbTest; mutable unsigned long mRandomConformChangeNbAccept; mutable REAL mRandomConformChangeTemp; REAL mLastLogLike; bool mIsSelfOptimizing; /// OPtion for the different types of flexibility possible for this /// molecule: rigid body, free atoms + restraints, torsion angles... /// \warning still EXPERIMENTAL ! RefObjOpt mFlexModel; RefObjOpt mFlipModel; /** Option to automatically optimize the starting conformation, if the * total restraint cost is too high. This is done in BeginOptimization(). * * This is enabled by default, and should be disabled by people who already * supply a good starting conformation for their molecule. */ RefObjOpt mAutoOptimizeConformation; /** Option to optimize the Molecule's orientation. Useful to completely * fix the Molecule. */ RefObjOpt mOptimizeOrientation; /** Option to choose the center of rotation of the Molecule for the global orientation * either as the geometrical center, or as a given atom. */ RefObjOpt mMoleculeCenter; /** Atom chosen as center of rotation, if mRotationCenter is set to use * an atom rather than the geometrical center. */ const MolAtom* mpCenterAtom; /// Connectivity table: for each atom, keep the list of atoms /// bonded to it. All atoms are referenced from their index. mutable map > mConnectivityTable; /** Defines a group of atoms which can be rotated around an axis defined * by two other atoms. */ struct RotorGroup { /** Constructor, with the two atoms around which the rotation * shall be made. The list of atoms to be rotated is initially empty. */ RotorGroup(const MolAtom &at1,const MolAtom &at2); /// The first atom defining the rotation axis const MolAtom * mpAtom1; /// The second atom defining the rotation axis const MolAtom * mpAtom2; /// The set of atoms that are to be rotated set mvRotatedAtomList; /** The recommended rotation amplitude, for a base global optimization * displacement, to obtain an average 0.1 Angstroem displacement * per atom (pi*0.04 by default) * * This is learnt at the beginning of an optimization, i.e. in * Molecule::BuildRotorGroup() */ REAL mBaseRotationAmplitude; }; /** List of RotorGroups corresponding to free torsion bonds. * * In this list are list of atoms on one side of a bond, that can be rotated * freely around this bond. Each bond is listed only once, with * the side which has the smallest number of atoms. */ mutable list mvRotorGroupTorsion; /** List of RotorGroups corresponding to free torsion bonds, but with only * one chain of atoms listed. * * The difference with Molecule::mRotorGroupTorsion is that if the bond is * A-B, with atom A linked with atoms A1,A2,A3, in this list only one chain * (starting either from A1, A2 or A3) will be rotated, instead of the 3 chains. * This is useful when searching for the absolute configuration of atoms. */ mutable list mvRotorGroupTorsionSingleChain; /** List of RotorGroups for internal rotations. This lists groups of atoms * that can be rotated \e between two given atoms. This is useful to alter * the conformation of large rings, where no free torsion bonds exists, and * also for long flexible chains. */ mutable list mvRotorGroupInternal; /** When 3(A1..1n) or more atoms are connected to a same atom A, it defines * a 'flip' group, where it is possible to rotate bonds to their symmetric * with respect to one plane defined by atoms Ai-A-Aj. This is useful to * flip the absolute configuration for asymmetric centers. Note that the bond * is only rotated, so that the entire group is not mirrored (no absolute configuration * is broken in the group). * * Also, a FlipGroup can correspond to a 180� rotation exchanging Ai and Aj * (rotating the two chains around the bissecting angle of bonds A-Ai and A-Aj) */ struct FlipGroup { /** Constructor, with the central atom. */ FlipGroup(const MolAtom &at0,const MolAtom &at1,const MolAtom &at2); /// The atom which is an asymmetric center const MolAtom * mpAtom0; /// The first atom defining the rotation axis const MolAtom * mpAtom1; /// The second atom defining the rotation axis const MolAtom * mpAtom2; /// The set of atoms that are to be rotated during the flip. The first /// atom is the one bonded to the central atom, whose bond will be flipped /// with respect to the plane defined by (at1,at0,at2). /// /// However, if this atom is identical to mpAtom0, then this indicates that /// a 180� rotation exchanging atom1 and atom2 is to be performed. list > > mvRotatedChainList; /// Number of times this flip has been tried, and the number of times /// it has been accepted. Used in Molecule::GlobalOptRandomMove, /// to avoid flips that break some restraint (and deciding which flips /// break some restraint is difficult before having a real conformation). mutable unsigned long mNbTest,mNbAccept; }; /// Flip a group of atom. See Molecule::FlipGroup. void FlipAtomGroup(const FlipGroup&, const bool keepCenter=true); /** The list of FlipGroups. * */ mutable list mvFlipGroup; // Group of atoms for random moves naturally respecting restraints /// List of StretchModeBondLength mutable list mvStretchModeBondLength; /// List of StretchModeBondLength mutable list mvStretchModeBondAngle; /// List of StretchModeBondLength mutable list mvStretchModeTorsion; /// List of StretchModeTwist mutable list mvStretchModeTwist; /// Groups of StretchMode not breaking any restraint (unless the one they are associated to) mutable std::list mvpStretchModeFree; /// Groups of StretchMode breaking restraints (beyond the one they are associated to) mutable std::list mvpStretchModeNotFree; /// Group of concurrent StretchModes (affecting common restraints) /// A given stretch mode can only belong to one group. struct StretchModeGroup { std::set mvpStretchMode; std::set mvpBrokenBond; std::set mvpBrokenBondAngle; std::set mvpBrokenDihedralAngle; }; /** Groups of atoms that should be moved according to molecular dynamics * principles. */ mutable list mvMDAtomGroup; /// Full list of atoms that can be moved using molecular dynamics /// This excludes any atom part of a rigid group mutable std::set mvMDFullAtomGroup; /// Frequency of using molecular dynamics move during GlobalOptRandomMove() REAL mMDMoveFreq; /// Relative energy of molecule during molecular dynamics move /// Default: 40, 10 (slow conformation change), 200 (large changes) REAL mMDMoveEnergy; /// The Molecule, as a lightweight ZMatrix, for export purposes. mutable std::vector mAsZMatrix; /// The current log(likelihood) mutable REAL mLogLikelihood; /** Scale (multiplier) for the log(likelihood) * * Changing this scale is equivalent to changing the sigma values of all bonds, * bond angles and dihedral angles - but it allows a simple global scaling for the * user. */ REAL mLogLikelihoodScale; /// Current LSQ Calc - one value for each restraint (bond distance, angle or dihedral angle) mutable CrystVector_REAL mLSQCalc; /// Current LSQ Calc - one value for each restraint (bond distance, angle or dihedral angle ideal values) mutable CrystVector_REAL mLSQObs; /// Current LSQ Calc - one value for each restraint(bond distance, angle or dihedral angle sigmas) mutable CrystVector_REAL mLSQWeight; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); #endif }; /** Build recursively a list of atoms, starting from a one atom, and given * a connectivity table. * * \param atom: the starting atom * \param connect: the connectivity table * \param atomlist: the list of atoms to which will be appended the atoms newly found. * \param finalAtom: if specified, the list buildin will stop after finding this atom. * This can be used to build the list of atoms between two given atoms. Otherwise, * the list is expanded until the end of the chain(s), or until an atom already * in the list is encountered (i.e. a ring has been found). */ void ExpandAtomGroupRecursive(MolAtom* atom, const map > &connect, set &atomlist,const MolAtom* finalAtom=0); /** Build recursively a list of atoms, starting from a one atom, and given * a connectivity table, until a certain depth (number of bonds) is reached. * * \param atom: the starting atom * \param connect: the connectivity table * \param atomlist: the list of atoms to which will be appended the atoms newly found. * \param finalAtom: if specified, the list buildin will stop after finding this atom. * This can be used to build the list of atoms between two given atoms. Otherwise, * the list is expanded until the end of the chain(s), or until an atom already * in the list is encountered (i.e. a ring has been found). */ void ExpandAtomGroupRecursive(MolAtom* atom, const map > &connect, map &atomlist,const unsigned long maxdepth, unsigned long depth=0); // Forward declaration class ZScatterer; /// Converter from ZScatterer to a Molecule object Molecule *ZScatterer2Molecule(ZScatterer *scatt); }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PDF.cpp000066400000000000000000000270161417150057700221670ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2007-2008 Vincent Favre-Nicolin vincefn@users.sourceforge.net 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* PDF.cpp - Pair Distribution calculations * */ #include "ObjCryst/ObjCryst/PDF.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxPDF.h" #endif #include namespace ObjCryst { const RefParType *gpRefParTypePDF=0; PDF::PDF(): mRadiationType(RAD_XRAY) { } PDF::PDF(const PDF &old): mRadiationType(old.mRadiationType), mPDFR(old.mPDFR),mPDFCalc(old.mPDFCalc),mPDFObs(old.mPDFObs), mvPDFPhase(old.mvPDFPhase) {} PDF::~PDF(){} const string& PDF::GetClassName() const { static const string className = "PDF"; return className; } void PDF::SetPDFObs(const CrystVector_REAL &r,const CrystVector_REAL &obs) { mPDFR=r; mPDFObs=obs, mPDFCalc.resize(r.numElements()); mPDFCalc=0; } RadiationType PDF::GetRadiationType()const{return mRadiationType;} void PDF::SetRadiationType(RadiationType type){mRadiationType=type;} REAL PDF::GetRMax()const { const unsigned long nb=mPDFR.numElements(); if(nb>0) return mPDFR(nb-1); return 0; } const CrystVector_REAL &PDF::GetPDFCalc()const { //:TODO: re-calculate only when needed ! mPDFCalc.resize(mPDFR.numElements()); mPDFCalc=0; CrystVector_REAL tmp; for(list >::const_iterator pos=mvPDFPhase.begin();pos!=mvPDFPhase.end();++pos) { tmp=pos->first->GetPDFCalc(); tmp*=pos->second; mPDFCalc+=tmp; } return mPDFCalc; } const CrystVector_REAL &PDF::GetPDFObs()const { return mPDFObs; } const CrystVector_REAL &PDF::GetPDFR()const { return mPDFR; } void PDF::AddPDFPhase(PDFPhase &phase) { mvPDFPhase.push_back(make_pair(&phase,1.0)); } #ifdef __WX__CRYST__ WXCrystObjBasic* PDF::WXCreate(wxWindow* parent) { if(mpWXCrystObj==0) mpWXCrystObj=new WXPDF(parent,this); return mpWXCrystObj; } #endif ////////////////////////// PDFPhase ///////////////////////////// PDFPhase::PDFPhase(const PDF &pdf): mpPDF(&pdf) { } const CrystVector_REAL &PDFPhase::GetPDFCalc()const { this->CalcPDF(); return mPDFCalc; } ////////////////////////// PDFCrystal ///////////////////////////// PDFCrystal::PDFCrystal(const PDF &pdf, const Crystal &cryst): PDFPhase(pdf),mpCrystal(&cryst),mDelta1(0.0),mDelta2(0.0),mQbroad(0.0),mQdamp(0.0) { } PDFCrystal::pdfAtom::pdfAtom(): fx0(0),fy0(0),fz0(0),x0(0),y0(0),z0(0),occupBi(1),hasChanged(true) {} void PDFCrystal::Init(const PDF &pdf, const Crystal &cryst) { mpCrystal=&cryst; mpPDF=&pdf; this->ResetParList(); { RefinablePar tmp("Delta1",&mDelta1,0,1.0,gpRefParTypePDF, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-3); this->AddPar(tmp); } { RefinablePar tmp("Delta2",&mDelta2,0,1.0,gpRefParTypePDF, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-3); this->AddPar(tmp); } { RefinablePar tmp("Qbroad",&mQbroad,0,1.0,gpRefParTypePDF, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-3); this->AddPar(tmp); } { RefinablePar tmp("Qdamp",&mQdamp,0,1.0,gpRefParTypePDF, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-3); this->AddPar(tmp); } } void PDFCrystal::CalcPDF()const { const unsigned long nbr=mpPDF->GetPDFR().numElements(); mPDFCalc.resize(nbr); if(mpCrystal==0) { mPDFCalc=0; return; } // Get current fractionnal coordinates from Crystal, check if any has changed const ScatteringComponentList *pScatt=&(mpCrystal->GetScatteringComponentList()); unsigned long nb=pScatt->GetNbComponent(); pScatt->Print(); // Calc and rho0 REAL rho0=0,b_av=0; // Note: We cannot use the dynamical occupancy as computed in a Crystal Object, //as we need the real occupancy for each *unique* poisition. // :TODO: So we need to compute a new dynamical occupancy that only corrects the overlap //between one unique atom and different atoms, excluding symetrics of the unique atom. if(nb!=mvPDFAtom.size()) { mvPDFAtom.resize(nb); unsigned int i=0; for(vector::iterator pos=mvPDFAtom.begin();pos!=mvPDFAtom.end();++pos) { pos->fx0=(*pScatt)(i).mX; pos->fy0=(*pScatt)(i).mY; pos->fz0=(*pScatt)(i).mZ; if((*pScatt)(i).mpScattPow==0) pos->occupBi=0; else { const REAL occ=(*pScatt)(i).mOccupancy; const REAL b=(*pScatt)(i).mpScattPow->GetForwardScatteringFactor(mpPDF->GetRadiationType()); rho0+=occ; b_av+=occ*b; pos->occupBi= occ*b; pos->pScattPow=(*pScatt)(i).mpScattPow; pos->hasChanged=true; } ++i; } } else { unsigned int i=0; for(vector::iterator pos=mvPDFAtom.begin();pos!=mvPDFAtom.end();++pos) { if(pos->fx0!=(*pScatt)(i).mX){pos->fx0=(*pScatt)(i).mX;pos->hasChanged=true;} if(pos->fy0!=(*pScatt)(i).mY){pos->fy0=(*pScatt)(i).mY;pos->hasChanged=true;} if(pos->fz0!=(*pScatt)(i).mZ){pos->fz0=(*pScatt)(i).mZ;pos->hasChanged=true;} if(pos->pScattPow!=(*pScatt)(i).mpScattPow){pos->pScattPow=(*pScatt)(i).mpScattPow;pos->hasChanged=true;} REAL occupBi; if((*pScatt)(i).mpScattPow==0) occupBi=0; else { const REAL occ=(*pScatt)(i).mOccupancy; const REAL b=(*pScatt)(i).mpScattPow->GetForwardScatteringFactor(mpPDF->GetRadiationType()); rho0+=occ; b_av+=occ*b; occupBi= occ*b; //:TODO: check if B-factor has changed } if(pos->occupBi!=occupBi){pos->occupBi=occupBi;pos->hasChanged=true;} } } // Determine number of translations needed //to get all interatomic distances up to Rmax // :TODO: faster by smarter limits on translations ? const int nx=int(ceil(mpPDF->GetRMax()/mpCrystal->GetLatticePar(0))+.001); const int ny=int(ceil(mpPDF->GetRMax()/mpCrystal->GetLatticePar(1))+.001); const int nz=int(ceil(mpPDF->GetRMax()/mpCrystal->GetLatticePar(2))+.001); const unsigned int nbSymmetrics=mpCrystal->GetSpaceGroup().GetNbSymmetrics(); const unsigned int neq=(2*nx+1)*(2*ny+1)*(2*nz+1)*nbSymmetrics; b_av/=rho0; cout<<"rho0="<GetVolume()<<"="<GetVolume()<GetVolume(); // Calc all equivalent positions & translations // TODO: Use knowledge of special positions, rather than use dynamical occupancy ? { const CrystMatrix_REAL *pOrth=&(mpCrystal->GetOrthMatrix()); const REAL m00=(*pOrth)(0,0); const REAL m01=(*pOrth)(0,1); const REAL m02=(*pOrth)(0,2); const REAL m11=(*pOrth)(1,1); const REAL m12=(*pOrth)(1,2); const REAL m22=(*pOrth)(2,2); cout<::iterator pos=mvPDFAtom.begin();pos!=mvPDFAtom.end();++pos) { if(pos->hasChanged) { symmetricsCoords=mpCrystal->GetSpaceGroup().GetAllSymmetrics(pos->fx0,pos->fy0,pos->fz0); pos->x.resize(neq); pos->y.resize(neq); pos->z.resize(neq); REAL *px=pos->x.data(); REAL *py=pos->y.data(); REAL *pz=pos->z.data(); for(unsigned int j=0;jFractionalToOrthonormalCoords(x,y,z); if(pos==mvPDFAtom.begin()) cout<x0=x;pos->y0=y;pos->z0=z;} for(int ix=-nx;ix<=nx;++ix) for(int iy=-ny;iy<=ny;++iy) for(int iz=-nz;iz<=nz;++iz) { //cout<GetRMax()+0.2)*(mpPDF->GetRMax()+0.2); const REAL nsigcut=5;// Cut gaussian at abs(r_ij-r)<3*sigma const REAL norm=1/sqrt(2*M_PI); for(vector::iterator pos=mvPDFAtom.begin();pos!=mvPDFAtom.end();++pos) { if(pos->occupBi==0) continue; const REAL x0=pos->x0; const REAL y0=pos->y0; const REAL z0=pos->z0; for(vector::iterator pos1=pos;pos1!=mvPDFAtom.end();++pos1) { if(pos1->occupBi==0) continue; REAL normij=norm*pos->occupBi*pos1->occupBi/(b_av*b_av)/nb; if(pos!=pos1)normij*=2;// i!j should be counted twice in the loop const REAL *px=pos1->x.data(); const REAL *py=pos1->y.data(); const REAL *pz=pos1->z.data(); const REAL sigma2=(pos->pScattPow->GetBiso()+pos1->pScattPow->GetBiso())/(8*M_PI*M_PI); for(unsigned long i=0;i1)) { const REAL rij=sqrt(d2); REAL s2=sigma2*(1-mDelta1/rij-mDelta2/d2+mQbroad*d2); if(s2<.01) s2=0.01; const REAL sig=sqrt(s2); REAL *p=mPDFCalc.data(); const REAL *pr=mpPDF->GetPDFR().data(); const REAL rmin=rij-nsigcut*sig,rmax=rij+nsigcut*sig; //cout<<" "<"<rmax) break; const REAL dr=rij-*pr; *p += n*exp(-dr*dr/(2*s2)); p++;pr++; } } } } } cout<GetPDFR(); CrystVector_REAL tmp; tmp=mpPDF->GetPDFR(); tmp*=4*M_PI*rho0; mPDFCalc-=tmp; } #ifdef __WX__CRYST__ WXCrystObjBasic* PDFCrystal::WXCreate(wxWindow* parent) { if(mpWXCrystObj==0) mpWXCrystObj=new WXPDFCrystal(parent,this); return mpWXCrystObj; } #endif }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PDF.h000066400000000000000000000113521417150057700216300ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2007-2008 Vincent Favre-Nicolin vincefn@users.sourceforge.net 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* PDF.h header file for Pair Distribution calculations * */ #ifndef _OBJCRYST_PDF_H_ #define _OBJCRYST_PDF_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/Crystal.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxCryst.h" #endif #include #include #include namespace ObjCryst { extern const RefParType *gpRefParTypePDF; // Forward declaration class PDFPhase; /** Main class for Pair distribution function calculations and comparison to observed one * */ class PDF:public RefinableObj { public: PDF(); /// Copy constructor PDF(const PDF &old); /// Crystal destructor ~PDF(); virtual const string& GetClassName() const; /// Experimental data void SetPDFObs(const CrystVector_REAL &r,const CrystVector_REAL &obs); /// GetRadiationType RadiationType GetRadiationType()const; /// SetRadiationType void SetRadiationType(RadiationType type); /// Cutoff r value REAL GetRMax()const; /// Get the calculated PDF const CrystVector_REAL &GetPDFCalc()const; /// Get the observed PDF const CrystVector_REAL &GetPDFObs()const; /// Get the r coordinates (in Angstroem) for the PDF const CrystVector_REAL &GetPDFR()const; /// Add PDF phase void AddPDFPhase(PDFPhase &phase); private: /// Radiation type RadiationType mRadiationType; /// r coordinates (in Angstroem) of the PDF CrystVector_REAL mPDFR; /// The PDF itself,calculated mutable CrystVector_REAL mPDFCalc; /// The PDF itself,observed CrystVector_REAL mPDFObs; /// Contributions to the PDF, with their scale factor std::list > mvPDFPhase; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); #endif }; /// Global registry for all PDF objects extern ObjRegistry gPDFRegistry; /** Contribution to a PDF * * Right now this can only be a PDFCrystal. */ class PDFPhase:public RefinableObj { public: /// Constructor PDFPhase(const PDF &pdf); /// Get the calculated PDF const CrystVector_REAL &GetPDFCalc()const; protected: /// Calculate the pdf virtual void CalcPDF()const=0; /// Parent PDF const PDF *mpPDF; /// The calculated PDF mutable CrystVector_REAL mPDFCalc; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*)=0; #endif }; /** Class for Pair Distribution Function calculations for a single Crystal object * */ class PDFCrystal:public PDFPhase { public: /// Constructor PDFCrystal(const PDF &pdf, const Crystal &cryst); private: /// Initialize all parameters void Init(const PDF &pdf, const Crystal &cryst); /// Calculate the pdf virtual void CalcPDF()const; /// The Crystal const Crystal *mpCrystal; // Parameters to describe the PDF /// Parameters affecting the width & intensity of peaks REAL mDelta1,mDelta2,mQbroad,mQdamp; // Cached data to speed up computations /// Container of temp data for each atom struct pdfAtom { /// default constructor pdfAtom(); /// Fractionnal & cartesian unique coordinates REAL fx0,fy0,fz0,x0,y0,z0; /// The scattering power const ScatteringPower *pScattPow; /// Scattering amplitudes, multiplied by occupancy REAL occupBi; /// Has this atom changed since last time ? bool hasChanged; /// List of all equivalent & translated positions, /// in cartesian coordinates CrystVector_REAL x,y,z; }; /// List of all temp data mutable std::vector mvPDFAtom; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); #endif }; }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Polyhedron.cpp000066400000000000000000000452351417150057700237040ustar00rootroot00000000000000#include "ObjCryst/ObjCryst/Polyhedron.h" namespace ObjCryst { Molecule* MakeTetrahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist) { Molecule *mol=new Molecule(cryst,name); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom(0.,0.,dist,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(0.,dist*0.943,-dist*0.333,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(dist*0.817,-dist*0.472,-dist*0.333,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(-dist*0.817,-dist*0.472,-dist*0.333,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),dist,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),109.5*DEG2RAD,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(3),109.5*DEG2RAD,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(4),109.5*DEG2RAD,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),109.5*DEG2RAD,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(4),109.5*DEG2RAD,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(4),109.5*DEG2RAD,0.01,0.05); return mol; } Molecule* MakeOctahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist) { Molecule *mol=new Molecule(cryst,name); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom(0.,0.,dist,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(dist,0.,0.,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(0.,dist,0.,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(-dist,0.,0.,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddAtom(0.,-dist,0.,peripheralAtom,peripheralAtom->GetName()+"5"); mol->AddAtom(0.,0.,-dist,peripheralAtom,peripheralAtom->GetName()+"6"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(5),dist,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(6),dist,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(3),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(4),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(5),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(2),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(3),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(4),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(5),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(4),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(5),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(5),mol->GetAtom(0),mol->GetAtom(2),M_PI/2.,0.01,0.05); return mol; } Molecule* MakeSquarePlane(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { Molecule *mol=new Molecule(cryst,name); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom( d,0.,0.,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(0., d,0.,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(-d,0.,0.,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(0.,-d,0.,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),d,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(4),M_PI/2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(1),M_PI/2.,0.01,0.05); return mol; } Molecule* MakeCube(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { Molecule *mol=new Molecule(cryst,name); const REAL d0=d/sqrt(3.); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom( d0,-d0, d0,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom( d0, d0, d0,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(-d0, d0, d0,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(-d0,-d0, d0,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddAtom( d0,-d0,-d0,peripheralAtom,peripheralAtom->GetName()+"5"); mol->AddAtom( d0, d0,-d0,peripheralAtom,peripheralAtom->GetName()+"6"); mol->AddAtom(-d0, d0,-d0,peripheralAtom,peripheralAtom->GetName()+"7"); mol->AddAtom(-d0,-d0,-d0,peripheralAtom,peripheralAtom->GetName()+"8"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(5),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(6),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(7),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(8),d,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(2),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(3),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(4),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(1),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(6),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(6),mol->GetAtom(7),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(8),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(5),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(5),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(6),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(7),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(8),2*d0,0.01,0.05); #if 0 const REAL a=2*atan(1/sqrt(2.)); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(4),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(1),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(5),mol->GetAtom(0),mol->GetAtom(6),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(7),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(7),mol->GetAtom(0),mol->GetAtom(8),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(8),mol->GetAtom(0),mol->GetAtom(1),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(5),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(6),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(7),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(8),a,0.01,0.05); #endif return mol; } Molecule* MakeAntiPrismTetragonal(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { Molecule *mol=new Molecule(cryst,name); const REAL d0=d/sqrt(3.); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom( d0,-d0, d0,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom( d0, d0, d0,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(-d0, d0, d0,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(-d0,-d0, d0,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddAtom( d0*sqrt(2.),0.,-d0,peripheralAtom,peripheralAtom->GetName()+"5"); mol->AddAtom(0., d0*sqrt(2.),-d0,peripheralAtom,peripheralAtom->GetName()+"6"); mol->AddAtom(-d0*sqrt(2.),0.,-d0,peripheralAtom,peripheralAtom->GetName()+"7"); mol->AddAtom(0.,-d0*sqrt(2.),-d0,peripheralAtom,peripheralAtom->GetName()+"8"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(5),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(6),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(7),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(8),d,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(2),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(3),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(4),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(1),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(6),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(6),mol->GetAtom(7),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(8),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(5),2*d0,0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(1),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(2),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(6),mol->GetAtom(2),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(6),mol->GetAtom(3),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(3),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(4),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(4),d0*sqrt(5.),0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(1),d0*sqrt(5.),0.01,0.05); #if 0 const REAL a=2*atan(1/sqrt(2.)); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(4),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(1),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(5),mol->GetAtom(0),mol->GetAtom(6),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(6),mol->GetAtom(0),mol->GetAtom(7),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(7),mol->GetAtom(0),mol->GetAtom(8),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(8),mol->GetAtom(0),mol->GetAtom(1),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(5),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(6),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(3),mol->GetAtom(0),mol->GetAtom(7),a,0.01,0.05); mol->AddBondAngle(mol->GetAtom(4),mol->GetAtom(0),mol->GetAtom(8),a,0.01,0.05); #endif return mol; } Molecule* MakePrismTrigonal(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { const REAL a=sqrt(3./7.)*d; const REAL a1=a*2./sqrt(3.); Molecule *mol=new Molecule(cryst,name); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom( a1 ,0. , a,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(-a1/2., a1*sqrt(3.)/2., a,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(-a1/2.,-a1*sqrt(3.)/2., a,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom( a1 ,0. ,-a,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddAtom(-a1/2., a1*sqrt(3.)/2.,-a,peripheralAtom,peripheralAtom->GetName()+"5"); mol->AddAtom(-a1/2.,-a1*sqrt(3.)/2.,-a,peripheralAtom,peripheralAtom->GetName()+"6"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(5),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(6),d,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(2),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(3),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(3),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(4),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(6),2*a,0.01,0.05); return mol; } Molecule* MakeIcosahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { Molecule *mol=new Molecule(cryst,name); const REAL g0=(1.+sqrt(5.))/2.; const REAL a=d/sqrt(1.+g0*g0); const REAL g=g0*a; mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom(0., g, a,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(0., g,-a,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(0.,-g, a,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddAtom(0.,-g,-a,peripheralAtom,peripheralAtom->GetName()+"4"); mol->AddAtom( a,0., g,peripheralAtom,peripheralAtom->GetName()+"5"); mol->AddAtom(-a,0., g,peripheralAtom,peripheralAtom->GetName()+"6"); mol->AddAtom( a,0.,-g,peripheralAtom,peripheralAtom->GetName()+"7"); mol->AddAtom(-a,0.,-g,peripheralAtom,peripheralAtom->GetName()+"8"); mol->AddAtom( g, a,0.,peripheralAtom,peripheralAtom->GetName()+"9"); mol->AddAtom( g,-a,0.,peripheralAtom,peripheralAtom->GetName()+"10"); mol->AddAtom(-g, a,0.,peripheralAtom,peripheralAtom->GetName()+"11"); mol->AddAtom(-g,-a,0.,peripheralAtom,peripheralAtom->GetName()+"12"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(4),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(5),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(6),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(7),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(8),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(9),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(10),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(11),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(12),d,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(2),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(11),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(1),mol->GetAtom(9),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(2),mol->GetAtom(11),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(11),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(6),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(5),mol->GetAtom(9),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(9),mol->GetAtom(2),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(3),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(12),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(8),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(7),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(4),mol->GetAtom(10),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(12),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(12),mol->GetAtom(8),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(7),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(10),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(10),mol->GetAtom(3),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(12),mol->GetAtom(6),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(12),mol->GetAtom(11),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(11),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(8),mol->GetAtom(2),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(2),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(7),mol->GetAtom(9),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(10),mol->GetAtom(9),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(10),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(5),2*a,0.01,0.05); mol->AddBond(mol->GetAtom(3),mol->GetAtom(6),2*a,0.01,0.05); return mol; } Molecule* MakeTriangle(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL d) { Molecule *mol=new Molecule(cryst,name); mol->AddAtom(0.,0.,0.,centralAtom,centralAtom->GetName()); mol->AddAtom(d,0.,0.,peripheralAtom,peripheralAtom->GetName()+"1"); mol->AddAtom(-d/2., d*sqrt(3.)/2,0.,peripheralAtom,peripheralAtom->GetName()+"2"); mol->AddAtom(-d/2.,-d*sqrt(3.)/2,0.,peripheralAtom,peripheralAtom->GetName()+"3"); mol->AddBond(mol->GetAtom(0),mol->GetAtom(1),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(2),d,0.01,0.05); mol->AddBond(mol->GetAtom(0),mol->GetAtom(3),d,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(2),M_PI/3.*2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(1),mol->GetAtom(0),mol->GetAtom(3),M_PI/3.*2.,0.01,0.05); mol->AddBondAngle(mol->GetAtom(2),mol->GetAtom(0),mol->GetAtom(3),M_PI/3.*2.,0.01,0.05); return mol; } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Polyhedron.h000066400000000000000000000054111417150057700233410ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Polyhedron.h * header file for the Polyhdron creation * */ #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Molecule.h" namespace ObjCryst { Molecule* MakeTetrahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeOctahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeSquarePlane(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeCube(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeAntiPrismTetragonal(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakePrismTrigonal(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeIcosahedron(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); Molecule* MakeTriangle(Crystal &cryst,const string &name, const ScatteringPower *centralAtom, const ScatteringPower *peripheralAtom, const REAL dist); }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PowderPattern.cpp000066400000000000000000010303071417150057700243520ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for LibCryst++ PowderPattern class * */ #include #include #include //for sprintf() #include #include "cctbx/sgtbx/space_group.h" // For fullprof export #include "ObjCryst/ObjCryst/PowderPattern.h" #include "ObjCryst/ObjCryst/Molecule.h" // For fullprof export #include "ObjCryst/ObjCryst/PowderPatternBackgroundBayesianMinimiser.h" #include "ObjCryst/RefinableObj/Simplex.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/ObjCryst/CIF.h" #include "ObjCryst/Quirks/Chronometer.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxPowderPattern.h" #endif #include #include #include #ifdef _MSC_VER // MS VC++ predefined macros.... #undef min #undef max #endif //#define USE_BACKGROUND_MAXLIKE_ERROR #define POSSIBLY_UNUSED(expr) (void)(expr) namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // Cylinder absorption correction // //////////////////////////////////////////////////////////////////////// CylinderAbsCorr::CylinderAbsCorr(const PowderPatternDiffraction & data): ScatteringCorr(data), mpPowderPatternDiff(&data) {} CylinderAbsCorr::~CylinderAbsCorr() {} const string & CylinderAbsCorr::GetName() const { //So far, we do not need a personalized name... const static string mName="CylinderAbsCorr"; return mName; } const string & CylinderAbsCorr::GetClassName() const { const static string className="CylinderAbsCorr"; return className; } void CylinderAbsCorr::CalcCorr() const { mpData->GetTheta(); // Make sure theta is up-to-date if((mpPowderPatternDiff->GetParentPowderPattern().GetClockPowderPatternAbsCorr() < mClockCorrCalc) && (mpData->GetClockTheta()GetNbRefl()); const REAL muR = mpPowderPatternDiff->GetParentPowderPattern().GetMuR(); if(muR == 0) { mCorr = 1; return; } for(long i=0;iGetNbRefl();i++) { const REAL s2 = pow(sin(mpData->GetTheta()(i)),2); if(muR<=3) { const REAL t0 = 16.0/(3.*M_PI); const REAL t1 = (25.99978-0.01911*pow(s2,0.25))*exp(-0.024551*s2)+ 0.109561*sqrt(s2)-26.04556; const REAL t2 = -0.02489-0.39499*s2+1.219077*pow(s2,1.5)- 1.31268*pow(s2,2)+0.871081*pow(s2,2.5)-0.2327*pow(s2,3); const REAL t3 = 0.003045+0.018167*s2-0.03305*pow(s2,2); const REAL t = -t0*muR-t1*pow(muR,2)-t2*pow(muR,3)-t3*pow(muR,4); mCorr(i) = exp(t); } else { const REAL t1 = 1.433902+11.07504*s2-8.77629*s2*s2+ 10.02088*s2*s2*s2-3.36778*s2*s2*s2*s2; const REAL t2 = (0.013869-0.01249*s2)*exp(3.27094*s2)+ (0.337894+13.77317*s2)/pow(1.0+11.53544*s2, 1.555039); const REAL t3 = 1.933433/pow(1.0+23.12967*s2, 1.686715) -0.13576*sqrt(s2)+1.163198; const REAL t4 = 0.044365-0.04259/pow(1.0+0.41051*s2, 148.4202); const REAL t = (t1-t4)/pow(1+t2*(muR-3),t3)+t4; mCorr(i) = t/100; } } mClockCorrCalc.Click(); } //////////////////////////////////////////////////////////////////////// // // PowderPatternComponent // //////////////////////////////////////////////////////////////////////// ObjRegistry gPowderPatternComponentRegistry("List of all PowderPattern Components"); PowderPatternComponent::PowderPatternComponent(): mIsScalable(false),mpParentPowderPattern(0) { gPowderPatternComponentRegistry.Register(*this); mClockMaster.AddChild(mClockBraggLimits); } PowderPatternComponent::PowderPatternComponent(const PowderPatternComponent &old): mIsScalable(old.mIsScalable), mpParentPowderPattern(old.mpParentPowderPattern) { mClockMaster.AddChild(mClockBraggLimits); if(mpParentPowderPattern!=0) { mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternPar()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternXCorr()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternRadiation()); } } PowderPatternComponent::~PowderPatternComponent() { gPowderPatternComponentRegistry.DeRegister(*this); } const string& PowderPatternComponent::GetClassName() const { const static string className="PowderPatternComponent"; return className; } const PowderPattern& PowderPatternComponent::GetParentPowderPattern()const { return *mpParentPowderPattern; } std::map& PowderPatternComponent::GetPowderPattern_FullDeriv(std::set &vPar) { this->CalcPowderPattern_FullDeriv(vPar); return mPowderPattern_FullDeriv; } std::map& PowderPatternComponent::GetPowderPatternIntegrated_FullDeriv(std::set &vPar) { this->CalcPowderPatternIntegrated_FullDeriv(vPar); return mPowderPatternIntegrated_FullDeriv; } PowderPattern& PowderPatternComponent::GetParentPowderPattern() { return *mpParentPowderPattern; } bool PowderPatternComponent::IsScalable()const {return mIsScalable;} const RefinableObjClock& PowderPatternComponent::GetClockPowderPatternCalc()const { return mClockPowderPatternCalc; } const RefinableObjClock& PowderPatternComponent::GetClockBraggLimits()const { return mClockBraggLimits; } const list >& PowderPatternComponent::GetPatternLabelList()const { return mvLabel; } void PowderPatternComponent::CalcPowderPattern_FullDeriv(std::set &vPar) { TAU_PROFILE("PowderPatternComponent::CalcPowderPattern_FullDeriv()","void ()",TAU_DEFAULT); mPowderPattern_FullDeriv.clear(); for(std::set::iterator par=vPar.begin();par!=vPar.end();par++) { if(*par==0) { mPowderPattern_FullDeriv[*par]=this->GetPowderPatternCalc(); continue; } const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); mPowderPattern_FullDeriv[*par] =this->GetPowderPatternCalc(); (*par)->Mutate(-2*step); mPowderPattern_FullDeriv[*par]-=this->GetPowderPatternCalc(); (*par)->Mutate(step); mPowderPattern_FullDeriv[*par]/= step*2; if(MaxAbs(mPowderPattern_FullDeriv[*par])==0) mPowderPattern_FullDeriv[*par].resize(0); } } void PowderPatternComponent::CalcPowderPatternIntegrated_FullDeriv(std::set &vPar) { TAU_PROFILE("PowderPatternComponent::CalcPowderPatternIntegrated_FullDeriv()","void ()",TAU_DEFAULT); mPowderPatternIntegrated_FullDeriv.clear(); for(std::set::iterator par=vPar.begin();par!=vPar.end();par++) { if(*par==0) { mPowderPatternIntegrated_FullDeriv[*par]=*(this->GetPowderPatternIntegratedCalc().first); continue; } const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); mPowderPatternIntegrated_FullDeriv[*par] =*(this->GetPowderPatternIntegratedCalc().first); (*par)->Mutate(-2*step); mPowderPatternIntegrated_FullDeriv[*par]-=*(this->GetPowderPatternIntegratedCalc().first); (*par)->Mutate(step); mPowderPatternIntegrated_FullDeriv[*par]/= step*2; if(MaxAbs(mPowderPatternIntegrated_FullDeriv[*par])==0) mPowderPatternIntegrated_FullDeriv[*par].resize(0); } } //////////////////////////////////////////////////////////////////////// // // PowderPatternBackground // //////////////////////////////////////////////////////////////////////// PowderPatternBackground::PowderPatternBackground(): mBackgroundNbPoint(0), mMaxSinThetaOvLambda(10),mModelVariance(0) { mClockMaster.AddChild(mClockBackgroundPoint); this->InitOptions(); } PowderPatternBackground::PowderPatternBackground(const PowderPatternBackground &old): mBackgroundNbPoint(old.mBackgroundNbPoint), mBackgroundInterpPointX(old.mBackgroundInterpPointX), mBackgroundInterpPointIntensity(old.mBackgroundInterpPointIntensity), mMaxSinThetaOvLambda(10),mModelVariance(0) { mClockMaster.AddChild(mClockBackgroundPoint); this->InitOptions(); mInterpolationModel.SetChoice(old.mInterpolationModel.GetChoice()); } PowderPatternBackground::~PowderPatternBackground(){} const string& PowderPatternBackground::GetClassName() const { const static string className="PowderPatternBackground"; return className; } void PowderPatternBackground::SetParentPowderPattern(PowderPattern &s) { if(mpParentPowderPattern!=0) mClockMaster.RemoveChild(mpParentPowderPattern->GetIntegratedProfileLimitsClock()); mpParentPowderPattern = &s; mClockMaster.AddChild(mpParentPowderPattern->GetIntegratedProfileLimitsClock()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternPar()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternXCorr()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternRadiation()); } const CrystVector_REAL& PowderPatternBackground::GetPowderPatternCalc()const { this->CalcPowderPattern(); return mPowderPatternCalc; } pair PowderPatternBackground::GetPowderPatternIntegratedCalc()const { VFN_DEBUG_MESSAGE("PowderPatternBackground::GetPowderPatternIntegratedCalc()",3) this->CalcPowderPatternIntegrated(); return make_pair(&mPowderPatternIntegratedCalc,&mClockPowderPatternIntegratedCalc); } void PowderPatternBackground::ImportUserBackground(const string &filename) { VFN_DEBUG_MESSAGE("PowderPatternBackground::ImportUserBackground():"<> bckgd2Theta(nbPoints); fin >> bckgd(nbPoints); if(!fin) break; VFN_DEBUG_MESSAGE("Background=" << bckgd(nbPoints)\ <<" at 2theta="<GetParentPowderPattern().GetRadiation().GetWavelengthType()==WAVELENGTH_MONOCHROMATIC) ||(this->GetParentPowderPattern().GetRadiation().GetWavelengthType()==WAVELENGTH_ALPHA12)) bckgd2Theta*= DEG2RAD; } else bckgd2Theta*= DEG2RAD; this->SetInterpPoints(bckgd2Theta,bckgd); this->InitRefParList(); mClockBackgroundPoint.Click(); { char buf [200]; sprintf(buf,"Imported %d background points",(int)nbPoints); (*fpObjCrystInformUser)((string)buf); } this->UpdateDisplay(); VFN_DEBUG_MESSAGE("PowderPatternBackground::ImportUserBackground():finished",5) } void PowderPatternBackground::SetInterpPoints(const CrystVector_REAL tth, const CrystVector_REAL backgd) { VFN_DEBUG_ENTRY("PowderPatternBackground::SetInterpPoints():",5) if( (tth.numElements()!=backgd.numElements()) ||(tth.numElements()<2)) { throw ObjCrystException("PowderPatternBackground::SetInterpPoints() : \ number of points differ or less than 2 points !"); } mBackgroundNbPoint=tth.numElements(); mBackgroundInterpPointX.resize(mBackgroundNbPoint); mBackgroundInterpPointIntensity.resize(mBackgroundNbPoint); // Sort in ascending order, disregarding radiation type. CrystVector subs; subs=SortSubs(tth); for(long i=0;iInitRefParList(); mClockBackgroundPoint.Click(); VFN_DEBUG_EXIT("PowderPatternBackground::SetInterpPoints()",5) } const pair PowderPatternBackground::GetInterpPoints()const { return make_pair(&mBackgroundInterpPointX,&mBackgroundInterpPointIntensity); } void PowderPatternBackground::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { // One group for all background points unsigned int index=0; VFN_DEBUG_MESSAGE("PowderPatternBackground::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { if(index==0) index=first++; groupIndex(i)=index; } } void PowderPatternBackground::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); } const CrystVector_REAL& PowderPatternBackground::GetPowderPatternCalcVariance()const { this->CalcPowderPattern(); return mPowderPatternCalcVariance; } pair PowderPatternBackground::GetPowderPatternIntegratedCalcVariance()const { this->CalcPowderPatternIntegrated(); return make_pair(&mPowderPatternIntegratedCalcVariance, &mClockPowderPatternIntegratedVarianceCalc); } bool PowderPatternBackground::HasPowderPatternCalcVariance()const { #ifdef USE_BACKGROUND_MAXLIKE_ERROR return true; #else return false; #endif } void PowderPatternBackground::TagNewBestConfig()const { } void PowderPatternBackground::OptimizeBayesianBackground() { VFN_DEBUG_ENTRY("PowderPatternBackground::OptimizeBayesianBackground()",5); TAU_PROFILE("PowderPatternBackground::OptimizeBayesianBackground()","void ()",TAU_DEFAULT); PowderPatternBackgroundBayesianMinimiser min(*this); SimplexObj simplex("Simplex Test"); simplex.AddRefinableObj(min); long nbcycle; REAL llk=simplex.GetLogLikelihood(); long ct=0; cout<<"Initial Chi^2(BayesianBackground)="<SetGlobalOptimStep(gpRefParTypeScattDataBackground, mBackgroundInterpPointIntensity.max()/1000.0); { char buf [200]; sprintf(buf,"Optimizing Background, Cycle %d, Chi^2(Background)=%f", (int)ct,(float)llk); (*fpObjCrystInformUser)((string)buf); } nbcycle=500*mBackgroundNbPoint; simplex.Optimize(nbcycle,false); llk=simplex.GetLogLikelihood(); cout<GetParentPowderPattern().UpdateDisplay(); VFN_DEBUG_EXIT("PowderPatternBackground::OptimizeBayesianBackground()",5); } void PowderPatternBackground::FixParametersBeyondMaxresolution(RefinableObj &obj) { //Auto-fix points beyond used range unsigned long nbpoint=this->GetParentPowderPattern().GetNbPointUsed(); for(long j=0;jGetParentPowderPattern().X2Pixel(mBackgroundInterpPointX(j))>nbpoint) { // obj.GetPar(&mBackgroundInterpPointIntensity(j)).Print(); obj.GetPar(&mBackgroundInterpPointIntensity(j)).SetIsFixed(true); } } void PowderPatternBackground::CalcPowderPattern() const { if(mClockPowderPatternCalc>mClockMaster) return; //:TODO: This needs serious optimization ! if( (mClockPowderPatternCalc>mClockBackgroundPoint) &&(mClockPowderPatternCalc>mpParentPowderPattern->GetClockPowderPatternPar()) &&(mClockPowderPatternCalc>mInterpolationModel.GetClock())) return; TAU_PROFILE("PowderPatternBackground::CalcPowderPattern()","void ()",TAU_DEFAULT); VFN_DEBUG_MESSAGE("PowderPatternBackground::CalcPowderPattern()",3); const unsigned long nb=mpParentPowderPattern->GetNbPoint(); mPowderPatternCalc.resize(nb); if(nb!=0) switch(mInterpolationModel.GetChoice()) { case POWDER_BACKGROUND_LINEAR: { VFN_DEBUG_MESSAGE("PowderPatternBackground::CalcPowderPattern()..Linear",2) REAL p1,p2; REAL b1,b2; if(mBackgroundNbPoint==0) { mPowderPatternCalc=0; break; } VFN_DEBUG_MESSAGE("PowderPatternBackground::CalcPowderPattern()"<InitSpline(); REAL *b=mPowderPatternCalc.data(); p1=this->GetParentPowderPattern().X2Pixel(mBackgroundInterpPointX(mPointOrder(0))); p2=this->GetParentPowderPattern().X2Pixel(mBackgroundInterpPointX(mPointOrder(1))); b1=mBackgroundInterpPointIntensity(mPointOrder(0)); b2=mBackgroundInterpPointIntensity(mPointOrder(1)); long point=1; for(unsigned long i=0;i= p2) { if(point < mBackgroundNbPoint-1) { b1=b2; p1=p2; b2=mBackgroundInterpPointIntensity(mPointOrder(point+1)); p2=this->GetParentPowderPattern().X2Pixel(mBackgroundInterpPointX(mPointOrder(point+1))); point++ ; } } *b = (b1*(p2-i)+b2*(i-p1))/(p2-p1) ; b++; } break; } case POWDER_BACKGROUND_CUBIC_SPLINE: { if(mBackgroundNbPoint==0) mPowderPatternCalc=0; else { this->InitSpline(); mPowderPatternCalc=mvSpline((REAL)0,(REAL)1,nb); } break; } } VFN_DEBUG_MESSAGE("PowderPatternBackground::CalcPowderPattern()",3); #ifdef USE_BACKGROUND_MAXLIKE_ERROR { mPowderPatternCalcVariance.resize(nb); const REAL step=mModelVariance*mModelVariance/(REAL)nbPoint; REAL var=0; REAL *p=mPowderPatternCalcVariance.data(); for(long i=0;i &vPar) { TAU_PROFILE("PowderPatternBackground::CalcPowderPattern_FullDeriv()","void ()",TAU_DEFAULT); const unsigned long nb=mpParentPowderPattern->GetNbPoint(); mPowderPattern_FullDeriv.clear(); if((nb==0)||(mBackgroundNbPoint==0)) return; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if((*par)==0) mPowderPattern_FullDeriv[*par]=this->GetPowderPatternCalc(); else for(int j = 0; j < mBackgroundNbPoint; j++) { if((*par)->GetPointer()!=mBackgroundInterpPointIntensity.data()+j) continue; const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); mPowderPattern_FullDeriv[*par] =this->GetPowderPatternCalc(); (*par)->Mutate(-2*step); mPowderPattern_FullDeriv[*par]-=this->GetPowderPatternCalc(); (*par)->Mutate(step); mPowderPattern_FullDeriv[*par]/= step*2; if(MaxAbs(mPowderPattern_FullDeriv[*par])==0) mPowderPattern_FullDeriv[*par].resize(0); } } } void PowderPatternBackground::CalcPowderPatternIntegrated() const { if(mClockPowderPatternCalc>mClockMaster) return; this->CalcPowderPattern();// :TODO: Optimize if( (mClockPowderPatternIntegratedCalc>mClockPowderPatternCalc) &&(mClockPowderPatternIntegratedCalc>mpParentPowderPattern->GetIntegratedProfileLimitsClock())) return; VFN_DEBUG_ENTRY("PowderPatternBackground::CalcPowderPatternIntegrated()",3) TAU_PROFILE("PowderPatternBackground::CalcPowderPatternIntegrated()","void ()",TAU_DEFAULT); const CrystVector_long *pMin=&(mpParentPowderPattern->GetIntegratedProfileMin()); const CrystVector_long *pMax=&(mpParentPowderPattern->GetIntegratedProfileMax()); const long numInterval=pMin->numElements(); mPowderPatternIntegratedCalc.resize(numInterval); REAL * RESTRICT p2=mPowderPatternIntegratedCalc.data(); for(int j=0;j &vPar) { TAU_PROFILE("PowderPatternBackground::CalcPowderPatternIntegrated_FullDeriv()","void ()",TAU_DEFAULT); //cout<<"PowderPatternBackground::CalcPowderPatternIntegrated_FullDeriv"<GetNbPoint(); mPowderPatternIntegrated_FullDeriv.clear(); if((nb==0)||(mBackgroundNbPoint==0)) return; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if((*par)==0) mPowderPattern_FullDeriv[*par]=this->GetPowderPatternCalc(); else for(int j = 0; j < mBackgroundNbPoint; j++) { if((*par)->GetPointer()!=mBackgroundInterpPointIntensity.data()+j) continue; const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); mPowderPatternIntegrated_FullDeriv[*par] =*(this->GetPowderPatternIntegratedCalc().first); (*par)->Mutate(-2*step); mPowderPatternIntegrated_FullDeriv[*par]-=*(this->GetPowderPatternIntegratedCalc().first); (*par)->Mutate(step); mPowderPatternIntegrated_FullDeriv[*par]/= step*2; if(MaxAbs(mPowderPatternIntegrated_FullDeriv[*par])==0) mPowderPatternIntegrated_FullDeriv[*par].resize(0); } } #if 0 std::map newDeriv=mPowderPatternIntegrated_FullDeriv; this->PowderPatternComponent::CalcPowderPatternIntegrated_FullDeriv(vPar); std::vector v; int n=0; for(std::map::reverse_iterator pos=mPowderPatternIntegrated_FullDeriv.rbegin();pos!=mPowderPatternIntegrated_FullDeriv.rend();++pos) { cout<first->GetName()<<":"<second.size()<<","<first].size()<second.size()==0) continue; v.push_back(&(pos->second)); v.push_back(&(newDeriv[pos->first])); if(++n>8) break; } if(v.size()>0) cout<<"PowderPatternBackground::CalcPowderPatternIntegrated_FullDeriv():"<(v,12,1,20)<ResetParList(); REAL *p=mBackgroundInterpPointIntensity.data(); char buf [10]; string str="Background_Point_"; //for(int i=0;i<3;i++) for(int i=0;iAddPar(tmp); } #ifdef USE_BACKGROUND_MAXLIKE_ERROR { RefinablePar tmp("ML Model Error",&mModelVariance, 0.,100000.,gpRefParTypeObjCryst,REFPAR_DERIV_STEP_RELATIVE, true,true,true,false,1.); tmp.AssignClock(mClockBackgroundPoint); tmp.SetDerivStep(1e-3); //tmp.SetGlobalOptimStep(10.); tmp.SetGlobalOptimStep(sqrt(mBackgroundInterpPointIntensity.sum() /mBackgroundInterpPointIntensity.numElements())); this->AddPar(tmp); } #endif } void PowderPatternBackground::InitOptions() { VFN_DEBUG_MESSAGE("PowderPatternBackground::InitOptions()",5) static string InterpolationModelName; static string InterpolationModelChoices[2]; static bool needInitNames=true; if(true==needInitNames) { InterpolationModelName="Interpolation Model"; InterpolationModelChoices[0]="Linear"; InterpolationModelChoices[1]="Spline"; //InterpolationModelChoices[2]="Chebyshev"; needInitNames=false;//Only once for the class } mInterpolationModel.Init(2,&InterpolationModelName,InterpolationModelChoices); this->AddOption(&mInterpolationModel); mClockMaster.AddChild(mInterpolationModel.GetClock()); mInterpolationModel.SetChoice(1); } void PowderPatternBackground::InitSpline()const { if( (mClockSpline>mClockBackgroundPoint) &&(mClockSpline>mpParentPowderPattern->GetClockPowderPatternPar()) &&(mClockSpline>this->GetParentPowderPattern().GetRadiation().GetClockWavelength())) return; mvSplinePixel.resize(mBackgroundNbPoint); // The points must be in ascending order // Take care later of neutron TOF, as the powder apttern data may not have been initialized yet. CrystVector subs; subs=SortSubs(mBackgroundInterpPointX); if(this->GetParentPowderPattern().GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { mPointOrder.resize(mBackgroundNbPoint); for(long i=0;iGetParentPowderPattern().X2Pixel(mBackgroundInterpPointX(mPointOrder(i))); ipixel(i)=mBackgroundInterpPointIntensity(mPointOrder(i)); } mvSpline.Init(mvSplinePixel,ipixel); mClockSpline.Click(); } #ifdef __WX__CRYST__ WXCrystObjBasic* PowderPatternBackground::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXPowderPatternBackground(parent,this); return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // PowderPatternDiffraction // //////////////////////////////////////////////////////////////////////// PowderPatternDiffraction::PowderPatternDiffraction(): mpReflectionProfile(0), mCorrLorentz(*this),mCorrPolar(*this),mCorrSlitAperture(*this), mCorrTextureMarchDollase(*this),mCorrTextureEllipsoid(*this),mCorrTOF(*this),mCorrCylAbs(*this),mExtractionMode(false), mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(false),mFrozenBMatrix(3,3) { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::PowderPatternDiffraction()",10) mIsScalable=true; this->InitOptions(); this->SetProfile(new ReflectionProfilePseudoVoigt); this->SetIsIgnoringImagScattFact(true); this->AddSubRefObj(mCorrTextureMarchDollase); this->AddSubRefObj(mCorrTextureEllipsoid); mClockMaster.AddChild(mClockProfilePar); mClockMaster.AddChild(mClockLorentzPolarSlitCorrPar); mClockMaster.AddChild(mpReflectionProfile->GetClockMaster()); for(unsigned int i=0;i<3;++i) mFrozenLatticePar(i)=5; for(unsigned int i=3;i<6;++i) mFrozenLatticePar(i)=M_PI/2; } PowderPatternDiffraction::PowderPatternDiffraction(const PowderPatternDiffraction &old): mpReflectionProfile(0), mCorrLorentz(*this),mCorrPolar(*this),mCorrSlitAperture(*this), mCorrTextureMarchDollase(*this),mCorrTextureEllipsoid(*this),mCorrTOF(*this),mCorrCylAbs(*this),mExtractionMode(false), mpLeBailData(0),mFrozenLatticePar(6),mFreezeLatticePar(old.FreezeLatticePar()),mFrozenBMatrix(3,3) { this->AddSubRefObj(mCorrTextureMarchDollase); this->AddSubRefObj(mCorrTextureEllipsoid); this->SetIsIgnoringImagScattFact(true); this->SetProfile(old.mpReflectionProfile->CreateCopy()); #if 0 //:TODO: if(old.mpLeBailData!=0) { mpLeBailData=new DiffractionDataSingleCrystal(false); *mpLeBailData = *(old.mpLeBailData); } #endif mClockMaster.AddChild(mClockProfilePar); mClockMaster.AddChild(mClockLorentzPolarSlitCorrPar); mClockMaster.AddChild(mpReflectionProfile->GetClockMaster()); for(unsigned int i=0;i<6;++i) mFrozenLatticePar(i)=old.GetFrozenLatticePar(i); mFrozenBMatrix=old.GetBMatrix(); } PowderPatternDiffraction::~PowderPatternDiffraction() { if(mpReflectionProfile!=0) { this->RemoveSubRefObj(*mpReflectionProfile); delete mpReflectionProfile; } } const string& PowderPatternDiffraction::GetClassName() const { const static string className="PowderPatternDiffraction"; return className; } PowderPatternDiffraction* PowderPatternDiffraction::CreateCopy()const { return new PowderPatternDiffraction(*this); } void PowderPatternDiffraction::SetParentPowderPattern(PowderPattern &s) { if(mpParentPowderPattern!=0) mClockMaster.RemoveChild(mpParentPowderPattern->GetIntegratedProfileLimitsClock()); mpParentPowderPattern = &s; mClockMaster.AddChild(mpParentPowderPattern->GetIntegratedProfileLimitsClock()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternPar()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternXCorr()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternRadiation()); mClockMaster.AddChild(mpParentPowderPattern->GetClockPowderPatternAbsCorr()); } const CrystVector_REAL& PowderPatternDiffraction::GetPowderPatternCalc()const { this->CalcPowderPattern(); return mPowderPatternCalc; } pair PowderPatternDiffraction::GetPowderPatternIntegratedCalc()const { this->CalcPowderPatternIntegrated(); return make_pair(&mPowderPatternIntegratedCalc,&mClockPowderPatternIntegratedCalc); } void PowderPatternDiffraction::SetReflectionProfilePar(const ReflectionProfileType prof, const REAL w, const REAL u, const REAL v, const REAL eta0, const REAL eta1) { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::SetReflectionProfilePar()",5) ReflectionProfilePseudoVoigt* p=new ReflectionProfilePseudoVoigt(); p->SetProfilePar(w,u,v,eta0,eta1); this->SetProfile(p); } void PowderPatternDiffraction::SetProfile(ReflectionProfile *p) { if(p==mpReflectionProfile) return; if(mpReflectionProfile!=0) { this->RemoveSubRefObj(*mpReflectionProfile); delete mpReflectionProfile; } mpReflectionProfile= p; this->AddSubRefObj(*mpReflectionProfile); mClockMaster.AddChild(mpReflectionProfile->GetClockMaster()); } const ReflectionProfile& PowderPatternDiffraction::GetProfile()const { return *mpReflectionProfile; } ReflectionProfile& PowderPatternDiffraction::GetProfile() { return *mpReflectionProfile; } // Disable the base-class function. void PowderPatternDiffraction::GenHKLFullSpace( const REAL maxTheta, const bool useMultiplicity) { // This should be never called. abort(); } void PowderPatternDiffraction::GenHKLFullSpace() { VFN_DEBUG_ENTRY("PowderPatternDiffraction::GenHKLFullSpace():",5) float stol; if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) stol=mpParentPowderPattern->X2STOL(mpParentPowderPattern->GetPowderPatternXMin()); else stol=mpParentPowderPattern->X2STOL(mpParentPowderPattern->GetPowderPatternXMax()); if(stol>1) stol=1; // Do not go beyond 0.5 A resolution (mostly for TOF data) this->ScatteringData::GenHKLFullSpace2(stol,true); if((mExtractionMode) && (mFhklObsSq.numElements()!=this->GetNbRefl())) {// Reflections changed, so ScatteringData::PrepareHKLarrays() probably reseted mFhklObsSq VFN_DEBUG_ENTRY("PowderPatternDiffraction::GenHKLFullSpace(): need to reset observed intensities",7) mFhklObsSq.resize(this->GetNbRefl()); mFhklObsSq=100; } mCorrTextureEllipsoid.InitRefParList();// #TODO: SHould this be here ? VFN_DEBUG_EXIT("PowderPatternDiffraction::GenHKLFullSpace():"<GetNbRefl(),5) } void PowderPatternDiffraction::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { if(mUseFastLessPreciseFunc!=allowApproximations) { mClockProfileCalc.Reset(); mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=allowApproximations; this->GetNbReflBelowMaxSinThetaOvLambda(); this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); } void PowderPatternDiffraction::EndOptimization() { if(mOptimizationDepth==1) { if(mUseFastLessPreciseFunc==true) { mClockProfileCalc.Reset(); mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=false; this->GetNbReflBelowMaxSinThetaOvLambda(); } this->RefinableObj::EndOptimization(); } void PowderPatternDiffraction::SetApproximationFlag(const bool allow) { if(mUseFastLessPreciseFunc!=allow) { mClockProfileCalc.Reset(); mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=allow; this->GetNbReflBelowMaxSinThetaOvLambda(); this->RefinableObj::SetApproximationFlag(allow); } void PowderPatternDiffraction::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { // One group for all profile parameters unsigned int index=0; VFN_DEBUG_MESSAGE("PowderPatternDiffraction::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { //if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs()) //{ if(index==0) index=first++; groupIndex(i)=index; //} //else //no parameters other than unit cell } } const CrystVector_REAL& PowderPatternDiffraction::GetPowderPatternCalcVariance()const { return mPowderPatternCalcVariance; } pair PowderPatternDiffraction::GetPowderPatternIntegratedCalcVariance()const { this->CalcPowderPatternIntegrated(); return make_pair(&mPowderPatternIntegratedCalcVariance, &mClockPowderPatternIntegratedVarianceCalc); } bool PowderPatternDiffraction::HasPowderPatternCalcVariance()const { return true; } void PowderPatternDiffraction::SetCrystal(Crystal &crystal) { bool reprep=(mpCrystal!=0); this->ScatteringData::SetCrystal(crystal); // Check if we use DE-PV if(mpReflectionProfile!=0) if(mpReflectionProfile->GetClassName()=="ReflectionProfileDoubleExponentialPseudoVoigt") { ReflectionProfileDoubleExponentialPseudoVoigt *p =dynamic_cast(mpReflectionProfile); p->SetUnitCell((UnitCell)crystal); } mClockHKL.Reset(); if(reprep) this->Prepare(); } const Radiation& PowderPatternDiffraction::GetRadiation()const { return mpParentPowderPattern->GetRadiation();} void PowderPatternDiffraction::SetExtractionMode(const bool extract,const bool init) { VFN_DEBUG_ENTRY("PowderPatternDiffraction::SetExtractionMode(),ExtractionMode="<0)) {// Leaving extraction mode, so update extracted single crystal data VFN_DEBUG_ENTRY("PowderPatternDiffraction::SetExtractionMode(),LEAVING Le Bail Mode",7) if(mpLeBailData==0) mpLeBailData=new DiffractionDataSingleCrystal(this->GetCrystal(),false); // Update wavelength & name mpLeBailData->SetWavelength(this->GetRadiation().GetWavelength()(0)); mpLeBailData->SetRadiationType(this->GetRadiation().GetRadiationType()); char buf[200]; sprintf(buf,"LeBail (d=%4.2fA):",1/(2*abs(mMaxSinThetaOvLambda)+1e-6)); mpLeBailData->SetName(string(buf)+this->GetCrystal().GetName()); const unsigned long nbrefl=this->GetNbReflBelowMaxSinThetaOvLambda(); CrystVector_REAL iobs(nbrefl),sigma(nbrefl); CrystVector_long h(nbrefl),k(nbrefl),l(nbrefl); sigma=1; for(unsigned long i=0;iSetHklIobs(h,k,l,iobs,sigma); // Erase mFhklObsSq - only used during extraction mode. mFhklObsSq.resize(0); } mClockIhklCalc.Reset();mClockMaster.Reset(); mClockFhklObsSq.Click(); VFN_DEBUG_EXIT("PowderPatternDiffraction::SetExtractionMode(),ExtractionMode="<SetExtractionMode(true,true);// Should not have to do this here ! if(mFhklObsSq.numElements()!=this->GetNbRefl()) {//Something went wrong ! VFN_DEBUG_ENTRY("PowderPatternDiffraction::ExtractLeBail() mFhklObsSq.size() != NbRefl !!!!!!",7) mFhklObsSq.resize(this->GetNbRefl()); mFhklObsSq=100; } // First get the observed powder pattern, minus the contribution of all other phases. CrystVector_REAL obs,iextract,calc; iextract=mFhklObsSq; mFhklObsSq=0; mClockFhklObsSq.Click(); // Get the observed and calculated powder pattern (excluding this diffraction phase) obs=mpParentPowderPattern->GetPowderPatternObs(); obs-=mpParentPowderPattern->GetPowderPatternCalc(); mFhklObsSq=iextract; mClockFhklObsSq.Click(); // We take here the reflections which are centered below the max(sin(theta)/lambda) // actually more reflections are calculated, but the pattern is only calculated up to // max(sin(theta)/lambda). const unsigned long nbrefl=this->ScatteringData::GetNbReflBelowMaxSinThetaOvLambda(); iextract=0; for(;nbcycle>0;nbcycle--) { //cout<<"PowderPatternDiffraction::ExtractLeBail(): cycle #"<GetPowderPatternCalc(); for(unsigned int k0=0;k0=(long)(mpParentPowderPattern->GetNbPointUsed())) last=mpParentPowderPattern->GetNbPointUsed(); if(mvReflProfile[k0].first<0)first=0; else first=(mvReflProfile[k0].first); const REAL *p1=mvReflProfile[k0].profile.data()+(first-mvReflProfile[k0].first); const REAL *p2=calc.data()+first; const REAL *pobs=obs.data()+first; for(long i=first;i<=last;++i) { const REAL s2=*p2++; const REAL tmp=*pobs++ * *p1++; if( (s2<1e-8) ) // || (tmp<=0) {// Avoid <0 intensities (should not happen, it means profile is <0) //cout<<"S2? "<< int(mH(k0))<<" "<1e-8)&&(!ISNAN_OR_INF(s1))) iextract(k0)=s1*mFhklObsSq(k0); else iextract(k0)=1e-8;//:KLUDGE: should <0 intensities be allowed ? //if(nbcycle==1) cout<<" Le Bail "<(mH,mK,mL,this->GetFhklCalcSq(),mFhklObsSq,10,4,nbrefl)<SetHklIobs(h,k,l,iobs,sigma); } VFN_DEBUG_EXIT("PowderPatternDiffraction::ExtractLeBail()mFhklObsSq.size()=="<IsBeingRefined()) return mNbReflUsed; VFN_DEBUG_MESSAGE("PowderPatternDiffraction::GetNbReflBelowMaxSinThetaOvLambda(): "<CalcPowderReflProfile(); const long nbpoint=mpParentPowderPattern->GetNbPointUsed(); if((mNbReflUsed>0)&&(mNbReflUsednbpoint) &&(mvReflProfile[mNbReflUsed-1].first<=nbpoint)) return mNbReflUsed; } if((mNbReflUsed==mNbRefl) && (mvReflProfile[mNbReflUsed-1].profile.numElements()>0)) if(mvReflProfile[mNbReflUsed-1].first<=nbpoint)return mNbReflUsed; long i; for(i=0;inbpoint) break; } if(i!=mNbReflUsed) { mNbReflUsed=i; mClockNbReflUsed.Click(); VFN_DEBUG_MESSAGE("->Changed Max sin(theta)/lambda="<CalcFrozenBMatrix(); } REAL PowderPatternDiffraction::GetFrozenLatticePar(const unsigned int i) const {return mFrozenLatticePar(i);} void PowderPatternDiffraction::FreezeLatticePar(const bool use) { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::FreezeLatticePar("<GetCrystal().GetLatticePar(); if(use) this->CalcFrozenBMatrix(); mClockTheta.Reset(); this->UpdateDisplay(); } bool PowderPatternDiffraction::FreezeLatticePar() const {return mFreezeLatticePar;} unsigned int PowderPatternDiffraction::GetProfileFitNetNbObs()const { unsigned int nb=0; unsigned int irefl=0; unsigned int ilast=0; while(this->GetParentPowderPattern().STOL2Pixel(mSinThetaLambda(irefl))<0) { irefl++; if(irefl>=this->GetNbReflBelowMaxSinThetaOvLambda()) break; } while(ireflGetNbReflBelowMaxSinThetaOvLambda()) { const REAL stol = mSinThetaLambda(irefl); while(mSinThetaLambda(irefl)==stol) { //cout<=this->GetNbReflBelowMaxSinThetaOvLambda()) break; } const int nbnew =this->GetParentPowderPattern().STOL2Pixel(stol)-ilast; if(nbnew>1) nb += nbnew-1; //cout<<" => Added "<< nbnew-1<< "net observed points ("<GetParentPowderPattern().STOL2Pixel(stol)<<"-"<GetParentPowderPattern().STOL2Pixel(stol); } //cout<<"Final number of net observed points: "<GetNbReflBelowMaxSinThetaOvLambda(); if(mClockPowderPatternCalc>mClockMaster) return; TAU_PROFILE("PowderPatternDiffraction::CalcPowderPattern()-Apply profiles","void (bool)",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPatternDiffraction::CalcPowderPattern():",3) // :TODO: Can't do this as this is non-const //if(this->GetCrystal().GetSpaceGroup().GetClockSpaceGroup()>mClockHKL) // this->GenHKLFullSpace(); // // The workaround is to call Prepare() (non-const) before every calculation // when a modifictaion may have occured. this->CalcIhkl(); this->CalcPowderReflProfile(); if( (mClockPowderPatternCalc>mClockIhklCalc) &&(mClockPowderPatternCalc>mClockProfileCalc)) return; if(true) //:TODO: false == mUseFastLessPreciseFunc { const long nbRefl=this->GetNbRefl(); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPattern\ Applying profiles for "<GetNbPoint(); mPowderPatternCalc.resize(specNbPoints); mPowderPatternCalc=0; const bool useML= (mIhklCalcVariance.numElements() != 0); if(useML) { mPowderPatternCalcVariance.resize(specNbPoints); mPowderPatternCalcVariance=0; } else mPowderPatternCalcVariance.resize(0); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPattern() Has variance:"<=mNbReflUsed) break;// After sin(theta)/lambda limit else continue; // before beginning of pattern ? } VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPattern()#"<IsAnisotropic()) break;// Anisotropic profiles if( (i+step) >= nbRefl) break; if(mSinThetaLambda(i+step) > (mSinThetaLambda(i)+1e-5) ) break; } VFN_DEBUG_MESSAGE("Apply profile(Monochromatic)Refl("<"< &vPar) { TAU_PROFILE("PowderPatternDiffraction::CalcPowderPattern_FullDeriv()","void ()",TAU_DEFAULT); //cout<<"PowderPatternDiffraction::CalcPowderPattern_FullDeriv"<CalcPowderPattern(); bool notYetDerivProfiles=true; mIhkl_FullDeriv.clear(); mvReflProfile_FullDeriv.clear(); mPowderPattern_FullDeriv.clear(); for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) continue; if((*par)->IsFixed()) continue; if((*par)->IsUsed()==false) continue; if( (*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScatt) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattPow)) { this->CalcIhkl_FullDeriv(vPar); } if(notYetDerivProfiles) { if( (*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeRadiation) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeUnitCell) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataCorrPos) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataProfile)) { this->CalcPowderReflProfile_FullDeriv(vPar); notYetDerivProfiles=false; } } } //this->CalcPowderReflProfile(); for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) mPowderPattern_FullDeriv[*par]=this->GetPowderPatternCalc(); else { if((*par)->IsFixed()) continue; if((*par)->IsUsed()==false) continue; if(mIhkl_FullDeriv[*par].size()!=0) { const long nbRefl=this->GetNbRefl(); long step; // number of reflections at the same place and with the same (assumed) profile const long specNbPoints=mpParentPowderPattern->GetNbPoint(); mPowderPattern_FullDeriv[*par].resize(specNbPoints); mPowderPattern_FullDeriv[*par]=0; for(long i=0;i=mNbReflUsed) break; else continue; } REAL intensity=0.; //check if the next reflection is at the same theta. If this is true, //Then assume that the profile is exactly the same, unless it is anisotropic for(step=0; ;) { intensity += mIhkl_FullDeriv[*par](i + step); step++; if(mpReflectionProfile->IsAnisotropic()) break;// Anisotropic profiles if( (i+step) >= nbRefl) break; if(mSinThetaLambda(i+step) > (mSinThetaLambda(i)+1e-5) ) break; } { const long first=mvReflProfile[i].first,last=mvReflProfile[i].last; const REAL *p2 = mvReflProfile[i].profile.data(); REAL *p3 = mPowderPattern_FullDeriv[*par].data()+first; for(long j=first;j<=last;j++) *p3++ += *p2++ * intensity; } } } if(mvReflProfile_FullDeriv[*par].size()!=0) { const long nbRefl=this->GetNbRefl(); long step; // number of reflections at the same place and with the same (assumed) profile const long specNbPoints=mpParentPowderPattern->GetNbPoint(); mPowderPattern_FullDeriv[*par].resize(specNbPoints); mPowderPattern_FullDeriv[*par]=0;// :TODO: use only the number of points actually used cout<<__FILE__<<":"<<__LINE__<<":PowderPatternDiffraction::CalcPowderPattern_FullDeriv():par="<<(*par)->GetName()<=mNbReflUsed) break; else continue; } REAL intensity=0.; //check if the next reflection is at the same theta. If this is true, //Then assume that the profile is exactly the same, unless it is anisotropic for(step=0; ;) { intensity += mIhklCalc(i + step); step++; if(mpReflectionProfile->IsAnisotropic()) break;// Anisotropic profiles if( (i+step) >= nbRefl) break; if(mSinThetaLambda(i+step) > (mSinThetaLambda(i)+1e-5) ) break; } if(mvReflProfile_FullDeriv[*par][i].size()>0)// Some profiles may be unaffected by a given parameter { const long first=mvReflProfile[i].first,last=mvReflProfile[i].last; const REAL *p2 = mvReflProfile_FullDeriv[*par][i].data(); REAL *p3 = mPowderPattern_FullDeriv[*par].data()+first; for(long j=first;j<=last;j++) *p3++ += *p2++ * intensity; } } } } } #if 0 std::map newDeriv=mPowderPattern_FullDeriv; this->PowderPatternComponent::CalcPowderPattern_FullDeriv(vPar); std::vector v; int n=0; for(std::map::reverse_iterator pos=mPowderPattern_FullDeriv.rbegin();pos!=mPowderPattern_FullDeriv.rend();++pos) { if(pos->first==0) continue; if(pos->second.size()==0) continue; v.push_back(&(newDeriv[pos->first])); v.push_back(&(pos->second)); cout<first->GetName()<<":"<second.size()<<","<first].size()<8) break; } cout<(v,16,4,1000)<GetNbReflBelowMaxSinThetaOvLambda(); if(mClockPowderPatternIntegratedCalc>mClockMaster) return; TAU_PROFILE("PowderPatternDiffraction::CalcPowderPatternIntegrated()","void (bool)",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"PowderPatternDiffraction::CalcPowderPatternIntegrated()1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"PowderPatternDiffraction::CalcPowderPatternIntegrated()2","", TAU_FIELD); this->CalcIhkl(); TAU_PROFILE_START(timer1); this->PrepareIntegratedProfile(); TAU_PROFILE_STOP(timer1); if( (mClockPowderPatternIntegratedCalc>mClockIhklCalc) &&(mClockPowderPatternIntegratedCalc>mClockIntegratedProfileFactor) &&(mClockPowderPatternIntegratedCalc>mpParentPowderPattern->GetIntegratedProfileLimitsClock())) return; VFN_DEBUG_ENTRY("PowderPatternDiffraction::CalcPowderPatternIntegrated()",3) const long nbRefl=this->GetNbRefl(); const long nb=mpParentPowderPattern->GetIntegratedProfileMin().numElements(); mPowderPatternIntegratedCalc.resize(nb); mPowderPatternIntegratedCalc=0; const bool useML= (mIhklCalcVariance.numElements() != 0); if(useML) { mPowderPatternIntegratedCalcVariance.resize(nb); mPowderPatternIntegratedCalcVariance=0; } else mPowderPatternIntegratedCalcVariance.resize(0); const REAL * RESTRICT psith=mSinThetaLambda.data(); const REAL * RESTRICT pI=mIhklCalc.data(); const REAL * RESTRICT pIvar=mIhklCalcVariance.data(); vector< pair >::const_iterator pos; pos=mIntegratedProfileFactor.begin(); TAU_PROFILE_START(timer2); for(long i=0;i= nbRefl) break; if( *(++psith) > thmax ) break; if(mpReflectionProfile->IsAnisotropic()) break;// Anisotropic profile ++pos; } VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderPatternIntegrated():"<first; const REAL * RESTRICT pFact=pos->second.data(); const unsigned long nb=pos->second.numElements(); //cout <0;j--) { //cout <first+j<<"("<<*pFact<<","<<*pData<<") "; *pData++ += intensity * *pFact++ ; } //cout<second.data(); REAL * RESTRICT pVar=mPowderPatternIntegratedCalcVariance.data()+pos->first; for(unsigned long j=nb;j>0;j--) *pVar++ += var * *pFact++ ; } ++pos; } TAU_PROFILE_STOP(timer2); #ifdef __DEBUG__ if(gVFNDebugMessageLevel<3) { this->CalcPowderPattern(); CrystVector_REAL integr(nb),min(nb),max(nb),diff(nb),index(nb); integr=0; for(long i=0;iGetIntegratedProfileMin()(i); max(i)=mpParentPowderPattern->GetIntegratedProfileMax()(i); integr(i)=0; for(long j=mpParentPowderPattern->GetIntegratedProfileMin()(i); j<=mpParentPowderPattern->GetIntegratedProfileMax()(i);j++) { integr(i) += mPowderPatternCalc(j); } diff(i)=1.-mPowderPatternIntegratedCalc(i)/integr(i); } cout << "Integrated intensities, Component"< (index,min,max,integr,mPowderPatternIntegratedCalc,diff,20,6)< &vPar) { TAU_PROFILE("PowderPatternDiffraction::CalcPowderPatternIntegrated_FullDeriv()","void ()",TAU_DEFAULT); //cout<<"PowderPatternDiffraction::CalcPowderPatternIntegrated_FullDeriv"<PowderPatternComponent::CalcPowderPatternIntegrated_FullDeriv(vPar); //return; this->CalcPowderPatternIntegrated(); this->CalcIhkl_FullDeriv(vPar); const long nbRefl=this->GetNbRefl(); //#define PowderPatternDiffraction_CalcPowderPatternIntegrated_FullDerivDEBUG #ifdef PowderPatternDiffraction_CalcPowderPatternIntegrated_FullDerivDEBUG this->PowderPatternComponent::CalcPowderPatternIntegrated_FullDeriv(vPar); std::map oldDeriv=mPowderPatternIntegrated_FullDeriv; #endif const long nbprof=mpParentPowderPattern->GetIntegratedProfileMin().size(); long ctpar=0; mPowderPatternIntegrated_FullDeriv.clear(); for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) mPowderPatternIntegrated_FullDeriv[*par]=mPowderPatternIntegratedCalc; else { if(mIhkl_FullDeriv[*par].size()==0) continue; if(mPowderPatternIntegrated_FullDeriv[*par].size()==0) { mPowderPatternIntegrated_FullDeriv[*par].resize(nbprof); mPowderPatternIntegrated_FullDeriv[*par]=0; } const REAL * RESTRICT psith=mSinThetaLambda.data(); const REAL * RESTRICT pI=mIhkl_FullDeriv[*par].data(); // :TODO: also handle derivatives of profile parameters ? Though one should not // refine profiles using integrated profiles ! vector< pair >::const_iterator pos=mIntegratedProfileFactor.begin(); for(long i=0;i= nbRefl) break; if( *(++psith) > thmax ) break; if(mpReflectionProfile->IsAnisotropic()) break;// Anisotropic profile ++pos; } REAL * RESTRICT pData=mPowderPatternIntegrated_FullDeriv[*par].data()+pos->first; const REAL * RESTRICT pFact=pos->second.data(); const unsigned long nb=pos->second.numElements(); #ifdef PowderPatternDiffraction_CalcPowderPatternIntegrated_FullDerivDEBUG if((i<5)&&(ctpar<8)) cout<<__FILE__<<":"<<__LINE__<<":"<<(*par)->GetName()<<"i="<0;j--) { #ifdef PowderPatternDiffraction_CalcPowderPatternIntegrated_FullDerivDEBUG *pData += intensity * *pFact ; if((i<5)&&((*par)->GetName()=="Cimetidine_C11_x")&&(pos->first==0)&&(nb==j)) cout<::iterator par=vPar.begin();par!=vPar.end();++par) { if(mPowderPatternIntegrated_FullDeriv[*par].size()==0) continue; v.push_back(&(mPowderPatternIntegrated_FullDeriv[*par])); v.push_back(&(oldDeriv[*par])); cout<<(*par)->GetName()<<":"<6) break; } cout<<"PowderPatternDiffraction::CalcPowderPatternIntegrated_FullDeriv():"<(v,12,1,20)<CalcSinThetaLambda(); mpParentPowderPattern->GetNbPointUsed();// if( (mClockProfileCalc>mClockProfilePar) &&(mClockProfileCalc>mpReflectionProfile->GetClockMaster()) &&(mClockProfileCalc>mClockTheta) &&(mClockProfileCalc>this->GetRadiation().GetClockWavelength()) &&(mClockProfileCalc>mpParentPowderPattern->GetClockPowderPatternXCorr()) &&(mClockProfileCalc>mClockHKL) &&(mClockProfileCalc>mpParentPowderPattern->GetClockNbPointUsed())) return; TAU_PROFILE("PowderPatternDiffraction::CalcPowderReflProfile()","void (bool)",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPatternDiffraction::CalcPowderReflProfile()",5) //Calc all profiles mvLabel.clear(); stringstream label; unsigned int nbLine=1; CrystVector_REAL spectrumDeltaLambdaOvLambda; CrystVector_REAL spectrumFactor;//relative weigths of different lines of X-Ray tube switch(this->GetRadiation().GetWavelengthType()) { case WAVELENGTH_MONOCHROMATIC: { spectrumDeltaLambdaOvLambda.resize(1);spectrumDeltaLambdaOvLambda=0.0; spectrumFactor.resize(1);spectrumFactor=1.0; break; } case WAVELENGTH_ALPHA12: { nbLine=2; spectrumDeltaLambdaOvLambda.resize(2); spectrumDeltaLambdaOvLambda(0) =-this->GetRadiation().GetXRayTubeDeltaLambda() *this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio() /(1+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()) /this->GetRadiation().GetWavelength()(0); spectrumDeltaLambdaOvLambda(1) = this->GetRadiation().GetXRayTubeDeltaLambda() /(1+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()) /this->GetRadiation().GetWavelength()(0); spectrumFactor.resize(2); spectrumFactor(0)=1./(1.+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()); spectrumFactor(1)=this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio() /(1.+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()); break; } case WAVELENGTH_TOF: { spectrumDeltaLambdaOvLambda.resize(1);spectrumDeltaLambdaOvLambda=0.0; spectrumFactor.resize(1);spectrumFactor=1.0; break; } default: throw ObjCrystException("PowderPatternDiffraction::PrepareIntegratedProfile():\ Radiation must be either monochromatic, from an X-Ray Tube, or neutron TOF !!"); } VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderReflProfile():\ Computing all Profiles",5) REAL center,// center of current reflection (depends on line if several) x0; // theoretical (uncorrected for zero's, etc..) position of center of line long first,last;// first & last point of the stored profile CrystVector_REAL vx,reflProfile,tmpV; mvReflProfile.resize(this->GetNbRefl()); for(unsigned int i=0;iGetNbRefl();i++) { mvReflProfile[i].first=0; mvReflProfile[i].last=0; mvReflProfile[i].profile.resize(0); } VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderReflProfile()",5) for(unsigned int line=0;lineGetNbRefl();i++) {// Only the reflections contributing below the max(sin(theta)/lambda) will be computed VFN_DEBUG_ENTRY("PowderPatternDiffraction::CalcPowderReflProfile()#"<STOL2X(mSinThetaLambda(i)); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderReflProfile()#"<1) {// we have several lines, not centered on the profile range center = mpParentPowderPattern->X2XCorr( x0+2*tan(x0/2.0)*spectrumDeltaLambdaOvLambda(line)); } else center=mpParentPowderPattern->X2XCorr(x0); REAL fact=1.0; if(!mUseFastLessPreciseFunc) fact=5.0; const REAL halfwidth=mpReflectionProfile->GetFullProfileWidth(0.04,center,mH(i),mK(i),mL(i))*fact; if(line==0) { // For an X-Ray tube, label on first (strongest) of reflections lines (Kalpha1) label.str(""); label<GetRadiation().GetWavelengthType()==WAVELENGTH_ALPHA12) {// We need to shift the last point to include 2 lines in the profile spectrumwidth=2*this->GetRadiation().GetXRayTubeDeltaLambda() /this->GetRadiation().GetWavelength()(0)*tan(x0/2.0); } first=(long)(mpParentPowderPattern->X2Pixel(center-halfwidth)); last =(long)(mpParentPowderPattern->X2Pixel(center+halfwidth+spectrumwidth)); if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { const long f=first; first=last; last=f; } if(first>last) { // Whoops - should not happen !! Unless there is a strange (dis)order for the x coordinates... cout<<"PowderPatternDiffraction::CalcPowderReflProfile(), line"<<__LINE__<<"first>last !! :"<last) { cout<<__FILE__<<__LINE__<=0)&&(first<(long)(mpParentPowderPattern->GetNbPoint()))) { if(first<0) first=0; if(last>=(long)(mpParentPowderPattern->GetNbPoint())) last=mpParentPowderPattern->GetNbPoint()-1; vx.resize(last-first+1); } else vx.resize(0); // store no profile if reflection out of pattern mvReflProfile[i].first=first; mvReflProfile[i].last=last; } else { first=mvReflProfile[i].first; last=mvReflProfile[i].last; if((last>=0)&&(first<(long)(mpParentPowderPattern->GetNbPoint()))) vx.resize(last-first+1); else vx.resize(0); vx.resize(last-first+1); } if((last>=0)&&(first<(long)(mpParentPowderPattern->GetNbPoint()))) { { const REAL *p0=mpParentPowderPattern->GetPowderPatternX().data()+first; REAL *p1=vx.data(); for(long i=first;i<=last;i++) *p1++ = *p0++; } VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderReflProfile():"<GetProfile(vx,center,mH(i),mK(i),mL(i)); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcPowderReflProfile()",2) if(nbLine>1) reflProfile *=spectrumFactor(line); if(line==0) mvReflProfile[i].profile = reflProfile; else mvReflProfile[i].profile += reflProfile; } else { // reflection is out of pattern, so store no profile mvReflProfile[i].profile.resize(0); } VFN_DEBUG_EXIT("PowderPatternDiffraction::CalcPowderReflProfile():\ Computing all Profiles: Reflection #"<(long)(mpParentPowderPattern->GetNbPointUsed())) break; } } mClockProfileCalc.Click(); VFN_DEBUG_EXIT("PowderPatternDiffraction::CalcPowderReflProfile()",5) } void PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv(std::set &vPar) { TAU_PROFILE("PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv()","void (bool)",TAU_DEFAULT); cout<<__FILE__<<":"<<__LINE__<<":PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv()"<CalcPowderReflProfile(); unsigned int nbLine=1; CrystVector_REAL spectrumDeltaLambdaOvLambda; CrystVector_REAL spectrumFactor;//relative weigths of different lines of X-Ray tube switch(this->GetRadiation().GetWavelengthType()) { case WAVELENGTH_MONOCHROMATIC: { spectrumDeltaLambdaOvLambda.resize(1);spectrumDeltaLambdaOvLambda=0.0; spectrumFactor.resize(1);spectrumFactor=1.0; break; } case WAVELENGTH_ALPHA12: { nbLine=2; spectrumDeltaLambdaOvLambda.resize(2); spectrumDeltaLambdaOvLambda(0) =-this->GetRadiation().GetXRayTubeDeltaLambda() *this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio() /(1+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()) /this->GetRadiation().GetWavelength()(0); spectrumDeltaLambdaOvLambda(1) = this->GetRadiation().GetXRayTubeDeltaLambda() /(1+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()) /this->GetRadiation().GetWavelength()(0); spectrumFactor.resize(2); spectrumFactor(0)=1./(1.+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()); spectrumFactor(1)=this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio() /(1.+this->GetRadiation().GetXRayTubeAlpha2Alpha1Ratio()); break; } case WAVELENGTH_TOF: { spectrumDeltaLambdaOvLambda.resize(1);spectrumDeltaLambdaOvLambda=0.0; spectrumFactor.resize(1);spectrumFactor=1.0; break; } default: throw ObjCrystException("PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv():\ Radiation must be either monochromatic, from an X-Ray Tube, or neutron TOF !!"); } REAL center,// center of current reflection (depends on line if several) x0; // theoretical (uncorrected for zero's, etc..) position of center of line long first,last;// first & last point of the stored profile CrystVector_REAL vx,reflProfile,tmpV; // Derivative vs the shift of the reflection center vector vReflProfile_DerivCenter(mNbReflUsed); mvReflProfile_FullDeriv.clear(); for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) continue; if( (*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeRadiation) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeUnitCell) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataCorrPos) ||(*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataProfile)) { mvReflProfile_FullDeriv[*par].resize(mNbReflUsed); for(unsigned int line=0;lineSTOL2X(mSinThetaLambda(i)); if(nbLine>1) {// we have several lines, not centered on the profile range center = mpParentPowderPattern->X2XCorr( x0+2*tan(x0/2.0)*spectrumDeltaLambdaOvLambda(line)); } else center=mpParentPowderPattern->X2XCorr(x0); first=mvReflProfile[i].first; last=mvReflProfile[i].last; if((last>=0)&&(first<(long)(mpParentPowderPattern->GetNbPoint()))) vx.resize(last-first+1); else vx.resize(0); vx.resize(last-first+1); if((last>=0)&&(first<(long)(mpParentPowderPattern->GetNbPoint()))) { { const REAL *p0=mpParentPowderPattern->GetPowderPatternX().data()+first; REAL *p1=vx.data(); for(long i=first;i<=last;i++) *p1++ = *p0++; } if((*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataProfile)) {// Parameter only affects profile //if(i==0) cout<<"PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv()par="<<(*par)->GetName()<<":refl #"<GetDerivStep(); (*par)->Mutate(step); reflProfile=mpReflectionProfile->GetProfile(vx,center,mH(i),mK(i),mL(i)); (*par)->Mutate(-2*step); reflProfile-=mpReflectionProfile->GetProfile(vx,center,mH(i),mK(i),mL(i)); (*par)->Mutate(step); reflProfile/=2*step; } else {// Parameter affects reflection center REAL dcenter=0; { //:TODO: analytical derivatives const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); REAL x1=mpParentPowderPattern->STOL2X(this->CalcSinThetaLambda(mH(i),mK(i),mL(i))); if(nbLine>1) dcenter = mpParentPowderPattern->X2XCorr(x1+2*tan(x1/2.0)*spectrumDeltaLambdaOvLambda(line)); else dcenter = mpParentPowderPattern->X2XCorr(x1); (*par)->Mutate(-2*step); x1=mpParentPowderPattern->STOL2X(this->CalcSinThetaLambda(mH(i),mK(i),mL(i))); if(nbLine>1) dcenter-= mpParentPowderPattern->X2XCorr(x1+2*tan(x1/2.0)*spectrumDeltaLambdaOvLambda(line)); else dcenter-= mpParentPowderPattern->X2XCorr(x1); (*par)->Mutate(step); dcenter/=2*step; } if(dcenter!=0) { //if(i==0) cout<<"PowderPatternDiffraction::CalcPowderReflProfile_FullDeriv()par="<<(*par)->GetName()<<":refl #"< Parameter affects nothing ?"<0) { if(nbLine>1) reflProfile *=spectrumFactor(line); if(line==0) mvReflProfile_FullDeriv[*par][i] = reflProfile; else mvReflProfile_FullDeriv[*par][i] += reflProfile; } } } } } } } void PowderPatternDiffraction::CalcIntensityCorr()const { bool needRecalc=false; this->CalcSinThetaLambda(); if((mClockIntensityCorrGetClockNbReflBelowMaxSinThetaOvLambda())) needRecalc=true; const CrystVector_REAL *mpCorr[6] = {0, 0, 0, 0, 0, 0}; if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { mpCorr[0]=&(mCorrTOF.GetCorr()); if(mClockIntensityCorrGetRadiation().GetRadiationType()==RAD_XRAY) { mpCorr[1]=&(mCorrPolar.GetCorr()); if(mClockIntensityCorr0) { mpCorr[3]=&(mCorrTextureMarchDollase.GetCorr()); if(mClockIntensityCorrdata(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ = *p++; if(this->GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) { if(this->GetRadiation().GetRadiationType()==RAD_XRAY) { pCorr=mIntensityCorr.data(); p=mpCorr[1]->data(); const REAL* p2=mpCorr[2]->data(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ *= *p++ * *p2++; } else { pCorr=mIntensityCorr.data(); p=mpCorr[2]->data(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ *= *p++; } } if(mCorrTextureMarchDollase.GetNbPhase()>0) { pCorr=mIntensityCorr.data(); p=mpCorr[3]->data(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ *= *p++; } if(mpCorr[4]->numElements()>0) { pCorr=mIntensityCorr.data(); p=mpCorr[4]->data(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ *= *p++; } if(mpCorr[5] != NULL) if(mpCorr[5]->numElements()>0) { pCorr=mIntensityCorr.data(); p=mpCorr[5]->data(); for(long i=mNbReflUsed;i>0;i--) *pCorr++ *= *p++; } mClockIntensityCorr.Click(); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIntensityCorr():finished",2) } void PowderPatternDiffraction::CalcIhkl() const { this->CalcIntensityCorr(); if(mExtractionMode==true) { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIhkl():"<CalcStructFactor(); if( (mClockIhklCalc>mClockIntensityCorr) &&(mClockIhklCalc>mClockStructFactor) &&(mClockIhklCalc>mClockNbReflUsed)) return; VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIhkl()",3) TAU_PROFILE("PowderPatternDiffraction::CalcIhkl()","void ()",TAU_DEFAULT); const REAL * RESTRICT pr,* RESTRICT pi,* RESTRICT pcorr; const int * RESTRICT mult; REAL * RESTRICT p; pr=mFhklCalcReal.data(); pi=mFhklCalcImag.data(); pcorr=mIntensityCorr.data(); mult=mMultiplicity.data(); mIhklCalc.resize(mNbRefl); p=mIhklCalc.data(); if(mFhklCalcVariance.numElements()>0) { const REAL * RESTRICT pv=mFhklCalcVariance.data(); for(long i=mNbReflUsed;i>0;i--) { *p++ = *mult++ * (*pr * *pr + *pi * *pi + 2 * *pv++) * *pcorr++; pr++; pi++; } } else { for(long i=mNbReflUsed;i>0;i--) { *p++ = *mult++ * (*pr * *pr + *pi * *pi) * *pcorr++; pr++; pi++; } } if(mFhklCalcVariance.numElements()==0) { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIhkl(): No Calc Variance",2) mIhklCalcVariance.resize(0); VFN_DEBUG_MESSAGE(endl<< FormatVertVectorHKLFloats(mH,mK,mL,mSinThetaLambda, mFhklCalcReal, mFhklCalcImag, mIhklCalc, mIntensityCorr ),2) } else { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIhkl(): Calc Variance",2) mIhklCalcVariance.resize(mNbRefl); REAL * RESTRICT pVar2=mIhklCalcVariance.data(); const REAL * RESTRICT pInt=mIhklCalc.data(); const REAL * RESTRICT pVar=mFhklCalcVariance.data(); pcorr=mIntensityCorr.data(); mult=mMultiplicity.data(); for(long j=mNbReflUsed;j>0;j--) { *pVar2++ = (4* *mult) * *pcorr * *pVar *(*pInt++ - (*mult * *pcorr) * *pVar); pVar++;mult++;pcorr++; } VFN_DEBUG_MESSAGE(endl<< FormatVertVectorHKLFloats(mH,mK,mL,mSinThetaLambda, mFhklCalcReal, mIhklCalc, mExpectedIntensityFactor, mIntensityCorr, mMultiplicity, mvLuzzatiFactor[&(mpCrystal->GetScatteringPowerRegistry().GetObj(0))], mFhklCalcVariance, mIhklCalcVariance),2); VFN_DEBUG_MESSAGE(mNbRefl<<" "<(mTheta,mIhklCalc,mMultiplicity, // mFhklCalcReal,mFhklCalcImag,mIntensityCorr); mClockIhklCalc.Click(); VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcIhkl():End",3) } void PowderPatternDiffraction::CalcIhkl_FullDeriv(std::set &vPar) { TAU_PROFILE("PowderPatternDiffraction::CalcIhkl_FullDeriv()","void ()",TAU_DEFAULT); //cout<<"PowderPatternDiffraction::CalcIhkl_FullDeriv()"<CalcIntensityCorr();//:TODO: derivatives of intensity corrections (Texture, displacement parameters,...) mIhkl_FullDeriv.clear(); if(mExtractionMode==true) { //:TODO: handle Pawley refinements of I(hkl) return; } this->CalcStructFactor_FullDeriv(vPar); for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) mIhkl_FullDeriv[*par]=mIhklCalc; else { if(mFhklCalcReal_FullDeriv[*par].size()==0) continue; const REAL * RESTRICT pr,* RESTRICT pi,* RESTRICT prd,* RESTRICT pid,* RESTRICT pcorr; const int * RESTRICT mult; REAL * RESTRICT p; pr=mFhklCalcReal.data(); pi=mFhklCalcImag.data(); prd=mFhklCalcReal_FullDeriv[*par].data(); pid=mFhklCalcImag_FullDeriv[*par].data(); pcorr=mIntensityCorr.data();//:TODO: derivatives of intensity corrections (Texture, displacement parameters,...) mult=mMultiplicity.data(); mIhkl_FullDeriv[*par].resize(mNbRefl); p=mIhkl_FullDeriv[*par].data(); if(mFhklCalcImag_FullDeriv[*par].size()==0) for(long i=mNbReflUsed;i>0;i--) *p++ = *mult++ * 2 * *pr++ * *prd++ * *pcorr++; else for(long i=mNbReflUsed;i>0;i--) *p++ = *mult++ * 2 *(*pr++ * *prd++ + *pi++ * *pid++) * *pcorr++; } } #if 0 std::map oldDeriv; std::vector v; v.push_back(&mH); v.push_back(&mK); v.push_back(&mL); CrystVector_REAL m; m=mMultiplicity; v.push_back(&m); v.push_back(&mIntensityCorr); int n=0; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if((*par)==0) continue; if(mIhkl_FullDeriv[*par].size()==0) continue; const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); this->CalcIhkl(); oldDeriv[*par]=mIhklCalc; (*par)->Mutate(-2*step); this->CalcIhkl(); oldDeriv[*par]-=mIhklCalc; oldDeriv[*par]/=2*step; (*par)->Mutate(step); v.push_back(&(mIhkl_FullDeriv[*par])); v.push_back(&(oldDeriv[*par])); cout<<(*par)->GetName()<<":"<(v,12,1,20)<GetCrystal().GetSpaceGroup().GetClockSpaceGroup()>mClockHKL) ||(this->GetCrystal().GetClockLatticePar()>mClockHKL) ||(this->GetRadiation().GetClockWavelength()>mClockHKL) ||(mpParentPowderPattern->GetClockPowderPatternPar()>mClockHKL)) this->GenHKLFullSpace(); //if(0==this->GetNbRefl()) this->GenHKLFullSpace(); } void PowderPatternDiffraction::InitOptions() { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::InitOptions()",5) #if 0 static string ReflectionProfileTypeName; static string ReflectionProfileTypeChoices[3]; static bool needInitNames=true; if(true==needInitNames) { ReflectionProfileTypeName="Profile Type"; ReflectionProfileTypeChoices[0]="Gaussian"; ReflectionProfileTypeChoices[1]="Lorentzian"; ReflectionProfileTypeChoices[2]="Pseudo-Voigt"; needInitNames=false;//Only once for the class } mReflectionProfileType.Init(3,&ReflectionProfileTypeName,ReflectionProfileTypeChoices); this->AddOption(&mReflectionProfileType); #endif } const CrystVector_long& PowderPatternDiffraction::GetBraggLimits()const { this->CalcPowderReflProfile(); if((mClockProfileCalc>mClockBraggLimits)&&(this->GetNbReflBelowMaxSinThetaOvLambda()>0)) { VFN_DEBUG_ENTRY("PowderPatternDiffraction::GetBraggLimits(*min,*max)",3) TAU_PROFILE("PowderPatternDiffraction::GetBraggLimits()","void ()",TAU_DEFAULT); mIntegratedReflLimits.resize(this->GetNbReflBelowMaxSinThetaOvLambda()); long i = 0; mIntegratedReflLimits(i)=mvReflProfile[0].first; for(;i<(this->GetNbReflBelowMaxSinThetaOvLambda()-1);++i) mIntegratedReflLimits(i+1)=(mvReflProfile[i].first+mvReflProfile[i].last+mvReflProfile[i+1].first+mvReflProfile[i+1].last)/4; mIntegratedReflLimits(i)=mvReflProfile[i].last; mClockBraggLimits.Click(); VFN_DEBUG_EXIT("PowderPatternDiffraction::GetBraggLimits(*min,*max)",3) } return mIntegratedReflLimits; } void PowderPatternDiffraction::SetMaxSinThetaOvLambda(const REAL max) {this->ScatteringData::SetMaxSinThetaOvLambda(max);} const CrystMatrix_REAL& PowderPatternDiffraction::GetBMatrix()const { if(mFreezeLatticePar) return mFrozenBMatrix; return this->ScatteringData::GetBMatrix(); } void PowderPatternDiffraction::CalcFrozenBMatrix()const { VFN_DEBUG_MESSAGE("PowderPatternDiffraction::CalcFrozenBMatrix()", 10) REAL a,b,c,alpha,beta,gamma;//direct space parameters REAL aa,bb,cc,alphaa,betaa,gammaa;//reciprocal space parameters POSSIBLY_UNUSED(alphaa); REAL v;//volume of the unit cell a=mFrozenLatticePar(0); b=mFrozenLatticePar(1); c=mFrozenLatticePar(2); alpha=mFrozenLatticePar(3); beta=mFrozenLatticePar(4); gamma=mFrozenLatticePar(5); v=sqrt(1-cos(alpha)*cos(alpha)-cos(beta)*cos(beta)-cos(gamma)*cos(gamma) +2*cos(alpha)*cos(beta)*cos(gamma)); aa=sin(alpha)/a/v; bb=sin(beta )/b/v; cc=sin(gamma)/c/v; alphaa=acos( (cos(beta )*cos(gamma)-cos(alpha))/sin(beta )/sin(gamma) ); betaa =acos( (cos(alpha)*cos(gamma)-cos(beta ))/sin(alpha)/sin(gamma) ); gammaa=acos( (cos(alpha)*cos(beta )-cos(gamma))/sin(alpha)/sin(beta ) ); mFrozenBMatrix = aa , bb*cos(gammaa) , cc*cos(betaa) , 0 , bb*sin(gammaa) ,-cc*sin(betaa)*cos(alpha), 0 , 0 ,1/c; } void PowderPatternDiffraction::PrepareIntegratedProfile()const { this->CalcPowderReflProfile(); this->GetNbReflBelowMaxSinThetaOvLambda(); if( (mClockIntegratedProfileFactor>mClockProfileCalc) &&(mClockIntegratedProfileFactor>mpParentPowderPattern->GetIntegratedProfileLimitsClock()) &&(mClockIntegratedProfileFactor>mClockNbReflUsed)) return; VFN_DEBUG_ENTRY("PowderPatternDiffraction::PrepareIntegratedProfile()",7) TAU_PROFILE("PowderPatternDiffraction::PrepareIntegratedProfile()","void ()",TAU_DEFAULT); const CrystVector_long *pMin=&(mpParentPowderPattern->GetIntegratedProfileMin()); const CrystVector_long *pMax=&(mpParentPowderPattern->GetIntegratedProfileMax()); const long numInterval=pMin->numElements(); vector< map > vIntegratedProfileFactor; vIntegratedProfileFactor.resize(mNbReflUsed); vector< map >::iterator pos1; pos1=vIntegratedProfileFactor.begin(); mIntegratedProfileFactor.resize(mNbReflUsed); vector< pair >::iterator pos2; pos2=mIntegratedProfileFactor.begin(); for(long i=0;iclear(); long firstInterval=numInterval; for(long j=0;j(*pMin)(j) ? first0:(*pMin)(j); const long last = last0 <(*pMax)(j) ? last0 :(*pMax)(j); if((first<=last) && (mvReflProfile[i].profile.size()>0)) { if(firstInterval>j) firstInterval=j; if(pos1->find(j) == pos1->end()) (*pos1)[j]=0.; REAL *fact = &((*pos1)[j]);//this creates the 'j' entry if necessary const REAL *p2 = mvReflProfile[i].profile.data()+(first-first0); //cout << i<<","<first=firstInterval; pos2->second.resize(pos1->size()); REAL *pFact=pos2->second.data(); for(map::const_iterator pos=pos1->begin();pos!=pos1->end();++pos) *pFact++ = pos->second; pos1++; pos2++; } mClockIntegratedProfileFactor.Click(); #ifdef __DEBUG__ if(gVFNDebugMessageLevel<3) { unsigned long i=0; for(vector< pair >::const_iterator pos=mIntegratedProfileFactor.begin(); pos!=mIntegratedProfileFactor.end();++pos) { cout <<"Integrated profile factors for reflection #"<second.numElements();++j) cout << j+pos->first<<"("<second(j)<<") "; cout< gPowderPatternRegistry("List of all PowderPattern objects"); PowderPattern::PowderPattern(): mIsXAscending(true),mNbPoint(0), mXZero(0.),m2ThetaDisplacement(0.),m2ThetaTransparency(0.), mDIFC(48277.14),mDIFA(-6.7), mScaleFactor(20),mMuR(0), mUseFastLessPreciseFunc(false), mStatisticsExcludeBackground(false),mMaxSinThetaOvLambda(10),mNbPointUsed(0) { mScaleFactor=1; mSubObjRegistry.SetName("SubObjRegistry for a PowderPattern object"); mPowderPatternComponentRegistry.SetName("Powder Pattern Components"); this->AddSubRefObj(mRadiation); this->Init(); gPowderPatternRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); mClockMaster.AddChild(mClockPowderPatternPar); mClockMaster.AddChild(mClockNbPointUsed); mClockMaster.AddChild(mClockPowderPatternXCorr); mClockMaster.AddChild(mClockScaleFactor); mClockMaster.AddChild(mClockPowderPatternRadiation); mClockMaster.AddChild(mClockCorrAbs); } PowderPattern::PowderPattern(const PowderPattern &old): mIsXAscending(old.mIsXAscending),mNbPoint(old.mNbPoint), mRadiation(old.mRadiation), mXZero(old.mXZero),m2ThetaDisplacement(old.m2ThetaDisplacement), m2ThetaTransparency(old.m2ThetaTransparency), mDIFC(old.mDIFC),mDIFA(old.mDIFA), mPowderPatternComponentRegistry(old.mPowderPatternComponentRegistry), mScaleFactor(old.mScaleFactor),mMuR(old.mMuR), mUseFastLessPreciseFunc(old.mUseFastLessPreciseFunc), mStatisticsExcludeBackground(old.mStatisticsExcludeBackground), mMaxSinThetaOvLambda(old.mMaxSinThetaOvLambda),mNbPointUsed(old.mNbPointUsed) { mX=old.mX; this->Init(); mSubObjRegistry.SetName("SubObjRegistry for a PowderPattern :"+mName); gPowderPatternRegistry.Register(*this); gTopRefinableObjRegistry.Register(*this); this->AddSubRefObj(mRadiation); mClockMaster.AddChild(mClockPowderPatternPar); mClockMaster.AddChild(mClockNbPointUsed); mClockMaster.AddChild(mClockPowderPatternXCorr); mClockMaster.AddChild(mClockScaleFactor); mClockMaster.AddChild(mClockPowderPatternRadiation); } PowderPattern::~PowderPattern() { gPowderPatternRegistry.DeRegister(*this); for(int i=0;iRemoveSubRefObj(mPowderPatternComponentRegistry.GetObj(i)); delete &(mPowderPatternComponentRegistry.GetObj(i)); } gTopRefinableObjRegistry.DeRegister(*this); } const string& PowderPattern::GetClassName() const { const static string className="PowderPattern"; return className; } void PowderPattern::AddPowderPatternComponent(PowderPatternComponent &comp) { VFN_DEBUG_ENTRY("PowderPattern::AddPowderPatternComponent():"<AddSubRefObj(comp); comp.RegisterClient(*this); mClockPowderPatternCalc.Reset(); mClockIntegratedFactorsPrep.Reset(); mPowderPatternComponentRegistry.Register(comp); //:TODO: check if there are enough scale factors //mScaleFactor.resizeAndPreserve(mPowderPatternComponentRegistry.GetNb()); mScaleFactor(mPowderPatternComponentRegistry.GetNb()-1)=1.; mClockScaleFactor.Click(); if(comp.IsScalable()) {//Init refinable parameter RefinablePar tmp("Scale_"+comp.GetName(),mScaleFactor.data()+mPowderPatternComponentRegistry.GetNb()-1, 1e-10,1e10,gpRefParTypeScattDataScale,REFPAR_DERIV_STEP_RELATIVE, false,true,true,false,1.); tmp.SetGlobalOptimStep(0.); tmp.AssignClock(mClockScaleFactor); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } //this->UpdateDisplay(); VFN_DEBUG_EXIT("PowderPattern::AddPowderPatternComponent():"< mX(0)) mIsXAscending=true; else mIsXAscending=false; VFN_DEBUG_MESSAGE("PowderPattern::SetPowderPatternX() is ascending="<IsBeingRefined()) this->CalcNbPointUsed(); return mNbPointUsed; } const RefinableObjClock& PowderPattern::GetClockNbPointUsed()const{return mClockNbPointUsed;} void PowderPattern::SetRadiation(const Radiation &radiation) { mRadiation=radiation; mClockPowderPatternRadiation.Click(); } const Radiation& PowderPattern::GetRadiation()const {return mRadiation;} Radiation& PowderPattern::GetRadiation() {return mRadiation;} void PowderPattern::SetRadiationType(const RadiationType rad) { mRadiation.SetRadiationType(rad); } RadiationType PowderPattern::GetRadiationType()const {return mRadiation.GetRadiationType();} void PowderPattern::SetWavelength(const REAL lambda) { VFN_DEBUG_MESSAGE("PowderPattern::SetWavelength(lambda)",3) mRadiation.SetWavelength(lambda); } void PowderPattern::SetWavelength(const string &XRayTubeElementName,const REAL alpha12ratio) { VFN_DEBUG_MESSAGE("PowderPattern::SetWavelength(wavelength)",3) mRadiation.SetWavelength(XRayTubeElementName,alpha12ratio); } REAL PowderPattern::GetWavelength()const{return mRadiation.GetWavelength()(0);} const CrystVector_REAL& PowderPattern::GetPowderPatternCalc()const { this->CalcPowderPattern(); return mPowderPatternCalc; } std::map& PowderPattern::GetPowderPattern_FullDeriv(std::set &vPar) { this->CalcPowderPattern_FullDeriv(vPar); return mPowderPattern_FullDeriv; } const CrystVector_REAL& PowderPattern::GetPowderPatternObs()const { return mPowderPatternObs; } const CrystVector_REAL& PowderPattern::GetPowderPatternObsSigma()const { return mPowderPatternObsSigma; } const CrystVector_REAL& PowderPattern::GetPowderPatternVariance()const { return mPowderPatternVariance; } const CrystVector_REAL& PowderPattern::GetPowderPatternWeight()const { return mPowderPatternWeight; } REAL PowderPattern::GetPowderPatternXMin()const { if(mNbPoint==0) return 0;//:KLUDGE: ? if(true==mIsXAscending) return mX(0); return mX(mNbPoint-1); } REAL PowderPattern::GetPowderPatternXStep()const { if(mNbPoint==0) return 0;//:KLUDGE: ? return abs((-mX(0)+mX(mNbPoint-1))/(mNbPoint-1)); } REAL PowderPattern::GetPowderPatternXMax()const { if(mNbPoint==0) return 0;//:KLUDGE: ? if(true==mIsXAscending) return mX(mNbPoint-1); return mX(0); } const CrystVector_REAL& PowderPattern::GetPowderPatternX()const { return mX; } const CrystVector_REAL& PowderPattern::GetChi2Cumul(const int m)const { VFN_DEBUG_ENTRY("PowderPattern::GetChi2Cumul()",3) mChi2Cumul.resize(mNbPoint); int mode = m; if((mode!=0) && (mode!=1)) mode = mOptProfileIntegration.GetChoice(); if(0 == mode) { this->CalcPowderPatternIntegrated(); if(mNbIntegrationUsed==0) mChi2Cumul=0; else { const REAL *pObs=mIntegratedObs.data(); const REAL *pCalc=mPowderPatternIntegratedCalc.data(); const REAL *pWeight; if(mIntegratedWeight.numElements()==0) pWeight=mIntegratedWeightObs.data(); else pWeight=mIntegratedWeight.data(); REAL *pC2Cu=mChi2Cumul.data(); for(int i=0;i(int)mNbPointUsed) { for(unsigned int i=mIntegratedPatternMin(j);iCalcPowderPattern(); const REAL *pObs=mPowderPatternObs.data(); const REAL *pCalc=mPowderPatternCalc.data(); const REAL *pWeight=mPowderPatternWeight.data(); REAL *pC2Cu=mChi2Cumul.data(); REAL chi2cumul=0,tmp; for(unsigned int i=0;iX2Pixel(this->X2XCorr(x0)); } REAL PowderPattern::X2Pixel(const REAL x)const { //:TODO: faster if the step is actually constant. // Step may not be constant, so we guess twice before step-search REAL pixx; if(mIsXAscending==false) { VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel()",1) long pix=(long)(mNbPoint-1-(x-this->GetPowderPatternXMin())/this->GetPowderPatternXStep()); if((pix>0)&&(pix<((long)mNbPoint-1))) { // Why floor() and ceil() don't return a bloody integer is beyond me const REAL localStep=mX(pix)-mX(pix+1); if(localStep>0) pix -= (long)((x-mX(pix))/localStep); } VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<((long)mNbPoint-2))pix=(long)mNbPoint-2; VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<=x) break; if(pix==0) break; } } else { for(;;pix++) { if(mX(pix)<=x) {pix--;break;} if(pix==((long)mNbPoint-2)) break; } } // This assumes step is at least localy constant... VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<GetPowderPatternXMin()<<","<GetPowderPatternXMax(),1) long pix=(long)((x-this->GetPowderPatternXMin())/this->GetPowderPatternXStep()); if((pix>0)&&(pix<((long)mNbPoint-1))) { // Why floor() and ceil() don't return a bloody integer is beyond me const REAL localStep=mX(pix+1)-mX(pix); if(localStep>0) pix += (long)((x-mX(pix))/localStep); } VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<((long)mNbPoint-2))pix=(long)mNbPoint-2; VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<=x) {pix-- ;break;} if(pix==((long)mNbPoint-2)) break; } } VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<((long)mNbPoint-2))pix=(long)mNbPoint-2; // This assumes step is at least localy constant... const REAL localStep=mX(pix+1)-mX(pix); VFN_DEBUG_MESSAGE("PowderPattern::X2Pixel():"<> min >> step >> max; min *= DEG2RAD; max *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,(long)((max-min)/step+1.001)); VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternFullprof() :"\ << " 2Theta min=" << min*RAD2DEG << " 2Theta max=" << max*RAD2DEG \ << " NbPoints=" << mNbPoint,5) mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize (mNbPoint); mPowderPatternWeight.resize(mNbPoint); char tmpComment[200]; fin.getline(tmpComment,100); //if(""==mName) mName.append(tmpComment); for(unsigned long i=0;i> mPowderPatternObs(i); fin.close(); this->SetSigmaToSqrtIobs(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,max*RAD2DEG,step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportFullProfPattern():finished:"<> min >> step >> max; min *= DEG2RAD; max *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,(unsigned long)((max-min)/step+1.001)); VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternPSI_DMC() :"\ << " 2Theta min=" << min*RAD2DEG << " 2Theta max=" << max*RAD2DEG \ << " NbPoints=" << mNbPoint,5) mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize (mNbPoint); mPowderPatternWeight.resize(mNbPoint); fin.getline(tmpComment,100); //if(""==mName) mName.append(tmpComment); for(unsigned long i=0;i> mPowderPatternObs(i); for(unsigned long i=0;i> mPowderPatternObsSigma(i); fin.close(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,max*RAD2DEG,step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternPSI_DMC():finished",5) } void PowderPattern::ImportPowderPatternILL_D1A5(const string &filename) { VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternILL_D1AD2B() : \ from file : "+filename,5) ifstream fin(filename.c_str()); if(!fin) { throw ObjCrystException("PowderPattern::ImportPowderPatternILL_D1AD2B() : \ Error opening file for input:"+filename); } //Skip the first three lines char tmpComment[200]; fin.getline(tmpComment,190); fin.getline(tmpComment,190); fin.getline(tmpComment,190); fin >> mNbPoint; fin.getline(tmpComment,190); REAL min,step; fin >> min >> step; min *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,mNbPoint); VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternILL_D1AD2B() :"\ << " 2Theta min=" << min*RAD2DEG << " 2Theta max=" << min*RAD2DEG+mNbPoint*step*RAD2DEG \ << " NbPoints=" << mNbPoint,5) mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize (mNbPoint); mPowderPatternWeight.resize(mNbPoint); //if(""==mName) mName.append(tmpComment); for(unsigned long i=0;i> mPowderPatternObs(i); for(unsigned long i=0;i> mPowderPatternObsSigma(i); fin.close(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,(min+step*(mNbPoint-1))*RAD2DEG, step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternILL_D1AD2B():finished",5) } void PowderPattern::ImportPowderPatternXdd(const string &filename) { VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternXdd():from file :" \ +filename,5) ifstream fin (filename.c_str()); if(!fin) { throw ObjCrystException("PowderPattern::ImportPowderPatternXdd() : \ Error opening file for input:"+filename); } char tmpComment[200]; fin.getline(tmpComment,100); //if(""==mName) mName.append(tmpComment); REAL min,max,step,tmp; fin >> min >> step >> max; min *= DEG2RAD; max *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,(long)((max-min)/step+1.001)); mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize(mNbPoint); mPowderPatternCalc.resize(mNbPoint); mPowderPatternWeight.resize(mNbPoint); mPowderPatternWeight=1.; fin >> tmp; //Count time fin >> tmp; //unused fin >> tmp; //unused (wavelength?) for(unsigned long i=0;i> mPowderPatternObs(i); fin.close(); this->SetSigmaToSqrtIobs(); this->SetWeightToInvSigmaSq(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,max*RAD2DEG,step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("DiffractionDataPowder::ImportXddPattern() :finished",5) } void PowderPattern::ImportPowderPatternSietronicsCPI(const string &filename) { VFN_DEBUG_ENTRY("PowderPattern::ImportPowderPatternSietronicsCPI():from file :" \ +filename,5) ifstream fin (filename.c_str()); if(!fin) { throw ObjCrystException("PowderPattern::ImportPowderPatternSietronicsCPI() : \ Error opening file for input:"+filename); } char tmpComment[300]; fin.getline(tmpComment,100); VFN_DEBUG_MESSAGE(" ->Discarded comment :"<> min >> max >> step; min *= DEG2RAD; max *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,(long)((max-min)/step+1.001)); mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize(mNbPoint); mPowderPatternCalc.resize(mNbPoint); mPowderPatternWeight.resize(mNbPoint); mPowderPatternWeight=1.; //Following lines are ignored (no fixed format ?) string str; do { fin>>str; VFN_DEBUG_MESSAGE(" ->Read :"<> mPowderPatternObs(i); fin.close(); this->SetSigmaToSqrtIobs(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,max*RAD2DEG,step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_EXIT("DiffractionDataPowder::ImportPowderPatternSietronicsCPI()",5) } void PowderPattern::ImportPowderPattern2ThetaObsSigma(const string &filename,const int nbSkip) { VFN_DEBUG_MESSAGE("DiffractionDataPowder::ImportPowderPattern2ThetaObsSigma():from:" \ +filename,5) ifstream fin (filename.c_str()); if(!fin) { throw ObjCrystException("PowderPattern::ImportPowderPattern2ThetaObsSigma():\ Error opening file for input:"+filename); } {//Get rid of first lines char tmpComment[200]; for(int i=0;i> mX (mNbPoint); fin >> mPowderPatternObs (mNbPoint); fin >> mPowderPatternObsSigma(mNbPoint); //cout << mX (mNbPoint)<<" " // << mPowderPatternObs (mNbPoint)<<" " // << mPowderPatternObsSigma(mNbPoint)<SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,this->GetPowderPatternXMin()*RAD2DEG, this->GetPowderPatternXMax()*RAD2DEG, this->GetPowderPatternXStep()*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPattern2ThetaObsSigma()\ :finished: "<> mX(mNbPoint); fin >> mPowderPatternObs (mNbPoint); mPowderPatternObsSigma(mNbPoint) =sqrt(mPowderPatternObs(mNbPoint)); if(!fin) break; mNbPoint++; if( (mNbPoint%500)==0) { mX.resizeAndPreserve(mNbPoint+500); mPowderPatternObs.resizeAndPreserve(mNbPoint+500); mPowderPatternObsSigma.resizeAndPreserve(mNbPoint+500); } } while(fin.eof() == false); fin.close(); mX.resizeAndPreserve (mNbPoint); mPowderPatternObs.resizeAndPreserve (mNbPoint); mPowderPatternObsSigma.resizeAndPreserve(mNbPoint); mPowderPatternWeight.resize(mNbPoint); mX *= DEG2RAD; this->SetSigmaToSqrtIobs(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,this->GetPowderPatternXMin()*RAD2DEG, this->GetPowderPatternXMax()*RAD2DEG, this->GetPowderPatternXStep()*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPattern2ThetaObs():finished",5) } void PowderPattern::ImportPowderPatternMultiDetectorLLBG42(const string &filename) { //Sample 4: NaY + CF2=CCL2 T=20K, Lambda: 2.343 A. // 100 0 0.100 70 0 0 // 3.000 // 500000. 12000. 0.00 0.00 //70 570369 569668 562868 532769 527469 495669 481969 452767 429468 4132 //68 393269 372067 353769 337068 328268 310270 299469 296470 294668 2780 //... //14 255814 282714 274014 281314 300314 302714 301114 298014 313214 3097 //14 286914 295714 305214 300714 288311 295511 288511 3024 8 2937 7 2883 // 7 2905 7 2895 7 2767 7 2777 7 2758 7 2495 7 2507 7 2496 7 2382 7 2329 // 7 2542 7 2415 7 2049 7 2389 7 2270 7 2157 6 2227 6 2084 3 1875 2 2094 // 1 1867 // -1000 // -10000 VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternMultiDetectorLLBG42() : \ from file : "+filename,5) ifstream fin(filename.c_str()); if(!fin) { throw ObjCrystException("PowderPattern::ImportPowderPatternMultiDetectorLLBG42() : \ Error opening file for input:"+filename); } string str; getline(fin,str); float junk; REAL min,step; fin >>junk>>junk>>step>>junk>>junk>>junk>>min>>junk>>junk>>junk>>junk; min *= DEG2RAD; step *= DEG2RAD; VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternMultiDetectorLLBG42() :"\ << " 2Theta min=" << min*RAD2DEG << " 2Theta step=" << step*RAD2DEG,5) mPowderPatternObs.resize (500); mPowderPatternObsSigma.resize (500); getline(fin,str);//finish reading line float tmp; string sub; float ct,iobs; mNbPoint=0; for(;;) { getline(fin,str); sscanf(str.c_str(),"%f",&tmp); if(tmp<0) break; const unsigned int nb=str.length()/8; for(unsigned int i=0;iSetPowderPatternPar(min,step,mNbPoint); //exit(1); mPowderPatternObs.resizeAndPreserve (mNbPoint); mPowderPatternObsSigma.resizeAndPreserve (mNbPoint); mPowderPatternWeight.resizeAndPreserve(mNbPoint); fin.close(); this->SetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,mX(mNbPoint-1)*RAD2DEG,step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternMultiDetectorLLBG42():finished:"<> min >> step >> max; min *= DEG2RAD; max *= DEG2RAD; step *= DEG2RAD; this->SetPowderPatternPar(min,step,(long)((max-min)/step+1.001)); VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternFullprof4() :"\ << " 2Theta min=" << min*RAD2DEG << " 2Theta max=" << max*RAD2DEG \ << " NbPoints=" << mNbPoint,5) mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize (mNbPoint); mPowderPatternWeight.resize(mNbPoint); string str; getline(fin,str);//read end of first line unsigned ct=0; unsigned ctSig=0; float line[10]; for(;ctSetWeightToInvSigmaSq(); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,min*RAD2DEG,max*RAD2DEG, step*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportFullProfPattern4():finished:"<> mX (mNbPoint); fin >> mPowderPatternObs (mNbPoint); fin >> mPowderPatternObsSigma(mNbPoint); //cout << mX (mNbPoint)<<" " // << mPowderPatternObs (mNbPoint)<<" " // << mPowderPatternObsSigma(mNbPoint)<SetPowderPatternX(mX); this->SetWeightToInvSigmaSq(); this->SetRadiationType(RAD_NEUTRON); this->GetRadiation().SetWavelengthType(WAVELENGTH_TOF); mClockPowderPatternPar.Click(); this->UpdateDisplay(); { char buf [200]; sprintf(buf,"Imported TOF powder pattern: %d points, TOF=%7.3f -> %7.3f", (int)mNbPoint,this->GetPowderPatternXMin(), this->GetPowderPatternXMax()); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_MESSAGE("PowderPattern::ImportPowderPatternTOF_ISIS_XYSigma()\ :finished: "<GetName()=="Change Me!") this->SetName(title); } //BANK 1 38101 7620 CONST 200.00 0.10 0 0 ESD int numBank,nbRecords; string binType, type; float bcoeff[4]; //string line; char line[81]; char bank[5]; do { fin.getline(line,80); while(isprint(fin.peek())==false) { if(fin.eof()) break; fin.get(); } sscanf(line,"%4s",bank); if(fin.eof()) throw ObjCrystException("PowderPattern::ImportPowderPatternGSAS():\ Could not find BANK statement !! In file: "+filename); } while(string(bank)!=string("BANK")); { line[80]='\0'; char binTypeC[20],typeC[20]; sscanf(line,"%4s%d %ld %d %s %f %f %f %f %s",bank,&numBank,&mNbPoint,&nbRecords, binTypeC,&bcoeff[0],&bcoeff[1],&bcoeff[2],&bcoeff[3],typeC); binType=binTypeC; type=typeC; } if(binType=="CONST") binType="CONS"; if((type!="ALT")&&(type!="ESD")) type="STD"; cout<<"BANK #"<SetPowderPatternPar(bcoeff[0]*DEG2RAD/100,bcoeff[1]*DEG2RAD/100,mNbPoint); string sub; unsigned long point=0; REAL iobs,isig; string substr; for(long i=0;i> iobs; substr=string(line).substr(j*16+8 ,8); istringstream(substr) >> isig; mPowderPatternObs(point)=iobs; mPowderPatternObsSigma(point++)=isig; if(point==mNbPoint) break; } if(point==mNbPoint) break; } importOK=true; } if((binType=="CONS") && (type=="STD")) { this->SetPowderPatternPar(bcoeff[0]*DEG2RAD/100,bcoeff[1]*DEG2RAD/100,mNbPoint); unsigned long point=0; REAL iobs; int nc; string substr; for(long i=0;i> iobs; mPowderPatternObs(point)=iobs; mPowderPatternObsSigma(point++)=sqrt(iobs)/sqrt((REAL)nc); if(point==mNbPoint) break; } if(point==mNbPoint) break; } importOK=true; } if((binType=="RALF") && (type=="ALT")) { this->SetRadiationType(RAD_NEUTRON); this->GetRadiation().SetWavelengthType(WAVELENGTH_TOF); mClockPowderPatternPar.Click(); unsigned long point=0; REAL x,iobs,iobssigma; string substr; for(long i=0;i> x; substr=string(line).substr(j*20+8 ,7); istringstream(substr) >> iobs; substr=string(line).substr(j*20+15,5); istringstream(substr) >> iobssigma; mPowderPatternObs(point)=iobs; mPowderPatternObsSigma(point)=iobssigma; mX(point)=x/32; if(++point==mNbPoint) break; } if(point==mNbPoint) break; } // Reverse order of arrays, so that we are in ascending order of sin(theta)/lambda REAL tmp; for(unsigned long i=0;i<(mNbPoint/2);i++) { tmp=mX(i); mX(i)=mX(mNbPoint-1-i); mX(mNbPoint-1-i)=tmp; tmp=mPowderPatternObs(i); mPowderPatternObs(i)=mPowderPatternObs(mNbPoint-1-i); mPowderPatternObs(mNbPoint-1-i)=tmp; tmp=mPowderPatternObsSigma(i); mPowderPatternObsSigma(i)=mPowderPatternObsSigma(mNbPoint-1-i); mPowderPatternObsSigma(mNbPoint-1-i)=tmp; } importOK=true; } fin.close(); if(!importOK) { mNbPoint=0; mPowderPatternObs.resize (mNbPoint); mPowderPatternObsSigma.resize(mNbPoint); mX.resize(mNbPoint); throw ObjCrystException("PowderPattern::ImportPowderPatternGSAS(): Sorry, \ this type of format is not handled yet (send an example file to the Fox author)!:"+filename); } mPowderPatternWeight.resize(mNbPoint); this->SetPowderPatternX(mX); this->SetWeightToInvSigmaSq(); this->UpdateDisplay(); if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, tof=%7.3f us-> %7.3f us", (int)mNbPoint,this->GetPowderPatternXMin(), this->GetPowderPatternXMax()); (*fpObjCrystInformUser)((string)buf); } else { char buf [200]; sprintf(buf,"Imported powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,this->GetPowderPatternXMin()*RAD2DEG, this->GetPowderPatternXMax()*RAD2DEG, this->GetPowderPatternXStep()*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } VFN_DEBUG_EXIT("PowderPattern::ImportPowderPatternGSAS():file:"<::const_iterator pos=cif.mvData.begin();pos!=cif.mvData.end();++pos) if(pos->second.mPowderPatternObs.size()>10) { mNbPoint=pos->second.mPowderPatternObs.size(); mX.resize(mNbPoint); mPowderPatternObs.resize(mNbPoint); mPowderPatternObsSigma.resize(mNbPoint); mPowderPatternWeight.resize(mNbPoint); if(pos->second.mDataType==WAVELENGTH_TOF) { this->SetRadiationType(RAD_NEUTRON); this->GetRadiation().SetWavelengthType(WAVELENGTH_TOF); mClockPowderPatternPar.Click(); } else this->GetRadiation().SetWavelength(pos->second.mWavelength); for(unsigned long i=0;isecond.mPowderPatternObs[i]; mX(i)=pos->second.mPowderPatternX[i]; mPowderPatternObsSigma(i)=pos->second.mPowderPatternSigma[i]; } this->SetWeightToInvSigmaSq(); this->SetPowderPatternX(mX); } VFN_DEBUG_EXIT("PowderPattern::ImportPowderPatternCIF():file:",5) } void PowderPattern::SetPowderPatternObs(const CrystVector_REAL& obs) { VFN_DEBUG_MESSAGE("PowderPattern::SetPowderPatternObs()",5) if((unsigned long)obs.numElements() != mNbPoint) { throw(ObjCrystException("PowderPattern::SetPowderPatternObs(vect): The \ supplied vector of observed intensities does not have the expected number of points!")); } mPowderPatternObs=obs; mPowderPatternObsSigma.resize(mPowderPatternObs.numElements()); mPowderPatternWeight.resize(mNbPoint); this->SetSigmaToSqrtIobs(); this->SetWeightToInvSigmaSq(); mClockIntegratedFactorsPrep.Reset(); { char buf [200]; sprintf(buf,"Changed powder pattern: %d points, 2theta=%7.3f -> %7.3f, step=%6.3f", (int)mNbPoint,mX(0)*RAD2DEG,mX(mNbPoint-1)*RAD2DEG, (mX(mNbPoint-1)-mX(0))/(mNbPoint-1)*RAD2DEG); (*fpObjCrystInformUser)((string)buf); } } void PowderPattern::SavePowderPattern(const string &filename) const { VFN_DEBUG_MESSAGE("PowderPattern::SavePowderPattern",5) this->CalcPowderPattern(); ofstream out(filename.c_str()); CrystVector_REAL ttheta; ttheta=mX; if(this->GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) ttheta *= RAD2DEG; CrystVector_REAL diff; diff=mPowderPatternObs; diff-=mPowderPatternCalc; out << "# 2Theta/TOF Iobs ICalc Iobs-Icalc Weight Comp0" << endl; out << FormatVertVector(ttheta, mPowderPatternObs, mPowderPatternCalc, diff,mPowderPatternWeight, mPowderPatternComponentRegistry.GetObj(0).mPowderPatternCalc,16,8); out.close(); VFN_DEBUG_MESSAGE("DiffractionDataPowder::SavePowderPattern:End",3) } void PowderPattern::PrintObsCalcData(ostream&os)const { VFN_DEBUG_MESSAGE("DiffractionDataPowder::PrintObsCalcData()",5); CrystVector_REAL ttheta; ttheta=mX; if(this->GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) ttheta *= RAD2DEG; os << "PowderPattern : " << mName <(ttheta,mPowderPatternObs,mPowderPatternObsSigma, mPowderPatternCalc,mPowderPatternWeight,16,8); // mPowderPatternComponentRegistry.GetObj(0).mPowderPatternCalc,12,4); } REAL PowderPattern::GetR()const { if( (0==this->GetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { return 0; } this->CalcPowderPattern(); TAU_PROFILE("PowderPattern::GetR()","void ()",TAU_DEFAULT); REAL tmp1=0.; REAL tmp2=0.; unsigned long maxPoints=mNbPointUsed; if( (true==mStatisticsExcludeBackground) &&(mPowderPatternBackgroundCalc.numElements()>0)) { const REAL *p1, *p2, *p3; p1=mPowderPatternCalc.data(); p2=mPowderPatternObs.data(); p3=mPowderPatternBackgroundCalc.data(); const long nbExclude=mExcludedRegionMinX.numElements(); if(0==nbExclude) { VFN_DEBUG_MESSAGE("PowderPattern::GetR():Exclude Backgd",4); for(unsigned long i=0;iX2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>maxPoints) break; if(max>maxPoints)max=maxPoints; for(;iX2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>maxPoints) break; if(max>maxPoints)max=maxPoints; for(;iGetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { return 0; } this->CalcPowderPattern(); this->PrepareIntegratedRfactor(); VFN_DEBUG_ENTRY("PowderPattern::GetIntegratedR()",4); TAU_PROFILE("PowderPattern::GetIntegratedR()","void ()",TAU_DEFAULT); REAL tmp1=0.; REAL tmp2=0.; const long numInterval=mIntegratedPatternMin.numElements(); if( (true==mStatisticsExcludeBackground) &&(mPowderPatternBackgroundCalc.numElements()>0)) { const REAL *p1, *p2, *p3; CrystVector_REAL integratedCalc(numInterval); integratedCalc=0; CrystVector_REAL backgdCalc(numInterval); backgdCalc=0; REAL *pp1=integratedCalc.data(); REAL *pp2=backgdCalc.data(); for(int i=0;i(mPowderPatternObs, // mPowderPatternCalc, // mPowderPatternWeight); REAL tmp1=0.; REAL tmp2=0.; unsigned long maxPoints=mNbPointUsed; if( (true==mStatisticsExcludeBackground) &&(mPowderPatternBackgroundCalc.numElements()>0)) { VFN_DEBUG_MESSAGE("PowderPattern::GetRw():Exclude Backgd",3); const REAL *p1, *p2, *p3, *p4; p1=mPowderPatternCalc.data(); p2=mPowderPatternObs.data(); p3=mPowderPatternBackgroundCalc.data(); p4=mPowderPatternWeight.data(); const long nbExclude=mExcludedRegionMinX.numElements(); if(0==nbExclude) { for(unsigned long i=0;iX2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>maxPoints) break; if(max>maxPoints)max=maxPoints; for(;iX2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>maxPoints) break; if(max>maxPoints)max=maxPoints; for(;i0)) { const REAL *p1, *p2, *p3, *p4; CrystVector_REAL integratedCalc(numInterval); integratedCalc=0; CrystVector_REAL backgdCalc(numInterval); backgdCalc=0; REAL *pp1=integratedCalc.data(); REAL *pp2=backgdCalc.data(); for(int i=0;i"<GetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { mChi2=0.; return mChi2; } this->CalcNbPointUsed(); if(mClockChi2>mClockMaster) return mChi2; this->CalcPowderPattern(); if( (mClockChi2>mClockPowderPatternPar) &&(mClockChi2>mClockScaleFactor) &&(mClockChi2>mClockPowderPatternCalc)) return mChi2; // We want the best scale factor this->FitScaleFactorForRw(); TAU_PROFILE("PowderPattern::GetChi2()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPattern::GetChi2()",3); const unsigned long maxPoints=mNbPointUsed; mChi2=0.; mChi2LikeNorm=0.; VFN_DEBUG_MESSAGE("PowderPattern::GetChi2()Integrated profiles",3); const REAL * RESTRICT p1, * RESTRICT p2, * RESTRICT p3; p1=mPowderPatternCalc.data(); p2=mPowderPatternObs.data(); p3=mPowderPatternWeight.data(); const long nbExclude=mExcludedRegionMinX.numElements(); if(0==nbExclude) { for(unsigned long i=0;iX2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>maxPoints) break; if(max>maxPoints)max=maxPoints; for(;i0) weightProd *= *p3; p1++;p2++;p3++; if(++i == mNbIntegrationUsed) break; } mIntegratedChi2LikeNorm -= log(weightProd); weightProd=1.; } mIntegratedChi2LikeNorm/=2; VFN_DEBUG_MESSAGE("Chi^2="< Number of Scale Factors:"<X2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;lX2Pixel(mExcludedRegionMinX(k))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(k))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;lX2Pixel(mExcludedRegionMinX(k))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(k))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;l Old:"<GetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { return ; } this->CalcPowderPattern(); this->PrepareIntegratedRfactor(); VFN_DEBUG_ENTRY("PowderPattern::FitScaleFactorForIntegratedR()",3); TAU_PROFILE("PowderPattern::FitScaleFactorForIntegratedR()","void ()",TAU_DEFAULT); // Which components are scalable ? mScalableComponentIndex.resize(mPowderPatternComponentRegistry.GetNb()); int nbScale=0; for(int i=0;i Number of Scale Factors:"<1) { const REAL *p1; REAL *p2=backdIntegrated.data(); for(int j=0;j(integratedCalc[0],mIntegratedObs,mIntegratedWeight,backdIntegrated)<(integratedCalc[0],mIntegratedObs,mIntegratedWeight)< Old:"<GetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { return ; } TAU_PROFILE("PowderPattern::FitScaleFactorForRw()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPattern::FitScaleFactorForRw()",3); this->CalcPowderPattern(); //:TODO: take into account excluded regions... // Which components are scalable ? mScalableComponentIndex.resize(mPowderPatternComponentRegistry.GetNb()); int nbScale=0; for(int i=0;i Number of Scale Factors:"<X2Pixel(mExcludedRegionMinX(j))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;lX2Pixel(mExcludedRegionMinX(k))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(k))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;lX2Pixel(mExcludedRegionMinX(k))); max=(unsigned long)ceil (this->X2Pixel(mExcludedRegionMaxX(k))); if(min>mNbPointUsed) break; if(max>mNbPointUsed)max=mNbPointUsed; //! min is the *beginning* of the excluded region for(;l Old:"<GetPowderPatternObs().numElements()) ||(0==GetNbPowderPatternComponent())) { return ; } this->CalcPowderPatternIntegrated(); if(mClockScaleFactor>mClockPowderPatternIntegratedCalc)return; VFN_DEBUG_ENTRY("PowderPattern::FitScaleFactorForIntegratedRw()",3); TAU_PROFILE("PowderPattern::FitScaleFactorForIntegratedRw()","void ()",TAU_DEFAULT); // Which components are scalable ? Which scalable calculated components have a non-null variance ? mScalableComponentIndex.resize(mPowderPatternComponentRegistry.GetNb()); CrystVector_REAL vScalableVarianceIndex(mPowderPatternComponentRegistry.GetNb()); int nbScale=0; int nbVarCalc=0; for(int i=0;inumElements()) vScalableVarianceIndex(nbVarCalc++)=i; } } VFN_DEBUG_MESSAGE("-> Number of Scale Factors:"<data(); const REAL * RESTRICT p1v=mIntegratedVarianceObs.data(); const REAL * RESTRICT p2v=mPowderPatternComponentRegistry.GetObj(mScalableComponentIndex(0)) .GetPowderPatternIntegratedCalcVariance().first->data(); if(mPowderPatternBackgroundIntegratedCalc.numElements()<=1) { for(unsigned long k=mNbIntegrationUsed;k>0;k--) { a += *p2v * *p1 * *p2; b += *p2 * *p2 * *p1v - *p1 * *p1 * *p2v; c -= *p1 * *p2 * *p1v; p1++;p2++;p1v++;p2v++; } } else { const REAL * RESTRICT p3=mPowderPatternBackgroundIntegratedCalc.data(); for(unsigned long k=mNbIntegrationUsed;k>0;k--) { a += *p2v * (*p1 - *p3) * *p2; b += *p2 * *p2 * *p1v - (*p1 - *p3) * (*p1 - *p3) * *p2v; c -= (*p1 - *p3) * *p2 * *p1v; p1++;p2++;p1v++;p2v++;p3++; } } // Only one >0 solution to the 2nd degree equation newscale=(REAL)((-b+sqrt(b*b-4*a*c))/(2*a)); } {// Store new scale, and correct old calculated pattern const REAL s = newscale-mScaleFactor(mScalableComponentIndex(0)); const REAL s2 = newscale*newscale -mScaleFactor(mScalableComponentIndex(0)) *mScaleFactor(mScalableComponentIndex(0)); REAL * RESTRICT p0 = mPowderPatternIntegratedCalc.data(); const REAL * RESTRICT p1=mPowderPatternComponentRegistry.GetObj(mScalableComponentIndex(0)) .GetPowderPatternIntegratedCalc().first->data(); REAL * RESTRICT p0v = mPowderPatternVarianceIntegrated.data(); const REAL * RESTRICT p1v=mPowderPatternComponentRegistry.GetObj(mScalableComponentIndex(0)) .GetPowderPatternIntegratedCalcVariance().first->data(); REAL * RESTRICT p0w = mIntegratedWeight.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) { *p0++ += s * *p1++; *p0v += s2 * *p1v++; if(*p0v <=0) {*p0w++ =0;p0v++;}else *p0w++ = 1. / *p0v++; } } mScaleFactor(mScalableComponentIndex(0)) = newscale; mClockScaleFactor.Click(); mClockPowderPatternIntegratedCalc.Click();//we *did* correct the spectrum } else { again=false; mScalableComponentIndex.resizeAndPreserve(nbScale); // prepare matrices mFitScaleFactorM.resize(nbScale,nbScale); mFitScaleFactorB.resize(nbScale,1); mFitScaleFactorX.resize(nbScale,1); // Build Matrix & Vector for LSQ VFN_DEBUG_MESSAGE("PowderPattern::FitScaleFactorForIntegratedRw():1",2); vector integratedCalc; for(int i=0;idata(); const REAL * RESTRICT p2=integratedCalc[j]->data(); const REAL * RESTRICT p3; if(mIntegratedWeight.numElements()==0) { p3=mIntegratedWeightObs.data(); if(ctagain>5) VFN_DEBUG_MESSAGE("ctagain="<5) VFN_DEBUG_MESSAGE("ctagain="<0;k--) {m += *p1 * *p1 * *p3++; p1++;} else for(unsigned long k=mNbIntegrationUsed;k>0;k--) m += *p1++ * *p2++ * *p3++; mFitScaleFactorM(i,j)=m; mFitScaleFactorM(j,i)=m; } } VFN_DEBUG_MESSAGE("PowderPattern::FitScaleFactorForIntegratedRw():4",2); for(int i=0;idata(); const REAL * RESTRICT p4; if(mIntegratedWeight.numElements()==0) p4=mIntegratedWeightObs.data(); else p4=mIntegratedWeight.data(); REAL b=0.; if(mPowderPatternBackgroundIntegratedCalc.numElements()<=1) { for(unsigned long k=mNbIntegrationUsed;k>0;k--) { b += *p1++ * *p2++ * *p4++; //cout<<"B:"<0;k--) { //cout<<"B(minus backgd):"<0) { //if(ctagain>0) cout <<"ctgain, sumvar="<numElements()) { const REAL * RESTRICT p1=mPowderPatternComponentRegistry.GetObj(mScalableComponentIndex(i)) .GetPowderPatternIntegratedCalcVariance().first->data(); //cout <<",sumvar(i)="<sum()); REAL * RESTRICT p0 = mPowderPatternVarianceIntegrated.data(); const REAL s2 = mFitScaleFactorX(i)*mFitScaleFactorX(i) -mScaleFactor(mScalableComponentIndex(i)) *mScaleFactor(mScalableComponentIndex(i)); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += s2 * *p1++; } } } //if(ctagain>0) cout <<" ->"<0) { if(abs(s/mFitScaleFactorX(i))>0.001) { again=true; //cout<<"log(scale) :"<"<"<log(scale) Old :"<5) { VFN_DEBUG_MESSAGE("PowderPattern::FitScaleFactorForIntegratedRw(), scaling again #"<Prepare(); if(0 == mOptProfileIntegration.GetChoice()) this->FitScaleFactorForIntegratedRw(); else this->FitScaleFactorForRw(); this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); } //void PowderPattern::SetApproximationFlag(const bool allow) //{// Do we need this ? // this->Prepare(); // if(0 == mOptProfileIntegration.GetChoice()) this->FitScaleFactorForIntegratedRw(); // else this->FitScaleFactorForRw(); // this->RefinableObj::SetApproximationFlag(allow); //} void PowderPattern::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; this->RefinableObj::GlobalOptRandomMove(mutationAmplitude,type); } void PowderPattern::AddExcludedRegion(const REAL min,const REAL max) { VFN_DEBUG_MESSAGE("PowderPattern::AddExcludedRegion()",5) const int num=mExcludedRegionMinX.numElements(); if(num>0) { mExcludedRegionMinX.resizeAndPreserve(num+1); mExcludedRegionMaxX.resizeAndPreserve(num+1); } else { mExcludedRegionMinX.resize(1); mExcludedRegionMaxX.resize(1); } mExcludedRegionMinX(num)=min; mExcludedRegionMaxX(num)=max; //ensure regions are sorted by ascending 2thetamin CrystVector_long subs; subs=SortSubs(mExcludedRegionMinX); CrystVector_REAL tmp1,tmp2; tmp1=mExcludedRegionMinX; tmp2=mExcludedRegionMaxX; for(int i=0;i(mExcludedRegionMinX,mExcludedRegionMaxX),5) VFN_DEBUG_MESSAGE("PowderPattern::Add2ThetaExcludedRegion():End",5) } REAL PowderPattern::GetLogLikelihood()const { REAL tmp=this->GetChi2_Option(); if(mOptProfileIntegration.GetChoice()==0) tmp+=mIntegratedChi2LikeNorm; else tmp+=mChi2LikeNorm; return tmp; } unsigned int PowderPattern::GetNbLSQFunction()const{return 2;} const CrystVector_REAL& PowderPattern::GetLSQCalc(const unsigned int idx) const { TAU_PROFILE("PowderPattern::GetLSQCalc()","void ()",TAU_DEFAULT); switch(idx) { case 1: { this->CalcPowderPatternIntegrated(); mPowderPatternUsedCalc=mPowderPatternIntegratedCalc; break; } default: { mPowderPatternUsedCalc=this->GetPowderPatternCalc(); mPowderPatternUsedCalc.resizeAndPreserve(mNbPointUsed); break; } } return mPowderPatternUsedCalc; } const CrystVector_REAL& PowderPattern::GetLSQObs(const unsigned int idx) const { TAU_PROFILE("PowderPattern::GetLSQObs()","void ()",TAU_DEFAULT); switch(idx) { case 1: { this->PrepareIntegratedRfactor(); mPowderPatternUsedObs=mIntegratedObs; break; } default: { mPowderPatternUsedObs=this->GetPowderPatternObs(); mPowderPatternUsedObs.resizeAndPreserve(mNbPointUsed); break; } } return mPowderPatternUsedObs; } const CrystVector_REAL& PowderPattern::GetLSQWeight(const unsigned int idx) const { TAU_PROFILE("PowderPattern::GetLSQWeight()","void ()",TAU_DEFAULT); switch(idx) { case 1: { this->PrepareIntegratedRfactor(); // :KLUDGE: When variance is used, mIntegratedWeight will change at each powder pattern calculation, // so this might be quite wrong... if(mIntegratedWeight.numElements()==0) mPowderPatternUsedWeight=mIntegratedWeightObs; else mPowderPatternUsedWeight=mIntegratedWeight; break; } default: { mPowderPatternUsedWeight=this->GetPowderPatternWeight(); mPowderPatternUsedWeight.resizeAndPreserve(mNbPointUsed); break; } } return mPowderPatternUsedWeight; } std::map& PowderPattern::GetLSQ_FullDeriv(const unsigned int idx,std::set &vPar) { TAU_PROFILE("PowderPattern::GetLSQ_FullDeriv()","void ()",TAU_DEFAULT); //return this->RefinableObj::GetLSQ_FullDeriv(idx,vPar); if(idx==1) { this->CalcPowderPatternIntegrated_FullDeriv(vPar); #if 0 std::map fullderiv_old; std::vector v; int n=0; //cout<<"PowderPattern::GetLSQ_FullDeriv(integrated):scales:"<::iterator par=vPar.begin();par!=vPar.end();++par) { v.push_back(&(mPowderPatternIntegrated_FullDeriv[*par])); fullderiv_old[*par]=this->GetLSQDeriv(idx,*(*par)); v.push_back(&(fullderiv_old[*par])); cout<<(*par)->GetName()<<":"<8) break; } cout<<"PowderPattern::GetLSQ_FullDeriv(integrated):"<(v,12,1,20)<GetPowderPattern_FullDeriv(vPar); return mPowderPattern_FullDeriv; } void PowderPattern::Prepare() { VFN_DEBUG_MESSAGE("PowderPattern::Prepare()",5); for(int i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattDataScale)) { if(scaleIndex==0) scaleIndex=first++; groupIndex(i)=scaleIndex; } else //gpRefParTypeScattDataCorrPos { if(thetaIndex==0) thetaIndex=first++; groupIndex(i)=thetaIndex; } } } void PowderPattern::SetMaxSinThetaOvLambda(const REAL max) { mMaxSinThetaOvLambda=max; for(int i=0;iPrepareIntegratedRfactor(); return mIntegratedPatternMin; } const CrystVector_long& PowderPattern::GetIntegratedProfileMax()const { this->PrepareIntegratedRfactor(); return mIntegratedPatternMax; } const RefinableObjClock& PowderPattern::GetIntegratedProfileLimitsClock()const { return mClockIntegratedFactorsPrep; } REAL PowderPattern::STOL2X(const REAL stol)const { REAL x; if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { if(stol>0) x = 1.0/(2*stol); else return 0; x = mDIFC*x+mDIFA*x*x; VFN_DEBUG_MESSAGE("PowderPattern::STOL2X("<=thres) { cout<=nb) break; } cout< "<=nb) break; obs(i)=0; } } cout<<"Width of "<=16)width_golay=16; } // get 2nd derivative CrystVector_REAL obsd2; obsd2=SavitzkyGolay(this->GetPowderPatternObs(),width_golay,2); // Zero excluded regions. for(long i= 0;iX2Pixel(mExcludedRegionMinX(i))); max=(long)ceil (this->X2Pixel(mExcludedRegionMaxX(i))); if(min<0) min = 0; if(max>=obsd2.numElements()) max = obsd2.numElements(); for(long j=min;j sub(tmp.numElements()); QuickSortSubs(tmp,sub,tmp.numElements()-1,0); min_iobs=5*(tmp(tmp.numElements()/2)-tmp(tmp.numElements()/4)); //cout<<__FILE__<<":"<<__LINE__<<" MIN_IOBS (automatic)="<=lastiobs) break; lastiobs=obsd2(i); obsd2(i)=0; iobs+=lastiobs; xmax+=mX(i)*lastiobs;nbav++; if(lastiobs<=0) break; //cout<=(nb-2)) break; if(obsd2(++i)>=lastiobs) break; lastiobs=obsd2(i); obsd2(i)=0; iobs+=lastiobs; xmax+=mX(i)*lastiobs;nbav++; if(lastiobs<=0) break; //cout<X2STOL(xmax)*2; dright=this->X2STOL(dright)*2; dleft =this->X2STOL(dleft)*2; //TODO : evaluate min intensity ratio from noise ? if(min_iobs<0) { cout<GetPowderPatternObsSigma()(imax)<<","<GetPowderPatternObs()(imax)<(&(this->GetPowderPatternComponent(i))); if(this->GetPowderPatternComponent(i).GetClassName()=="PowderPatternDiffraction") vDiff.push_back(dynamic_cast(&(this->GetPowderPatternComponent(i)))); } if((pBackground==0)||vDiff.size()==0) return; // Powder data file ofstream dat((prefix+".dat").c_str()); dat<<"XYDATA"<GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) ttheta *= RAD2DEG; dat << FormatVertVector(ttheta,mPowderPatternObs,mPowderPatternObsSigma,12,4); dat.close(); // PCR file ofstream pcr((prefix+".pcr").c_str()); // if(!pcr) :TODO: // Title pcr<<"Fox/ObjCryst exported file:"<GetName()<GetRadiation().GetRadiationType()==RAD_XRAY) job=0; if(this->GetRadiation().GetRadiationType()==RAD_NEUTRON) job=1; //:TODO: TOF: pcr<<"! Job Npr Nba Nex Nsc Nor Iwg Ilo Res Ste Uni Cor Anm"<GetInterpPoints().first->numElements() <<" 0 0 1 0 0 0 1 0 0 0"<(long)idx))idx=idx2; if(((long)idx3!=(long)string::npos)&&((long)idx3>(long)idx))idx=idx3; if(idx==string::npos) shortName=prefix; else shortName=prefix.substr(idx+1); } pcr<<"! File names of data files"<GetRadiation().GetRadiationType()==RAD_NEUTRON) wdt=10; pcr<<"!lambda1 lambda2 Ratio Bkpos Wdt Cthm muR AsyLim Rpolarz -> Patt #1"<GetRadiation().GetWavelength()(0)<<" "<GetRadiation().GetWavelength()(0) << " 0 0 "< Patt #1"<GetInterpPoints().first->numElements();i++) pcr<<(*(pBackground->GetInterpPoints().first))(i)*RAD2DEG<<" " <<(*(pBackground->GetInterpPoints().second))(i)<<" 0.0"< Patt #1"< Current R_Bragg for Pattern# 1: 0.00 "<GetCrystal().GetName()< vExportAtom; list vExportBond; list vExportAngle; { CrystMatrix_REAL minDistTable; minDistTable=vDiff[i]->GetCrystal().GetMinDistanceTable(-1.); unsigned long k=0; // list0 is the full scattering component list with all atoms except dummies, // and a correct mDynPopCorr const ScatteringComponentList list0=vDiff[i]->GetCrystal().GetScatteringComponentList(); for(int s=0;sGetCrystal().GetScattererRegistry().GetNb();s++) { const ScatteringComponentList list=vDiff[i]->GetCrystal().GetScatt(s).GetScatteringComponentList(); // If we have a Molecule, remember the names used for the atoms to describe restraints // We can't use the original atom names as they might not be unique in the crystal const Molecule *pMol=0; if(vDiff[i]->GetCrystal().GetScatt(s).GetClassName()=="Molecule") pMol=dynamic_cast(&(vDiff[i]->GetCrystal().GetScatt(s))); map vMolAtomName; for(int j=0;j::iterator pos=vExportAtom.find(l); if(pos!=vExportAtom.end()) pos->second.occMult+=1; redundant=true;//-1 means dist > 10A } if(!redundant) { //:TODO: avoid non-alphanumeric characters in name stringstream name; name<GetName()<GetBiso(), list(j).mOccupancy*list0(k).mDynPopCorr, list(j).mpScattPow))); if(pMol!=0) vMolAtomName.insert(make_pair(pMol->GetAtomList()[j],name.str())); } k++; } if(pMol!=0) { for(vector::const_iterator pos=pMol->GetBondList().begin(); pos!=pMol->GetBondList().end();++pos) { map::const_iterator p1,p2; p1=vMolAtomName.find(&((*pos)->GetAtom1())); p2=vMolAtomName.find(&((*pos)->GetAtom2())); if( (p1!=vMolAtomName.end()) && (p2!=vMolAtomName.end())) vExportBond.push_back(exportBond(p1->second, p2->second, (*pos)->GetLength0(),(*pos)->GetLengthSigma())); } for(vector::const_iterator pos=pMol->GetBondAngleList().begin(); pos!=pMol->GetBondAngleList().end();++pos) { map::const_iterator p1,p2,p3; p1=vMolAtomName.find(&((*pos)->GetAtom1())); p2=vMolAtomName.find(&((*pos)->GetAtom2())); p3=vMolAtomName.find(&((*pos)->GetAtom3())); if( (p1!=vMolAtomName.end()) && (p2!=vMolAtomName.end()) && (p3!=vMolAtomName.end())) vExportAngle.push_back(exportAngle(p1->second, p2->second,p3->second, (*pos)->GetAngle0(),(*pos)->GetAngleSigma())); } } } // :TODO: recognize special positions, and move the atoms on them. // :TODO: list atoms excluded, commented out } // Main control codes line for the phase //:TODO: extract distance (Dis) and bond angle (Ang) restraints whenever possible //const ScatteringComponentList *pSC=&(vDiff[i]->GetCrystal().GetScatteringComponentList()); pcr<<"!Nat Dis Ang Jbt Isy Str Furth ATZ Nvk More"<GetCrystal().GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin() <<" <- Space Group Symbol"<::const_iterator pos=vExportAtom.begin();pos!=vExportAtom.end();++pos) { pcr<second.name <<" "<second.mpScattPow->GetSymbol()<<" " <second.x<<" "<second.y<<" "<second.z<<" " <second.biso<<" " <second.occ*pos->second.occMult<<" 0 0 0 0"<GetProfile().GetPar("Eta0").GetHumanValue(); if(eta0<.01) eta0=.01; else if(eta0>.99) eta0=.99; pcr<<"!Scale Shape1 Bov Str1 Str2 Str3 Strain-Model"<GetProfile().GetPar("U").GetHumanValue()<<" "; pcr<GetProfile().GetPar("V").GetHumanValue()<<" "; pcr<GetProfile().GetPar("W").GetHumanValue()<<" "; pcr<< " 0.0 0.0 0.0 0.0 "<GetCrystal().GetLatticePar(0)<<" " <GetCrystal().GetLatticePar(1)<<" " <GetCrystal().GetLatticePar(2)<<" " <GetCrystal().GetLatticePar(3)*RAD2DEG<<" " <GetCrystal().GetLatticePar(4)*RAD2DEG<<" " <GetCrystal().GetLatticePar(5)*RAD2DEG<0) { pcr<<"!Soft distance constraints"<::const_iterator pos=vExportBond.begin();pos!=vExportBond.end();++pos) { pcr<at1<<" "<at2<<" 1 0 0 0 "<dist<<" "<sigma<0) { pcr<<"!Soft angle constraints"<::const_iterator pos=vExportAngle.begin();pos!=vExportAngle.end();++pos) { pcr<at1<<" "<at2<<" "<at3<<" 1 1 0 0 0 0 0 0 " <ang*RAD2DEG<<" "<sigma*RAD2DEG<CalcNbPointUsed(); if(mClockPowderPatternCalc>mClockMaster) return; TAU_PROFILE("PowderPattern::CalcPowderPattern()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPattern::CalcPowderPattern()",3); if(mPowderPatternComponentRegistry.GetNb()==0) { mPowderPatternCalc.resize(mNbPoint); mPowderPatternCalc=0; mPowderPatternVariance.resize(mNbPoint); mPowderPatternVariance = mPowderPatternObsSigma; mPowderPatternVariance *= mPowderPatternObsSigma; const REAL *p0 = mPowderPatternVariance.data(); REAL *p1=mPowderPatternWeight.data(); for(unsigned long j=0;jIsBeingRefined())) for(unsigned long j=mNbPointUsed;jIsBeingRefined())) for(unsigned long j=mNbPointUsed;jIsBeingRefined())) for(unsigned long j=mNbPointUsed;j &vPar) { TAU_PROFILE("PowderPattern::CalcPowderPattern_FullDeriv()","void ()",TAU_DEFAULT); this->CalcPowderPattern(); mPowderPattern_FullDeriv.clear(); if(mPowderPatternComponentRegistry.GetNb()==0) return; std::vector*> comps; for(int i=0;i::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) continue; for(int i=0;iGetPointer()==mScaleFactor.data()+i) { mPowderPattern_FullDeriv[*par]=mPowderPatternComponentRegistry.GetObj(i).GetPowderPatternCalc(); continue; } else { if((*(comps[i]))[*par].size()==0) continue; } if(true==mPowderPatternComponentRegistry.GetObj(i).IsScalable()) { if(mPowderPattern_FullDeriv[*par].size()==0) { mPowderPattern_FullDeriv[*par].resize(mNbPoint);// :TODO: only use mNbPointUsed const REAL * p1=(*comps[i])[*par].data(); REAL * p0 = mPowderPattern_FullDeriv[*par].data(); const REAL s = mScaleFactor(i); for(unsigned long j=0;j oldDeriv; std::vector v; int n=0; for(std::map::reverse_iterator pos=mPowderPattern_FullDeriv.rbegin();pos!=mPowderPattern_FullDeriv.rend();++pos) { if(pos->first==0) continue; if(pos->second.size()==0) continue; const REAL step=pos->first->GetDerivStep(); pos->first->Mutate(step); this->CalcPowderPattern(); oldDeriv[pos->first]=mPowderPatternCalc; pos->first->Mutate(-2*step); this->CalcPowderPattern(); oldDeriv[pos->first]-=mPowderPatternCalc; oldDeriv[pos->first]/=2*step; pos->first->Mutate(step); v.push_back(&(pos->second)); v.push_back(&(oldDeriv[pos->first])); cout<first->GetName()<<":"<second.size()<<","<first].size()<8) break; } cout<(v,16)<CalcNbPointUsed(); if(mClockPowderPatternIntegratedCalc>mClockMaster) return; this->PrepareIntegratedRfactor(); TAU_PROFILE("PowderPattern::CalcPowderPatternIntegrated()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("PowderPattern::CalcPowderPatternIntegrated()",4); if(mPowderPatternComponentRegistry.GetNb()==0) { mPowderPatternIntegratedCalc.resize(0); mPowderPatternVarianceIntegrated.resize(0); VFN_DEBUG_EXIT("PowderPattern::CalcPowderPatternIntegrated():no components!",4); return; } TAU_PROFILE_TIMER(timer1,"PowderPattern::CalcPowderPatternIntegrated()1:Calc components",\ "", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"PowderPattern::CalcPowderPatternIntegrated()2:Add comps-scaled"\ ,"", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"PowderPattern::CalcPowderPatternIntegrated()2:Add backgd1"\ ,"", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"PowderPattern::CalcPowderPatternIntegrated()2:Add backgd2"\ ,"", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"PowderPattern::CalcPowderPatternIntegrated()3:Variance" ,"", TAU_FIELD); TAU_PROFILE_START(timer1); vector< pair > comps; for(int i=0;i >::iterator pos=comps.begin();pos!=comps.end();++pos) if(mClockPowderPatternCalc < *(pos->second) ) { b=true; break; } if(false==b) { VFN_DEBUG_EXIT("PowderPattern::CalcPowderPatternIntegrated():no need to recalc",4); return; } VFN_DEBUG_MESSAGE("PowderPattern::CalcPowderPatternIntegrated():Recalc",3); mPowderPatternIntegratedCalc.resize(mNbIntegrationUsed); int nbBackgd=0;//count number of background phases for(int i=0;idata(); REAL * RESTRICT p0 = mPowderPatternIntegratedCalc.data(); const REAL s = mScaleFactor(i); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ = s * *p1++; } else { const REAL * RESTRICT p1= comps[i].first->data(); REAL * RESTRICT p0 = mPowderPatternIntegratedCalc.data(); const REAL s = mScaleFactor(i); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += s * *p1++; } TAU_PROFILE_STOP (timer2); } else {// This is a background phase TAU_PROFILE_START(timer3); if(0==i) { const REAL * RESTRICT p1= comps[i].first->data(); REAL * RESTRICT p0 = mPowderPatternIntegratedCalc.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ = *p1++; } else { const REAL * RESTRICT p1= comps[i].first->data(); REAL * RESTRICT p0 = mPowderPatternIntegratedCalc.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += *p1++; } TAU_PROFILE_STOP(timer3); TAU_PROFILE_START(timer4); // The following is useless if there is only one background phase... if(0==nbBackgd) { mPowderPatternBackgroundIntegratedCalc.resize(mNbIntegrationUsed); const REAL * RESTRICT p1= comps[i].first->data(); REAL * RESTRICT p0 = mPowderPatternBackgroundIntegratedCalc.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ = *p1++; } else { const REAL * RESTRICT p1= comps[i].first->data(); REAL * RESTRICT p0 = mPowderPatternBackgroundIntegratedCalc.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += *p1++; } nbBackgd++; TAU_PROFILE_STOP(timer4); } } TAU_PROFILE_START(timer5); if(0==nbBackgd) mPowderPatternBackgroundIntegratedCalc.resize(0); // Calc variance bool useCalcVariance=false; for(int i=0;inumElements() !=0) useCalcVariance=true; if(useCalcVariance) { VFN_DEBUG_MESSAGE("PowderPattern::CalcPowderPatternIntegrated():variance",3); { mPowderPatternVarianceIntegrated.resize(mNbIntegrationUsed); mIntegratedWeight.resize(mNbIntegrationUsed); const REAL * RESTRICT p1= mIntegratedVarianceObs.data(); REAL * RESTRICT p0 = mPowderPatternVarianceIntegrated.data(); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ = *p1++; } //cout <<"PowderPattern::CalcPowderPatternIntegrated():variance" // <<"obsvarsum="<numElements()) break; const REAL * RESTRICT p1= mPowderPatternComponentRegistry.GetObj(i) .GetPowderPatternIntegratedCalcVariance().first->data(); //cout <<",sumvar(i)="<sum()); REAL * RESTRICT p0 = mPowderPatternVarianceIntegrated.data(); if(true==mPowderPatternComponentRegistry.GetObj(i).IsScalable()) { const REAL s2 = mScaleFactor(i) * mScaleFactor(i); for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += s2 * *p1++; } else for(unsigned long j=mNbIntegrationUsed;j>0;j--) *p0++ += *p1++; } } //cout <0;j--) if(*p1 <=0) {*p0++ =0;p1++;} else *p0++ = 1. / *p1++; } else mIntegratedWeight.resize(0); mClockPowderPatternIntegratedCalc.Click(); TAU_PROFILE_STOP(timer5); /* // Compare-DEBUG ONLY { VFN_DEBUG_MESSAGE("PowderPattern::CalcPowderPatternIntegrated():Check",10); this->CalcPowderPattern(); CrystVector_REAL integr(mNbIntegrationUsed); for(int k=0;k (integr,*(comps[k].first))< &vPar) { TAU_PROFILE("PowderPattern::CalcPowderPatternIntegrated_FullDeriv()","void ()",TAU_DEFAULT); this->CalcPowderPatternIntegrated(); this->CalcNbPointUsed(); this->PrepareIntegratedRfactor(); mPowderPatternUsed_FullDeriv.clear(); if(mPowderPatternComponentRegistry.GetNb()==0) return; std::vector*> comps; for(int i=0;i::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) continue; //:TODO: store the calculated (non-derived) pattern here ? for(int i=0;iGetPointer()==mScaleFactor.data()+i) { //scalePar=*par; mPowderPatternIntegrated_FullDeriv[*par]=*(mPowderPatternComponentRegistry.GetObj(i).GetPowderPatternIntegratedCalc().first); //cout<<"PowderPattern::CalcPowderPatternIntegrated_FullDeriv():scale #"<GetName()<<":"<<(*par)->GetPointer()<<":"<0;j--) { #if 1 *p0++ = s * *p1++; #else *p0 = s * *p1; if((j==mNbIntegrationUsed)&&((*par)->GetName()=="Cimetidine_C11_x")) cout<<__FILE__<<":"<<__LINE__<<":"<<*p0<<","<0;j--) { #if 1 *p0++ += s * *p1++; #else *p0 += s * *p1; if((j==mNbIntegrationUsed)&&((*par)->GetName()=="Cimetidine_C11_x")) cout<<__FILE__<<":"<<__LINE__<<":"<<*p0<<","<0;j--) { #if 1 *p0++ = *p1++; #else *p0 = *p1; if((j==mNbIntegrationUsed)&&((*par)->GetName()=="Cimetidine_C11_x")) cout<<__FILE__<<":"<<__LINE__<<":"<<*p0<<","<<*p1<0;j--) { #if 1 *p0++ += *p1++; #else *p0 += *p1; if((j==mNbIntegrationUsed)&&((*par)->GetName()=="Cimetidine_C11_x")) cout<<__FILE__<<":"<<__LINE__<<":"<<*p0<<","<<*p1<GetName()=="Cimetidine_C11_x") cout<<"PowderPattern::CalcPowderPatternIntegrated_FullDeriv():" <<(*par)->GetName()<<":s="<GetName()<<":"<GetPointer()<<":"<InitOptions(); { RefinablePar tmp("Zero",&mXZero,-.05,.05,gpRefParTypeScattDataCorrPos, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockPowderPatternXCorr); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("2ThetaDispl",&m2ThetaDisplacement,-.05,.05,gpRefParTypeScattDataCorrPos, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockPowderPatternXCorr); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("2ThetaTransp",&m2ThetaTransparency,-.05,.05,gpRefParTypeScattDataCorrPos, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockPowderPatternXCorr); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("DIFC",&mDIFC,0,1e6,gpRefParTypeScattDataCorrPos, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.0); tmp.AssignClock(mClockPowderPatternXCorr); tmp.SetDerivStep(1e-2); this->AddPar(tmp); } { RefinablePar tmp("DIFA",&mDIFA,-1e4,1e4,gpRefParTypeScattDataCorrPos, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.0); tmp.AssignClock(mClockPowderPatternXCorr); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("MuR",&mMuR,0,1000,gpRefParTypeScattDataCorrIntAbsorp, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.0); tmp.AssignClock(mClockCorrAbs); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } } void PowderPattern::PrepareIntegratedRfactor()const { bool needPrep=false; for(int i=0;imClockIntegratedFactorsPrep) { needPrep=true; break; } } // If using max sin(theta)/lambda this->CalcNbPointUsed(); if(mClockIntegratedFactorsPrep vLimits; for(int i=0;i::iterator pos=vLimits.begin();pos!=vLimits.end();) { if( (*pos<0) || (*pos>=long(mNbPointUsed)) ) pos=vLimits.erase(pos); else ++pos; } // Try to avoid too small intervals list vLimits2; list::iterator pos1=vLimits.begin(); list::iterator pos2=pos1;pos2++; for(;pos2!=vLimits.end();) { const long pix1=*pos1; //cout<<__FILE__<<":"<<__LINE__<<":"<(pix1+8)) break; } } vLimits2.push_back(*pos1); // Try to avoid too small intervals (2nd pass) pos1=vLimits2.begin(); pos2=pos1;pos2++; for(;pos2!=vLimits2.end();) { //cout<<__FILE__<<":"<<__LINE__<<":"<<*pos1<<" -> "<<*pos2< "<<*pos2<<"...PLONK"; pos2=vLimits2.erase(pos2); //cout<<"->"<<*pos2< > vLimits3; pos1=vLimits2.begin(); pos2=pos1;pos2++; for(;pos2!=vLimits2.end();) { if(*pos2!=(long(mNbPointUsed)-1)) vLimits3.push_back(make_pair(*pos1++,*pos2++-1)); else vLimits3.push_back(make_pair(*pos1++,*pos2++)); //cout<<__FILE__<<":"<<__LINE__<<":"< "< >::iterator pos=vLimits3.begin();pos!=vLimits3.end();++pos) { mIntegratedPatternMin(i)=pos->first; mIntegratedPatternMax(i++)=pos->second; } } long numInterval=mIntegratedPatternMin.numElements(); CrystVector_bool keep(numInterval); keep=true; // Take care of excluded regions (change integration areas accordingly) // regions are sorted by ascending theta const long nbExclude=mExcludedRegionMinX.numElements(); if(nbExclude>0) { VFN_DEBUG_MESSAGE("PowderPattern::PrepareIntegratedRfactor():5:Excluded regions("<X2Pixel(mExcludedRegionMinX(j))); maxExcl=(long)ceil (this->X2Pixel(mExcludedRegionMaxX(j))); for(int i=0;i=numInterval) break; } if(j>=numInterval) break; while(mIntegratedPatternMin(j)minExcl) &&(mIntegratedPatternMax(j)minExcl) &&(mIntegratedPatternMax(j)>maxExcl)) mIntegratedPatternMin(j)=maxExcl; if(j==(numInterval-1)) break; j++; } minExcl=(long)(this->X2Pixel(mExcludedRegionMinX(i))); maxExcl=(long)(this->X2Pixel(mExcludedRegionMaxX(i))); //go back if one integration segment is concerned by several exclusion zones... if(j!=0) while(mIntegratedPatternMax(j)>=minExcl) { j--; if(j==0) break; } } } // Keep only the selected intervals VFN_DEBUG_MESSAGE("PowderPattern::PrepareIntegratedRfactor():6",3); long j=0; for(int i=0;i(mIntegratedPatternMin,mIntegratedPatternMax),2); // Integrate Obs and weight arrays mIntegratedObs.resize(numInterval); mIntegratedVarianceObs.resize(numInterval); mIntegratedVarianceObs=0; mIntegratedObs=0; mIntegratedWeightObs.resize(numInterval); for(int i=0;i(mIntegratedPatternMin, // mIntegratedPatternMax, // mIntegratedObs,mIntegratedWeight,12,6)<IsBeingRefined())return; unsigned long tmp; // Use the first point of the profile of the first reflection not calculated if(this->GetRadiation().GetWavelengthType()==WAVELENGTH_TOF) { tmp=(unsigned long)(this->X2PixelCorr(this->STOL2X(mMaxSinThetaOvLambda))); } else { REAL sinth=mMaxSinThetaOvLambda*this->GetWavelength(); if(1>fabs(sinth)) tmp=(unsigned long)(this->X2PixelCorr(2*asin(sinth))); else tmp=mNbPoint; } if(tmp>mNbPoint) tmp= mNbPoint; if(tmp !=mNbPointUsed) { mNbPointUsed=tmp; mClockNbPointUsed.Click(); VFN_DEBUG_MESSAGE("PowderPattern::CalcNbPointUsed():"<AddOption(&mOptProfileIntegration); } #ifdef __WX__CRYST__ WXCrystObjBasic* PowderPattern::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXPowderPattern(parent,this); return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // Spacegroup Explorer // //////////////////////////////////////////////////////////////////////// /** Structure to hold the score corresponding to a given spacegroup. * */ SPGScore::SPGScore(const string &s, const REAL r, const REAL g, const unsigned int nbextinct, const REAL ngof, const unsigned int nbrefl): hm(s),rw(r),gof(g),ngof(ngof),nbextinct446(nbextinct),nbreflused(nbrefl) {}; bool compareSPGScore(const SPGScore &s1, const SPGScore &s2) { if(s1.ngof > 0.00001 && s2.ngof >0.00001) return s1.ngof < s2.ngof; return s1.gof < s2.gof; } /// Function which determines the unique extinction fingerprint of a spacegroup, /// by calculating all present reflections between 0<=H<=4 0<=K<=4 0<=L<=6 std::vector spgExtinctionFingerprint(Crystal &c, const cctbx::sgtbx::space_group &spg) { // We don't have the extinction symbol, so do it the stupid way std::vector fingerprint(5*5*7-1+6); long i=0; fingerprint[i++]=c.GetPar("a").IsUsed(); fingerprint[i++]=c.GetPar("b").IsUsed(); fingerprint[i++]=c.GetPar("c").IsUsed(); fingerprint[i++]=c.GetPar("alpha").IsUsed(); fingerprint[i++]=c.GetPar("beta").IsUsed(); fingerprint[i++]=c.GetPar("gamma").IsUsed(); for(long h=0;h<5;++h) for(long k=0;k<5;++k) for (long l=0;l<7;++l) { if((h+k+l)==0) continue; cctbx::miller::index hkl(scitbx::vec3(h,k,l)); if(i>=fingerprint.size()) cout<<"WHOOOOOOOOOOOOOPS"<Run(sg, fitprofile, verbose, restore_orig, update_display, relative_length_tolerance, absolute_angle_tolerance_degree); } SPGScore SpaceGroupExplorer::Run(const cctbx::sgtbx::space_group &spg, const bool fitprofile, const bool verbose, const bool restore_orig, const bool update_display, const REAL relative_length_tolerance, const REAL absolute_angle_tolerance_degree) { TAU_PROFILE("SpaceGroupExplorer::Run()","void (wxCommandEvent &)",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"SpaceGroupExplorer::Run()LSQ-P1","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"SpaceGroupExplorer::Run()LSQ1","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"SpaceGroupExplorer::Run()LSQ2","", TAU_FIELD); Crystal *pCrystal=&(mpDiff->GetCrystal()); // Keep initial lattice parameters & spg const REAL a=pCrystal->GetLatticePar(0), b=pCrystal->GetLatticePar(1), c=pCrystal->GetLatticePar(2), d=pCrystal->GetLatticePar(3), e=pCrystal->GetLatticePar(4), f=pCrystal->GetLatticePar(5); const string spghm=pCrystal->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin(); const string name=pCrystal->GetName(); // Set up new spacegroup const cctbx::sgtbx::space_group_symbols s = spg.match_tabulated_settings(); const string hm=s.universal_hermann_mauguin(); const cctbx::uctbx::unit_cell uc(scitbx::af::double6(a,b,c,d*RAD2DEG,e*RAD2DEG,f*RAD2DEG)); if(!spg.is_compatible_unit_cell(uc,relative_length_tolerance,absolute_angle_tolerance_degree)) { throw ObjCrystException("Spacegroup is not compatible with unit cell."); } mpDiff->GetCrystal().Init(a,b,c,d,e,f,hm,name); mpDiff->SetExtractionMode(true,true); unsigned int nbcycle=1; if(update_display) mpDiff->GetParentPowderPattern().UpdateDisplay(); // Number of free parameters (not taking into account refined profile/background parameters) unsigned int nbfreepar=mpDiff->GetProfileFitNetNbObs(); if(nbfreepar<1) nbfreepar=1; // Should not happen ! // Create the LSQ obj even if the profile is not fitted, to allow restoring all parameters LSQNumObj lsq; lsq.SetRefinedObj(mpDiff->GetParentPowderPattern(),0,true,true); lsq.PrepareRefParList(true); const unsigned int saved_par = lsq.GetCompiledRefinedObj().CreateParamSet("SpaceGroupExplorer saved parameters"); lsq.GetCompiledRefinedObj().SaveParamSet(saved_par); Chronometer chrono; for(unsigned int j=0;jSetExtractionMode(true,true); const float t0=chrono.seconds(); if(verbose) cout<<"Doing Le Bail, t="<ExtractLeBail(5); if(verbose) cout<<", dt="<GetParentPowderPattern().FitScaleFactorForIntegratedRw(); if(fitprofile) {// Perform LSQ TAU_PROFILE_START(timer2); lsq.SetParIsFixed(gpRefParTypeObjCryst,true); lsq.SetParIsFixed(gpRefParTypeScattDataScale,false); std::list vnewpar; std::list vnewpartype; // Only do the full monty for P1, keep the parameters for other spacegroups if(s.number()==1) vnewpar.push_back(&lsq.GetCompiledRefinedObj().GetPar("Zero")); lsq.SetParIsFixed(gpRefParTypeUnitCell,false); lsq.SafeRefine(vnewpar, vnewpartype,1.01,2,true,true); vnewpar.clear(); TAU_PROFILE_STOP(timer2); if(s.number()==1) { TAU_PROFILE_START(timer1); vnewpar.push_back(&lsq.GetCompiledRefinedObj().GetPar("2ThetaDispl")); vnewpar.push_back(&lsq.GetCompiledRefinedObj().GetPar("2ThetaTransp")); lsq.SafeRefine(vnewpar, vnewpartype,1.01,2,true,true); vnewpar.clear(); lsq.SetParIsFixed(gpRefParTypeScattDataBackground,false); // Fix background point beyond optimized domain const unsigned int nbcomp= mpDiff->GetParentPowderPattern().GetNbPowderPatternComponent(); for(unsigned int i=0;iGetParentPowderPattern().GetPowderPatternComponent(i).GetClassName()=="PowderPatternBackground") { PowderPatternBackground *pback=dynamic_cast (&(mpDiff->GetParentPowderPattern().GetPowderPatternComponent(i))); pback->FixParametersBeyondMaxresolution(lsq.GetCompiledRefinedObj()); } for(unsigned int i=0; iSetExtractionMode(true,true); mpDiff->ExtractLeBail(5); TAU_PROFILE_START(timer3); lsq.SafeRefine(vnewpar,vnewpartype,1.01,3,true,true); TAU_PROFILE_STOP(timer3); //mpLog->AppendText(wxString::Format(_T("%5.2f%%/"),pDiff->GetParentPowderPattern().GetRw()*100)); //mpDiff->GetParentPowderPattern().FitScaleFactorForIntegratedRw(); } if(update_display) mpDiff->GetParentPowderPattern().UpdateDisplay(); const REAL rw=mpDiff->GetParentPowderPattern().GetRw()*100; const REAL gof=mpDiff->GetParentPowderPattern().GetChi2()/mpDiff->GetParentPowderPattern().GetNbPointUsed(); if(verbose) cout << boost::format(" (cycle #%u)\n Rwp=%5.2f%%\n GoF=%9.2f") % j % rw % gof <GetParentPowderPattern().GetRw()*100; const REAL gof=mpDiff->GetParentPowderPattern().GetChi2()/nbfreepar; const REAL ngof = this->GetP1IntegratedGoF(); unsigned int nbextinct446=0; std::vector fgp=spgExtinctionFingerprint(*pCrystal,spg); for(unsigned int i=6;iGetNbReflBelowMaxSinThetaOvLambda(); if(verbose>0) cout << boost::format(" Rwp= %5.2f%% GoF=%9.2f nGoF =%9.2f (%3u reflections, %3u extinct)") % rw % gof % ngof % nbrefl % nbextinct446<GetCrystal().Init(a,b,c,d,e,f,spghm,name); lsq.GetCompiledRefinedObj().RestoreParamSet(saved_par); if (update_display) { mpDiff->GetCrystal().UpdateDisplay(); this->mpDiff->GetParentPowderPattern().UpdateDisplay(); } } return SPGScore(hm.c_str(),rw,gof,nbextinct446, ngof, nbrefl); } void SpaceGroupExplorer::RunAll(const bool fitprofile_all, const bool verbose, const bool keep_best, const bool update_display, const bool fitprofile_p1, const REAL relative_length_tolerance, const REAL absolute_angle_tolerance_degree) { Crystal *pCrystal=&(mpDiff->GetCrystal()); // Initial lattice parameters & spg const REAL a=pCrystal->GetLatticePar(0), b=pCrystal->GetLatticePar(1), c=pCrystal->GetLatticePar(2), d=pCrystal->GetLatticePar(3), e=pCrystal->GetLatticePar(4), f=pCrystal->GetLatticePar(5); const cctbx::uctbx::unit_cell uc(scitbx::af::double6(a,b,c,d*RAD2DEG,e*RAD2DEG,f*RAD2DEG)); const string spghm=pCrystal->GetSpaceGroup().GetCCTbxSpg().match_tabulated_settings().hermann_mauguin(); const string name=pCrystal->GetName(); cctbx::sgtbx::space_group_symbol_iterator it=cctbx::sgtbx::space_group_symbol_iterator(); // First, count compatible spacegroups unsigned int nbspg=0; for(;;) { cctbx::sgtbx::space_group_symbols s=it.next(); if(s.number()==0) break; cctbx::sgtbx::space_group spg(s); if(spg.is_compatible_unit_cell(uc,relative_length_tolerance, absolute_angle_tolerance_degree)) nbspg++; //if(s.universal_hermann_mauguin().size()>hmlen) hmlen=s.universal_hermann_mauguin().size(); } if(verbose) cout << boost::format("Beginning spacegroup exploration... %u to go...\n") % nbspg; mvSPG.clear(); mvSPGExtinctionFingerprint.clear(); // Nb refl below max sin(theta/lambda) for p1, to compute nGoF unsigned int nb_refl_p1=1; it=cctbx::sgtbx::space_group_symbol_iterator(); Chronometer chrono; chrono.start(); for(int i=0;;) { cctbx::sgtbx::space_group_symbols s=it.next(); if(s.number()==0) break; cctbx::sgtbx::space_group spg(s); bool compat=spg.is_compatible_unit_cell(uc,relative_length_tolerance,absolute_angle_tolerance_degree); if(compat) { i++; const string hm=s.universal_hermann_mauguin(); // cout<Init(a,b,c,d,e,f,hm,name); std::vector fgp=spgExtinctionFingerprint(*pCrystal,spg); std::map,SPGScore>::iterator posfgp=mvSPGExtinctionFingerprint.find(fgp); if(posfgp!=mvSPGExtinctionFingerprint.end()) { pCrystal->Init(a,b,c,d,e,f,hm,name); mpDiff->SetExtractionMode(true,true); //:TODO: why is this needed to actually get the updated GetNbReflBelowMaxSinThetaOvLambda ? unsigned int nbrefl = mpDiff->GetNbReflBelowMaxSinThetaOvLambda(); REAL ngof = (posfgp->second.ngof * nbrefl) / posfgp->second.nbreflused; mvSPG.push_back(SPGScore(hm.c_str(),posfgp->second.rw,posfgp->second.gof,posfgp->second.nbextinct446, ngof, nbrefl)); if(verbose) cout<second.hm<<"]\n"; } else { if(((s.number()==1) && fitprofile_p1) || fitprofile_all) mvSPG.push_back(this->Run(spg, true, false, false, update_display, relative_length_tolerance, absolute_angle_tolerance_degree)); else mvSPG.push_back(this->Run(spg, false, false, true, update_display,relative_length_tolerance,absolute_angle_tolerance_degree)); if(s.number() == 1) nb_refl_p1 = mvSPG.back().nbreflused; mvSPG.back().ngof *= mpDiff->GetNbReflBelowMaxSinThetaOvLambda() / (float)nb_refl_p1; mvSPGExtinctionFingerprint.insert(make_pair(fgp, mvSPG.back())); if(verbose) cout<GetSpaceGroup().ChangeSpaceGroup(mvSPG.front().hm); } else { // Go back to original lattice and spacegroup & update display pCrystal->Init(a,b,c,d,e,f,spghm,name); } mpDiff->SetExtractionMode(true,true); mpDiff->ExtractLeBail(5); if(update_display) { pCrystal->UpdateDisplay(); this->mpDiff->GetParentPowderPattern().UpdateDisplay(); } } const list& SpaceGroupExplorer::GetScores() const { return mvSPG; } REAL SpaceGroupExplorer::GetP1IntegratedGoF() { if(mpDiff->GetCrystal().GetSpaceGroup().GetSpaceGroupNumber()==1) { mpDiff->GetPowderPatternIntegratedCalc(); mP1IntegratedProfileMin = mpDiff->GetParentPowderPattern().GetIntegratedProfileMin(); mP1IntegratedProfileMax = mpDiff->GetParentPowderPattern().GetIntegratedProfileMax(); // cout<<"Updating mP1IntegratedProfileMin/Max:"<(mP1IntegratedProfileMin, mP1IntegratedProfileMax,mP1IntegratedProfileMax)<(mpDiff->GetH(), mpDiff->GetK(), mpDiff->GetL(), mpDiff->GetFhklCalcSq()); REAL integratedChi2=0.; REAL integratedChi2LikeNorm=0.; const REAL * RESTRICT p1, * RESTRICT p2, * RESTRICT p3; CrystVector_REAL const* pcalc = &(mpDiff->GetParentPowderPattern().GetPowderPatternCalc()); CrystVector_REAL const* pobs = &(mpDiff->GetParentPowderPattern().GetPowderPatternObs()); CrystVector_REAL const* psigma = &(mpDiff->GetParentPowderPattern().GetPowderPatternObsSigma()); const unsigned int jmax = mpDiff->GetParentPowderPattern().GetNbPointUsed(); REAL chi2=0; unsigned int nbpoint = 0; for(unsigned long i=0;i jmax) break; if(mP1IntegratedProfileMax(i) < 0) continue; REAL v=0, c=0, o=0; for(unsigned long j=mP1IntegratedProfileMin(i); j<=mP1IntegratedProfileMax(i); j++) { if(j<0) continue; if(j >= jmax) break; nbpoint++; c += (*pcalc)(j); // calc o += (*pobs)(j); // obs v += (*psigma)(j)*(*psigma)(j); // variance } if(v>0) chi2 += (c-o)*(c-o)/v; } return chi2 / nbpoint; } }//namespace ObjCryst libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PowderPattern.h000066400000000000000000001761211417150057700240230ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _OBJCRYST_POWDERPATTERN_H_ #define _OBJCRYST_POWDERPATTERN_H_ #include #include #include #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/ScatteringCorr.h" #include "ObjCryst/ObjCryst/ReflectionProfile.h" #include "ObjCryst/ObjCryst/CIF.h" #include "ObjCryst/ObjCryst/Indexing.h" #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" namespace ObjCryst { class PeakList; class PowderPattern; class PowderPatternDiffraction; //###################################################################### /** \brief Cylinder absorption correction * * Correction formulas from Lobanov & Alte da Veiga, * Code re-implemented from GSAS-II (courtesy of B. von Dreele), original version: * https://subversion.xray.aps.anl.gov/trac/pyGSAS/browser/trunk/GSASIIpwd.py * */ class CylinderAbsCorr:public ScatteringCorr { public: /** Constructor * \param powp: the PowderPattern object which has the muR parameter */ CylinderAbsCorr(const PowderPatternDiffraction &data); virtual ~CylinderAbsCorr(); virtual const string & GetName() const; virtual const string & GetClassName() const; protected: virtual void CalcCorr() const; const PowderPatternDiffraction *mpPowderPatternDiff; }; //###################################################################### /** \brief Generic class to compute components (eg the contribution of * a given phase, or background) of a powder pattern. This is an abstract base class. * * Most functions are protected, only to be accessed, * internally or from the friend class PowderPattern. */ //###################################################################### class PowderPatternComponent : virtual public RefinableObj { public: PowderPatternComponent(); PowderPatternComponent(const PowderPatternComponent&); virtual ~PowderPatternComponent(); virtual const string& GetClassName() const; /// Get the PowderPattern object which uses this component. /// This allows to know the observed powder pattern to evaluate /// the background. const PowderPattern& GetParentPowderPattern()const; /// Get the PowderPattern object which uses this component. /// This allows to know the observed powder pattern to evaluate /// the background. PowderPattern& GetParentPowderPattern(); /// Set the PowderPattern object which uses this component. /// This sets all necessary pattern parameters (2theta/tof range, /// wavelength, radiation type...) accordingly. /// virtual void SetParentPowderPattern(PowderPattern&)=0; /// Get the calculated powder pattern for this component. /// Note that the pattern is \e not scaled. /// virtual const CrystVector_REAL& GetPowderPatternCalc()const=0; virtual std::map& GetPowderPattern_FullDeriv(std::set &vPar); /** Get the integrated values of the powder pattern * * \note: the integration intervals are those given by the parent * PowderPattern, so that all PowderPatternComponent's intervals * are taken into account * * This avoids explicitely calculating the full profile powder pattern. */ virtual pair GetPowderPatternIntegratedCalc()const=0; virtual std::map& GetPowderPatternIntegrated_FullDeriv(std::set &vPar); /** \brief Is this component scalable ? * * This is used by the PowderPattern class, which fits all * pattern components using scale factors. Some components may not * need to be scaled: background components, which are assumed * to be absolute. */ bool IsScalable()const; /** Get the variance associated to each point of the * calculated powder pattern, for this component. * * \warning: this is experimental, with the aim of using Maximum Likelihood * to improve structure determination. */ virtual const CrystVector_REAL& GetPowderPatternCalcVariance()const=0; /** Get the variance associated to each point of the * calculated powder pattern, for this component (integrated version). * * \warning: this is experimental, with the aim of using Maximum Likelihood * to improve structure determination. */ virtual pair GetPowderPatternIntegratedCalcVariance() const=0; /// Does this component have a variance associated with each calculated /// point ? i.e., do we use maximum likelihood to take into account /// incomplete models ? virtual bool HasPowderPatternCalcVariance()const=0; /// Last time the powder pattern was calculated. const RefinableObjClock& GetClockPowderPatternCalc()const; /// Get a list of labels for the pattern (usually reflection indexes). This /// returns the list generated during the last computation of the powder pattern. const list >& GetPatternLabelList() const; protected: /// Last time the variance on the pattern was actually calculated. const RefinableObjClock& GetClockPowderPatternCalcVariance()const; /// Calc the powder pattern. As always, recomputation is only /// done if necessary (ie if a parameter has changed since the last /// computation) virtual void CalcPowderPattern() const=0; virtual void CalcPowderPattern_FullDeriv(std::set &vPar); /// Calc the integrated powder pattern. This should be optimized so that /// the full powder pattern is not explicitely computed. virtual void CalcPowderPatternIntegrated_FullDeriv(std::set &vPar); /** Get the pixel positions separating the integration intervals around reflections. * * \returns: an array with the pixel positions, empty if this component * has no peaks. The positions should be in increasing order, but * could go beyond the pattern limits. */ virtual const CrystVector_long& GetBraggLimits()const=0; /// Get last time the Bragg Limits were changed const RefinableObjClock& GetClockBraggLimits()const; /// Set the maximum value for sin(theta)/lambda. All data above still /// exist but are ignored for all calculations. virtual void SetMaxSinThetaOvLambda(const REAL max)=0; /// The calculated component of a powder pattern. It is mutable since it is /// completely defined by other parameters (eg it is not an 'independent parameter') mutable CrystVector_REAL mPowderPatternCalc; /// The calculated powder pattern, integrated. mutable CrystVector_REAL mPowderPatternIntegratedCalc; /// The variance associated to each point of the calculated powder pattern. mutable CrystVector_REAL mPowderPatternCalcVariance; /// The variance associated to each point of the calculated powder pattern, integrated mutable CrystVector_REAL mPowderPatternIntegratedCalcVariance; /// Interval limits around each reflection, for integrated R-factors mutable CrystVector_long mIntegratedReflLimits; /// \internal /// This will be called by the parent PowderPattern object, before /// calculating the first powder pattern. Or maybe it should be called /// automatically by the object itself... virtual void Prepare()=0; /// Scalable ? (crystal phase = scalable, background= not scalable) bool mIsScalable; //Clocks /// When was the powder pattern last computed ? mutable RefinableObjClock mClockPowderPatternCalc; /// When was the 'integrated' powder pattern last computed ? mutable RefinableObjClock mClockPowderPatternIntegratedCalc; /// When was the powder pattern variance last computed ? mutable RefinableObjClock mClockPowderPatternVarianceCalc; /// When was the 'integrated' powder pattern variance last computed ? mutable RefinableObjClock mClockPowderPatternIntegratedVarianceCalc; /// The PowderPattern object in which this component is included PowderPattern *mpParentPowderPattern; /// Get last time the Bragg Limits were changed mutable RefinableObjClock mClockBraggLimits; /// The labels associated to different points of the pattern mutable list > mvLabel; mutable std::map mPowderPattern_FullDeriv; mutable std::map mPowderPatternIntegrated_FullDeriv; //Eventually this should be removed (?) friend class PowderPattern; }; /// Global registry for all PowderPatternComponent objects extern ObjRegistry gPowderPatternComponentRegistry; //###################################################################### /** \brief Phase to compute a background contribution to a powder * pattern using an interpolation. Currently only linear interpolation is * available. (in the works: cubic spline interpolation background) */ //###################################################################### class PowderPatternBackground : public PowderPatternComponent { public: PowderPatternBackground(); PowderPatternBackground(const PowderPatternBackground&); virtual ~PowderPatternBackground(); virtual const string& GetClassName() const; virtual void SetParentPowderPattern(PowderPattern&); virtual const CrystVector_REAL& GetPowderPatternCalc()const; virtual pair GetPowderPatternIntegratedCalc()const; /// Import background points from a file (with two columns 2theta (or tof), intensity) void ImportUserBackground(const string &filename); void SetInterpPoints(const CrystVector_REAL tth, const CrystVector_REAL backgd); const std::pair GetInterpPoints()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); virtual const CrystVector_REAL& GetPowderPatternCalcVariance()const; virtual pair GetPowderPatternIntegratedCalcVariance() const; virtual bool HasPowderPatternCalcVariance()const; virtual void TagNewBestConfig()const; /** Optimize the background using a Bayesian approach. The background parameters * must be un-fixed before. * * The minimization will a maximum of 50 Simplex runs (see the SimplexObj documentation), * each with 200 cycles. * * See the class documentation for PowderPatternBackgroundBayesianMinimiser. */ void OptimizeBayesianBackground(); /** Fix parameters corresponding to points of the pattern that are not actually calculated. * This is necessary for modelling using splines, to avoid divergence of interpolation * points during least squares optimization. * * \param obj: the object in which are parameters to be fixed. Normally this will be * the PowderPatternBackground object itself, but it can also be the parameter list * copied such as in a LSQNumObj. */ void FixParametersBeyondMaxresolution(RefinableObj &obj); protected: virtual void CalcPowderPattern() const; virtual void CalcPowderPattern_FullDeriv(std::set &vPar); virtual void CalcPowderPatternIntegrated() const; virtual void CalcPowderPatternIntegrated_FullDeriv(std::set &vPar); virtual void Prepare(); virtual const CrystVector_long& GetBraggLimits()const; virtual void SetMaxSinThetaOvLambda(const REAL max); void InitRefParList(); void InitOptions(); void InitSpline()const; /// Number of fitting points for background int mBackgroundNbPoint; /// Vector of 2theta values for the fitting points of the background CrystVector_REAL mBackgroundInterpPointX; /// Values of background at interpolating points CrystVector_REAL mBackgroundInterpPointIntensity; /// Subscript of the points, sorted the correct order, ///taking into account the type of radiation (monochromatic/TOF). mutable CrystVector_long mPointOrder; /// Vector of pixel values between each interval, for faster CubicSpline calculations. /// Mutable since it copies information from mBackgroundInterpPointX. mutable CrystVector_REAL mvSplinePixel; /// Spline used for interpolation. /// Mutable since it copies information from mBackgroundInterpPointX ///and mBackgroundInterpPointIntensity. mutable CubicSpline mvSpline; // Clocks /// Modification of the interpolated points RefinableObjClock mClockBackgroundPoint; /// Initialization of the spline mutable RefinableObjClock mClockSpline; /** Maximum sin(theta)/lambda for all calculations (10 by default). * * This keeps all data in memory, but only the part which is below * the max is calculated. */ REAL mMaxSinThetaOvLambda; /// Constant error (sigma) on the calculated pattern, due to an incomplete /// model REAL mModelVariance; /// Type of interpolation performed: linear or cubic spline RefObjOpt mInterpolationModel; //To be removed friend class PowderPattern; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXPowderPatternBackground; #endif }; //###################################################################### /** \brief Class to compute the contribution to a powder pattern from * a crystalline phase. * */ //###################################################################### class PowderPatternDiffraction : virtual public PowderPatternComponent,public ScatteringData { public: PowderPatternDiffraction(); PowderPatternDiffraction(const PowderPatternDiffraction&); virtual ~PowderPatternDiffraction(); virtual PowderPatternDiffraction* CreateCopy()const; virtual const string& GetClassName() const; virtual void SetParentPowderPattern(PowderPattern&); virtual const CrystVector_REAL& GetPowderPatternCalc()const; virtual pair GetPowderPatternIntegratedCalc()const; /** Set reflection profile parameters * * :TODO: assymmetric profiles * \param fwhmCagliotiW,fwhmCagliotiU,fwhmCagliotiV : these are the U,V and W * parameters in the Caglioti's law : * \f$ fwhm^2= U \tan^2(\theta) + V \tan(\theta) +W \f$ * if only W is given, the width is constant * \param eta0,eta1: these are the mixing parameters in the case of a * pseudo-Voigt function. */ void SetReflectionProfilePar(const ReflectionProfileType prof, const REAL fwhmCagliotiW, const REAL fwhmCagliotiU=0, const REAL fwhmCagliotiV=0, const REAL eta0=0.5, const REAL eta1=0.); /** Assign a new profile * */ void SetProfile(ReflectionProfile *prof); /// Get reflection profile const ReflectionProfile& GetProfile()const; /// Get reflection profile ReflectionProfile& GetProfile(); virtual void GenHKLFullSpace(); virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); virtual void EndOptimization(); virtual void SetApproximationFlag(const bool allow); virtual const Radiation& GetRadiation()const; virtual const CrystVector_REAL& GetPowderPatternCalcVariance()const; virtual pair GetPowderPatternIntegratedCalcVariance() const; virtual bool HasPowderPatternCalcVariance()const; virtual void SetCrystal(Crystal &crystal); /** Prepare intensity extraction (Le Bail or Pawley) * * *\param extract: if true, begin extraction mode, else enable structure factor calculations *\param init: if true and extract=true, intensities are set to 100. Otherwise if extract==true * and init=false, the program will try to re-use existing extracted data (in mpLeBailData), * but only if the list of HKL is unchanged. Otherwise initilization to 100 will be forced. */ void SetExtractionMode(const bool extract=true,const bool init=false); /// Return true if in extraction mode, i.e. using extracted intensities instead of computed structure factors. bool GetExtractionMode()const; /** Extract intensities using Le Bail method * *\param nbcycle: number of cycles */ void ExtractLeBail(unsigned int nbcycle=1); /// Recalc, and get the number of reflections which should be actually used, /// due to the maximuml sin(theta)/lambda value set. virtual long GetNbReflBelowMaxSinThetaOvLambda()const; /// Change one parameter in mFrozenLatticePar. This triggers a call to CalcLocalBMatrix() if the parameter has changed void SetFrozenLatticePar(const unsigned int i, REAL v); /// Access to one parameter in mFrozenLatticePar REAL GetFrozenLatticePar(const unsigned int i) const; /// Set the use local cell parameters ? (see mFrozenLatticePar) /// If this changes mUseLocalLatticePar from false to true, this triggers a copy /// of the Crystal's lattice parameters into mFrozenLatticePar void FreezeLatticePar(const bool use); /// Do we use local cell parameters ? (see mFrozenLatticePar) bool FreezeLatticePar() const; /** Get the 'net' number of observed intensities, minus the number of reflections, for a profile fit. * This calculation takes into account where each reflection appears: * - if in a low angle region there are 500 points and 2 reflections, this will contribute 498 net * - if at high angle there are 200 points and 250 reflections, this will contribute to 0 net oberved. * - reflections appearing at exactly the same angle count as one * Note that the calculation only includes the region below max(sin(theta)/lambda). * No over paremeters (profile, background) are taken into account */ unsigned int GetProfileFitNetNbObs()const; protected: virtual void CalcPowderPattern() const; virtual void CalcPowderPattern_FullDeriv(std::set &vPar); virtual void CalcPowderPatternIntegrated() const; virtual void CalcPowderPatternIntegrated_FullDeriv(std::set &vPar); /// \internal Calc reflection profiles for ALL reflections (powder diffraction) void CalcPowderReflProfile()const; /// \internal Calc derivatives of reflection profiles for all used reflections, /// for a given list of refinable parameters void CalcPowderReflProfile_FullDeriv(std::set &vPar); /// \internal Calc Lorentz-Polarisation-Aperture correction void CalcIntensityCorr()const; /// \internal Compute the intensity for all reflections (taking into account /// corrections, but not the multiplicity) virtual void CalcIhkl() const; virtual void CalcIhkl_FullDeriv(std::set &vPar); virtual void Prepare(); virtual void InitOptions(); virtual const CrystVector_long& GetBraggLimits()const; virtual void SetMaxSinThetaOvLambda(const REAL max); /// This can use either locally stored lattice parameters from mLocalLatticePar, /// or the Crystal's, depending on mUseLocalLatticePar. virtual const CrystMatrix_REAL& GetBMatrix()const; /// Calculate the local BMatrix, used if mFreezeLatticePar is true. void CalcFrozenBMatrix()const; void PrepareIntegratedProfile()const; //Clocks /// Last time the reflection parameters were changed RefinableObjClock mClockProfilePar; /// Last time the Lorentz-Polarization and slit parameters were changed RefinableObjClock mClockLorentzPolarSlitCorrPar; //Clocks (internal, mutable) /// Last time the Lorentz-Polar-Slit correction was computed mutable RefinableObjClock mClockIntensityCorr; /// Last time the reflection profiles were computed mutable RefinableObjClock mClockProfileCalc; /// Last time intensities were computed mutable RefinableObjClock mClockIhklCalc; /// Profile ReflectionProfile *mpReflectionProfile; // Corrections /** \brief Calculated corrections for all reflections. Calc F^2 must be multiplied *by this factor to yield intensities. * * Thus we have : \f$ I_{hkl} = L \times P \times SlitAp \times F_{hkl}^2 \f$ * *with \f$ L = \frac{1}{\sin(2\theta)} \f$ (Lorentz factor). *\f$ P = \frac{1}{1+A}\left(1+A\cos^2(2\theta)\right) \f$ (Polarization factor), with * \f$ A = \frac{1-f}{1+f} \f$, where f is the polarization rate of the incident *beam in the plane which (i) includes the incident beam, and (ii) is perpendicular to *the diffracting plane. For an X-Ray Tube without monochromator, A=1, and *if there is a monochromator : \f$ A = \cos^2(2\theta_{mono}) \f$ *The factor \f$ SlitAp = \frac{1}{\sin(\theta)} \f$ takes into account the *fraction of the diffracted cone which falls in the detector slit. * * If there is prefereed orientation, this also holds the associated correction. * * \todo: store all corrections in a registry, so that other corrections * can more easily be added (? Maybe not that useful, especially since these * correction do not need to be displayed to the user ?). */ mutable CrystVector_REAL mIntensityCorr; /// Lorentz correction LorentzCorr mCorrLorentz; /// Polarization correction PolarizationCorr mCorrPolar; /// Slit aperture correction PowderSlitApertureCorr mCorrSlitAperture; /// Preferred orientation (texture) correction following the March-Dollase model TextureMarchDollase mCorrTextureMarchDollase; /// Preferred orientation (texture) correction following the Ellipsoidal function TextureEllipsoid mCorrTextureEllipsoid; /// Time-Of-Flight intensity correction TOFCorr mCorrTOF; /// Cylinder absorption correction CylinderAbsCorr mCorrCylAbs; /// Computed intensities for all reflections mutable CrystVector_REAL mIhklCalc; mutable std::map mIhkl_FullDeriv; /// Variance on computed intensities for all reflections mutable CrystVector_REAL mIhklCalcVariance; // Saved arrays to speed-up computations /// Profile of a single reflection struct ReflProfile { /// First point of the pattern for which the profile is calculated long first; /// Last point of the pattern for which the profile is calculated long last; /// The profile CrystVector_REAL profile; }; ///Reflection profiles for ALL reflections during the last powder pattern generation mutable vector mvReflProfile; /// Derivatives of reflection profiles versus a list of parameters. This will be limited /// to the reflections actually used. First and last point of each profile /// are the same as in mvReflProfile. mutable std::map > mvReflProfile_FullDeriv; // When using integrated profiles /** For each reflection, store the integrated value of the normalized * profile over all integration intervals. * * The first field is the first integration interval to which the reflection * contributes, and the second field is a vector with all the integrated * values for the intervals, listed in ascending 2theta(tof) order. */ mutable vector< pair > mIntegratedProfileFactor; /// Last time the integrated values of normalized profiles was calculated. mutable RefinableObjClock mClockIntegratedProfileFactor; /// Extraction mode (Le Bail, Pawley) bool mExtractionMode; /// Single crystal data extracted from the powder pattern. DiffractionDataSingleCrystal *mpLeBailData; /// a,b and c in Angstroems, angles (stored) in radians /// This is used to override lattice parameter from the Crystal structure, /// e.g. for multiple datasets collected at different temperatures /// Ignored unless mFreezeLatticePar is true mutable CrystVector_REAL mFrozenLatticePar; /// If true, use local cell parameters from mFrozenLatticePar rather than the Crystal bool mFreezeLatticePar; /// Local B Matrix, used if mFreezeLatticePar is true mutable CrystMatrix_REAL mFrozenBMatrix; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXPowderPatternDiffraction; #endif private: // Avoid compiler warnings. Explicitly hide the base-class method. void GenHKLFullSpace(const REAL, const bool); }; //###################################################################### /** \brief Powder pattern class, with an observed pattern and several * calculated components to modelize the pattern. * * This can also be used for simulation, using a fake Iobs. Supports * multiple phases. * */ //###################################################################### class PowderPattern : public RefinableObj { public: PowderPattern(); PowderPattern(const PowderPattern&); ~PowderPattern(); virtual const string& GetClassName() const; /** Add a component (phase, backround) to this pattern. * * It must have been allocated in the heap. The pattern parameters (2theta min, * step, nbpoints, wavelength, radiation type) of the component * are automatically changed to that of the PowderPattern object. */ void AddPowderPatternComponent(PowderPatternComponent &); /// Number of components unsigned int GetNbPowderPatternComponent()const; /// Access to a component of the powder pattern const PowderPatternComponent& GetPowderPatternComponent(const string &name)const; /// Access to a component of the powder pattern const PowderPatternComponent& GetPowderPatternComponent(const int)const; /// Access to a component of the powder pattern PowderPatternComponent& GetPowderPatternComponent(const string &name); /// Access to a component of the powder pattern PowderPatternComponent& GetPowderPatternComponent(const int); /// Access to the scale factor of components (will be 1 for background components) REAL GetScaleFactor(const int i)const; /// Access to the scale factor of components (will be 1 for background components) REAL GetScaleFactor(const PowderPatternComponent &comp)const; /// Access to the scale factor of components (will be 1 for background components) void SetScaleFactor(const int i, REAL s); /// Access to the scale factor of components (will be 1 for background components) void SetScaleFactor(const PowderPatternComponent &comp, REAL s); // Pattern parameters (2theta range, wavelength, radiation) /** \briefSet the powder pattern angular range & resolution parameter. * this will affect all components (phases) of the pattern. * * Use this with caution, as the number of points must be correct with * respect to the observed data (Iobs). * * \param min: min 2theta (in radians) or time-of-flight *(in microseconds) value, * \param step: step (assumed constant) in 2theta or time-of-flight * (in microseconds). * \param nbPoints: number of points in the pattern. * * \warning : use only this for constant-step patterns. Otherwise, use * PowderPattern::SetPowderPatternX() */ void SetPowderPatternPar(const REAL min, const REAL step, unsigned long nbPoint); /** Set the x coordinate of the powder pattern : either the * 2theta or time-of-flight values for each recorded point. The * step need not be constant, but the variation must be strictly * monotonous. * * 2theta must be in radians and time-of-flight in microseconds */ void SetPowderPatternX(const CrystVector_REAL &x); ///Number of points ? unsigned long GetNbPoint()const; ///Number of points actually calculated (below the chosen max(sin(theta)/lambda)) ? unsigned long GetNbPointUsed()const; /// Clock corresponding to the last time the number of points used was changed const RefinableObjClock& GetClockNbPointUsed()const; /// Set the radiation void SetRadiation(const Radiation &radiation); ///Neutron or x-ray experiment ? const Radiation& GetRadiation()const; ///Neutron or x-ray experiment ? Radiation& GetRadiation(); /// Set the radiation type void SetRadiationType(const RadiationType radiation); ///Neutron or x-ray experiment ? RadiationType GetRadiationType()const; /** Set the wavelength of the experiment (in Angstroems). * * \note: this is only useful for a monochromatic (X-Ray or neutron) * powder pattern. */ void SetWavelength(const REAL lambda); /** \brief Set the wavelength of the experiment to that of an X-Ray tube. * *\param XRayTubeElementName : name of the anticathode element name. Known *ones are Cr, Fe, Cu, Mo, Ag. *\param alpha2Alpha2ratio: Kalpha2/Kalpha1 ratio (0.5 by default) * *Alpha1 and alpha2 wavelength are taken *from R. Grosse-Kunstleve package, and the average wavelength is calculated *using the alpha2/alpha1 weight. All structure factors computation are made *using the average wavelength, and for powder diffraction, profiles are output *at the alpha1 and alpha2 ratio for the calculated pattern. * *NOTE : if the name of the wavelength is generic (eg"Cu"), *then the program considers that *there are both Alpha1 and Alpha2, and thus automatically changes the WavelengthType *to WAVELENGTH_ALPHA12. If instead either alpha1 or alpha2 (eg "CuA1") is asked for, *the WavelengthType is set to WAVELENGTH_MONOCHROMATIC. In both cases, * the radiation type is set to X-Ray. */ void SetWavelength(const string &XRayTubeElementName,const REAL alpha12ratio=0.5); /// Set the energy of the experiment [in keV, lambda(A)=12398/E(keV)]. void SetEnergy(const REAL energy); /// wavelength of the experiment (in Angstroems) REAL GetWavelength()const; //Access to pattern data /// Get the calculated powder pattern const CrystVector_REAL& GetPowderPatternCalc()const; std::map& GetPowderPattern_FullDeriv(std::set &vPar); /// Get the observed powder pattern const CrystVector_REAL& GetPowderPatternObs()const; /// Get the sigma for each point of the observed powder pattern const CrystVector_REAL& GetPowderPatternObsSigma()const; /// Get the variance (obs+model) for each point of the powder pattern const CrystVector_REAL& GetPowderPatternVariance()const; /// Get the weight for each point of the powder pattern const CrystVector_REAL& GetPowderPatternWeight()const; /// Get the Minimum 2theta REAL GetPowderPatternXMin()const; /** Get the average step in 2theta * * \warning : this will only return (2ThetaMax-2ThetaMin)/(nbPoints-1), * so this is the 2theta step only if the step is fixed. * * \deprecated */ REAL GetPowderPatternXStep()const; /// Get the maximum 2theta REAL GetPowderPatternXMax()const; /// Get the vector of X (2theta or time-of-flight) coordinates const CrystVector_REAL& GetPowderPatternX()const; /** Get the powder pattern cumulative Chi^2. Depending on the chosen option, *it will be calculated in an integrated manner or not. * * The vector is recomputed on every call, so this is \e slow. * \param mode: if -1 (the default), the calculation mode uses the value of mOptProfileIntegration. * if 0, the integrated mode is used. If 1, the full powder pattern mode is used. */ const CrystVector_REAL& GetChi2Cumul(const int mode=-1)const; // Clocks /// Last time the pattern was calculated const RefinableObjClock& GetClockPowderPatternCalc()const; /// When were the pattern parameters (2theta range, step) changed ? const RefinableObjClock& GetClockPowderPatternPar()const; /// When were the radiation parameter (radiation type, wavelength) changed ? const RefinableObjClock& GetClockPowderPatternRadiation()const; /// When were the parameters for 2theta/TOF correction (zero, transparency, /// displacement) last changed ? const RefinableObjClock& GetClockPowderPatternXCorr()const; /// When were the absorption correction parameters (muR) last changed ? const RefinableObjClock& GetClockPowderPatternAbsCorr() const; // Corrections to the x (2theta, tof) coordinate ///Change Zero in x (2theta,tof) void SetXZero(const REAL newZero); /// Change displacement correction /// \f$ (2\theta)_{obs} = (2\theta)_{real} + a\cos(\theta) \f$ void Set2ThetaDisplacement(const REAL displacement); ///Change transparency correction /// \f$ (2\theta)_{obs} = (2\theta)_{real} + b\sin(2\theta) \f$ void Set2ThetaTransparency(const REAL transparency); // Import & export powder pattern /** \brief Import fullprof-style diffraction data. *\param fullprofFileName: filename */ void ImportPowderPatternFullprof(const string &fullprofFileName); /** \brief Import powder pattern, format DMC from PSI */ void ImportPowderPatternPSI_DMC(const string &filename); /** \brief Import powder pattern, format from ILL D1A/D2B * (format without counter info) */ void ImportPowderPatternILL_D1A5(const string &filename); /** \brief Import *.xdd diffraction data (Topas,...). *\param fileName: filename */ void ImportPowderPatternXdd(const string &fileName); /** \brief Import *.cpi Sietronics diffraction data *\param fileName: filename */ void ImportPowderPatternSietronicsCPI(const string &fileName); /** \brief Import file with 3 columns 2Theta Iobs Sigma. *\param fileName: the filename (surprise!) *\param nbSkip: the number of lines to skip at the beginning of the file (default=0) */ void ImportPowderPattern2ThetaObsSigma(const string &fileName,const int nbSkip=0); /** \brief Import diffraction data from a file, with the first line * has 2ThetaMin, step, 2thetaMax, and the following lines alternate * 10 Iobs and 10 sigma. Ends with null entries (to fill last Iobs line * to reach last sigme line). * That's fullprof format #4. *\param fileName: filename */ void ImportPowderPatternFullprof4(const string &fileName); /** \brief diffraction data in a multi-detector format (fullprof format #6). * * First line is text. Third entry of second line is the 2theta step. Third *line has the 2thetamin, fourth line has monitors and temperatures. * Then each line has ten pairs (I2,I8)of NbCounters,intensity. Ends with * negative entries. *\param fileName: filename */ void ImportPowderPatternMultiDetectorLLBG42(const string &fileName); /** \brief Import file with 2 columns 2Theta Iobs. * *\param fileName: the filename (surprise!) *\param nbSkip: the number of lines to skip at the beginning of the file (default=0) */ void ImportPowderPattern2ThetaObs(const string &fileName,const int nbSkip=0); /** \brief Import TOF file (ISIS type, 3 columns t, Iobs, sigma(Iobs)) *\param fileName: the filename */ void ImportPowderPatternTOF_ISIS_XYSigma(const string &fileName); /** Import GSAS standard powder pattern data (see GSAS manual). * \warning : partial support (only CONST-constant wavelength- data so far) */ void ImportPowderPatternGSAS(const string &fileName); /** Import CIF powder pattern data. */ void ImportPowderPatternCIF(const CIF &cif); /** \brief Set observed powder pattern from vector array. * * Note: powder pattern parameters must have been set before calling this function, * for example by calling DiffractionDataPowder::InitPowderPatternPar(). */ void SetPowderPatternObs(const CrystVector_REAL& obs); ///Save powder pattern to one file, text format, 3 columns theta Iobs Icalc. ///If Iobs is missing, the column is omitted. /// /// \todo export in other formats (.prf,...), with a list of reflection /// position for all phases... void SavePowderPattern(const string &filename="powderPattern.out") const; /// Print to thee screen/console the observed and calculated pattern (long, /// mostly useful for debugging) void PrintObsCalcData(ostream&os=cout)const; // Statistics.. /** \brief Unweighted R-factor * * \return \f$ R= \sqrt {\frac{\sum_i \left( I_i^{obs}-I_i^{calc} \right)^2} * {\sum_i (I_i^{obs})^2} }\f$ */ REAL GetR()const ; REAL GetIntegratedR()const ; /** Get the weighted R-factor * \return \f$ R_{w}= \sqrt {\frac{\sum_i w_i\left( I_i^{obs}-I_i^{calc} \right)^2} * {\sum_i w_i (I_i^{obs})^2} }\f$ */ REAL GetRw()const; REAL GetIntegratedRw()const; /** \brief Return conventionnal Chi^2 * * \return \f$ \chi^2 = \sum_i w_i \left(I_i^{obs}-I_i^{calc} \right)^2 * \f$ */ REAL GetChi2()const; /** \brief Return integrated Chi^2 * */ REAL GetIntegratedChi2()const; /** Return the conventionnal or integrated Chi^2, depending on the option. * */ REAL GetChi2_Option()const; /// Fit the scale(s) factor of each component to minimize R void FitScaleFactorForR()const; void FitScaleFactorForIntegratedR()const; /// Fit the scale(s) factor of each component to minimize Rw void FitScaleFactorForRw()const; void FitScaleFactorForIntegratedRw()const; /// Set sigma=sqrt(Iobs) void SetSigmaToSqrtIobs(); /// Set w = 1/sigma^2. /// /// To filter too small or null intensities :If sigma< minRelatSigma* max(sigma), /// then w=1/(minRelatSigma* max(sigma))^2 void SetWeightToInvSigmaSq(const REAL minRelatSigma=1e-3); /// Set w = 1 void SetWeightToUnit(); /// Set w = 1/(a+ Iobs + b*Iobs^2+c*Iobs^3) /// /// To filter too small or null intensities: /// if Iobs < [minRelatIobs * max(Iobs)], then use Iobs=minRelatIobs * max(Iobs) /// to compute the weight. /// /// Typical values: a=2*min(Iobs) b=2/max(Iobs) c=0 void SetWeightPolynomial(const REAL a, const REAL b, const REAL c, const REAL minRelatIobs=1e-3); /// Add an Exclusion region, in 2theta, which will be ignored when computing R's /// XMLInput values must be, as always, in radians. Does not work yet with /// integrated R factors. /// Note that the pattern is still computed in these regions. They are only ignored /// by statistics functions (R, Rws). void AddExcludedRegion(const REAL min2Theta,const REAL max2theta); virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); //virtual void SetApproximationFlag(const bool allow); virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); virtual REAL GetLogLikelihood()const; //LSQ functions virtual unsigned int GetNbLSQFunction()const; virtual const CrystVector_REAL& GetLSQCalc(const unsigned int) const; virtual const CrystVector_REAL& GetLSQObs(const unsigned int) const; virtual const CrystVector_REAL& GetLSQWeight(const unsigned int) const; virtual std::map& GetLSQ_FullDeriv(const unsigned int,std::set &vPar); // I/O virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); void Prepare(); virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; /// Set the maximum value for sin(theta)/lambda. All data (reflections,..) still /// exist but are ignored for all calculations. virtual void SetMaxSinThetaOvLambda(const REAL max); /// Get the maximum value for sin(theta)/lambda. REAL GetMaxSinThetaOvLambda()const; // For integrated pattern calculations /// Get the list of first pixels for the integration intervals const CrystVector_long& GetIntegratedProfileMin()const; /// Get the list of last pixels for the integration intervals const CrystVector_long& GetIntegratedProfileMax()const; /// When were the integration intervals last changed ? const RefinableObjClock& GetIntegratedProfileLimitsClock()const; /// Get the experimental x (2theta, tof) from the theoretical value, taking /// into account all corrections (zero, transparency,..). /// \internal /// \param ttheta: the theoretical x (2theta, tof) value. /// \return the x (2theta, tof) value as it appears on the pattern. REAL X2XCorr(const REAL x)const; /// Get the pixel number on the experimental pattern, from the /// theoretical (uncorrected) x coordinate, taking into account all corrections. /// (zero, transparency,..). /// \internal /// \param x: the theoretical x (2theta, tof) value. /// \return the x (2theta, tof) value as it appears on the pattern. /// /// \warning: this can be real slow, especially for non-fixed steps. /// /// \warning: this returns the exact pixel coordinate, as a floating-point /// value, and \e not the closest pixel coordinate. REAL X2PixelCorr(const REAL x)const; /// Get the pixel number on the experimental pattern, corresponding /// to a given (experimental) x coordinate /// \param x: the x (2theta, tof) value. /// \return the x (2theta, tof) value as it appears on the pattern. /// /// \warning: this can be real slow, especially for non-fixed steps. /// /// \warning: this returns the exact pixel coordinate, as a floating-point /// value, and \e not the closest pixel coordinate. REAL X2Pixel(const REAL x)const; /// Convert sin(theta)/lambda to X (i.e. either to 2theta or to TOF), /// depending on the type of radiation. /// /// This does not take into account any zero/transparency, etc... correction REAL STOL2X(const REAL stol)const; /// Convert X (either 2theta or TOF) to sin(theta)/lambda, /// depending on the type of radiation. /// /// This does not take into account any zero/transparency, etc... correction REAL X2STOL(const REAL x)const; /// Convert sin(theta)/lambda to pixel, /// depending on the type of radiation. /// /// This does not take into account any zero/transparency, etc... correction REAL STOL2Pixel(const REAL stol)const; /// Find peaks in the pattern PeakList FindPeaks(const float dmin=2.0,const float maxratio=0.01,const unsigned int maxpeak=100); /// Access the scale factors (see PowderPattern::mScaleFactor) const CrystVector_REAL &GetScaleFactor() const; /// Access the scale factors (see PowderPattern::mScaleFactor) CrystVector_REAL &GetScaleFactor(); /** Export powder pattern & crystal structure in Fullprof format. * * This will create two files - the .pcr file (including the crystal structure * and all pattern parameters), and the .dat file with the powder pattern, * written using the "Ins=10" file format. * \param prefix: the prefix used to output the two files, 'prefix'.pcr and 'prefix'.dat * * \note: in development. Only supports constant wavelength neutron & X-ray patterns. */ void ExportFullprof(const std::string &prefix)const; /// Set the $\mu R$ value for cylinder absorption correction void SetMuR(const REAL muR); /// Get the $\mu R$ value REAL GetMuR() const; protected: /// Calc the powder pattern void CalcPowderPattern() const; void CalcPowderPattern_FullDeriv(std::set &vPar); /// Calc the integrated powder pattern void CalcPowderPatternIntegrated() const; void CalcPowderPatternIntegrated_FullDeriv(std::set &vPar); /// Init parameters and options virtual void Init(); /// Prepare the calculation of the integrated R-factors void PrepareIntegratedRfactor()const; /// Calculate the number of points of the pattern actually used, from the maximum /// value of sin(theta)/lambda void CalcNbPointUsed()const; /// Initialize options virtual void InitOptions(); /// The calculated powder pattern. It is mutable since it is /// completely defined by other parameters (eg it is not an 'independent parameter') mutable CrystVector_REAL mPowderPatternCalc; mutable std::map mPowderPattern_FullDeriv; /// The calculated powder pattern, integrated mutable CrystVector_REAL mPowderPatternIntegratedCalc; mutable std::map mPowderPatternIntegrated_FullDeriv; /// The calculated powder pattern part which corresponds to 'background' /// (eg non-scalable components). It is already included in mPowderPatternCalc mutable CrystVector_REAL mPowderPatternBackgroundCalc; /// The calculated powder pattern part which corresponds to 'background' /// (eg non-scalable components), integrated mutable CrystVector_REAL mPowderPatternBackgroundIntegratedCalc; /// The observed powder pattern. CrystVector_REAL mPowderPatternObs; /// The sigma of the observed pattern. CrystVector_REAL mPowderPatternObsSigma; /// The weight for each point of the pattern. mutable CrystVector_REAL mPowderPatternWeight; /// The complete variance associated to each point of the powder pattern, /// taking into account observation and model errors. mutable CrystVector_REAL mPowderPatternVariance; /// The complete variance associated to each point of the powder pattern, /// taking into account observation and model errors. Integrated. mutable CrystVector_REAL mPowderPatternVarianceIntegrated; /// The cumulative Chi^2 (integrated or not, depending on the option) mutable CrystVector_REAL mChi2Cumul; /// The calculated powder pattern. Cropped to the maximum sin(theta)/lambda for LSQ mutable CrystVector_REAL mPowderPatternUsedCalc; mutable std::map mPowderPatternUsed_FullDeriv; /// The calculated powder pattern. Cropped to the maximum sin(theta)/lambda for LSQ mutable CrystVector_REAL mPowderPatternUsedObs; /// The weight for each point of the pattern. Cropped to the maximum sin(theta)/lambda for LSQ mutable CrystVector_REAL mPowderPatternUsedWeight; /** Vector of x coordinates (either 2theta or time-of-flight) for the pattern * * Stored in ascending order for 2theta, and descending for TOF, i.e. always * in ascending order for the corresponding sin(theta)/lambda. */ CrystVector_REAL mX; /// Is the mX vector sorted in ascending order ? (true for 2theta, false for TOF) bool mIsXAscending; /// Number of points in the pattern unsigned long mNbPoint; /// The Radiation corresponding to this experiment Radiation mRadiation; // Clocks /// When were the pattern parameters (2theta or time-of-flight range) changed ? RefinableObjClock mClockPowderPatternPar; /// When were the radiation parameter (radiation type, wavelength) changed ? RefinableObjClock mClockPowderPatternRadiation; /// When was the powder pattern last computed ? mutable RefinableObjClock mClockPowderPatternCalc; /// When was the powder pattern (integrated) last computed ? mutable RefinableObjClock mClockPowderPatternIntegratedCalc; /// Corrections to 2Theta RefinableObjClock mClockPowderPatternXCorr; /// Last modification of the scale factor mutable RefinableObjClock mClockScaleFactor; /// Last modification of absorption correction parameters mutable RefinableObjClock mClockCorrAbs; //Excluded regions in the powder pattern, for statistics. /// Min coordinate for for all excluded regions CrystVector_REAL mExcludedRegionMinX; /// Max coordinate for 2theta for all excluded regions CrystVector_REAL mExcludedRegionMaxX; //Various corrections to 2theta-to be used by the components /// Zero correction : /// \f$ (2\theta)_{obs} = (2\theta)_{real} +(2\theta)_{0}\f$ ///Thus mPowderPattern2ThetaMin=(mPowderPattern2ThetaMin-m2ThetaZero) REAL mXZero; /// Displacement correction : ///\f$ (2\theta)_{obs} = (2\theta)_{real} + \frac{a}{\cos(\theta)} \f$ REAL m2ThetaDisplacement; /// Transparency correction : ///\f$ (2\theta)_{obs} = (2\theta)_{real} + b\sin(2\theta) \f$ REAL m2ThetaTransparency; /// Time Of Flight (TOF) parameters : ///\f$ t = DIFC*\frac{\sin(\theta)}{\lambda} + DIFA*\left(\frac{\sin(\theta)}{\lambda}\right)^2 + mXZero\f$ REAL mDIFC,mDIFA; // Components of the powder pattern /// The components (crystalline phases, background,...) of the powder pattern ObjRegistry mPowderPatternComponentRegistry; /// The scale factors for each component. For unscalable phases, /// this is set to 1 (constant). /// /// This is mutable because generally we use the 'best' scale factor, but /// it should not be... mutable CrystVector_REAL mScaleFactor; /// Mu*R parameter for cylinder absorption correction REAL mMuR; /// Use faster, less precise functions ? bool mUseFastLessPreciseFunc; // For statistics /// Should Statistics (R, Rw,..) exclude the background ? bool mStatisticsExcludeBackground; /// \internal To compute scale factors, which are the components (phases) that /// can be scaled ? mutable CrystVector_int mScalableComponentIndex; /// \internal Used to fit the components' scale factors mutable CrystMatrix_REAL mFitScaleFactorM,mFitScaleFactorB,mFitScaleFactorX; /// Use Integrated profiles for Chi^2, R, Rwp... RefObjOpt mOptProfileIntegration; // Integrated R-factors mutable CrystVector_long mIntegratedPatternMin,mIntegratedPatternMax; mutable CrystVector_REAL mIntegratedObs; mutable CrystVector_REAL mIntegratedWeight; mutable CrystVector_REAL mIntegratedWeightObs; mutable CrystVector_REAL mIntegratedVarianceObs; mutable RefinableObjClock mClockIntegratedFactorsPrep; // Statistical indicators mutable REAL mChi2,mIntegratedChi2; /// This is the logarithm of the part of log(Likelihood) which corresponds /// to the normalization terms of gaussian distribution for each obs/calc /// point. In practice, this is the sum of 1/2*log(2pi*sig(i)^2), although /// we discard the 2pi terms. mutable REAL mChi2LikeNorm,mIntegratedChi2LikeNorm; mutable REAL mR; mutable REAL mRw; ///Clock the last time Chi^2 was computed mutable RefinableObjClock mClockChi2,mClockIntegratedChi2; /** Maximum sin(theta)/lambda for all calculations (10 by default). * * This keeps all data in memory, but only the part which is below * the max is calculated. */ REAL mMaxSinThetaOvLambda; /// Number of points actually used, due to the maximum value of /// sin(theta)/lambda. mutable unsigned long mNbPointUsed; /// Number of integration intervals actually used, due to the maximum value of /// sin(theta)/lambda. mutable unsigned long mNbIntegrationUsed; /// Clock recording the last time the number of points used (PowderPattern::mNbPointUsed) /// was changed. mutable RefinableObjClock mClockNbPointUsed; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXPowderPattern; // This should be removed friend class WXPowderPatternGraph; #endif }; /// Global registry for all PowderPattern objects extern ObjRegistry gPowderPatternRegistry; //###################################################################### // PROFILE FUNCTIONS (for powder diffraction) //###################################################################### ///Gaussian, normalized (ie integral is equal to 1), as a function of theta /// and of the FWHM. The input is an array of the theta values. The maximum of the ///function is in theta=0. If asymmetry is used, negative tth values must be first. CrystVector_REAL PowderProfileGauss (const CrystVector_REAL theta, const REAL fwhm, const REAL asymmetryPar=1.); ///Lorentzian, normalized (ie integral is equal to 1), as a function of theta /// and of the FWHM. The input is an array of the theta values. The maximum of the ///function is in theta=0. If asymmetry is used, negative tth values must be first. CrystVector_REAL PowderProfileLorentz(const CrystVector_REAL theta, const REAL fwhm, const REAL asymmetryPar=1.); //###################################################################### // Spacegroup explorer //###################################################################### /** Structure to hold the score corresponding to a given spacegroup. * */ struct SPGScore { SPGScore(const string &s, const REAL r, const REAL g, const unsigned int nbextinct, const REAL ngof=0, const unsigned int nbrefl=0); string hm; /// Rw factor, from PowderPattern::GetRw() REAL rw; /// Goodness-of-fit, from PowderPattern::GetChi2() normalised by REAL gof; /// Normalised & integrated goodness-of-fit = iGoF * (nb_refl) / (nb_refl in P1), /// where iGoF is the integrated goodness-of-fit, computed using the integration /// intervals determined for the P1 spacegroup. This is only computed /// if the P1 spacegroup was tested first. REAL ngof; /// Number of extinct reflections for 0<=H<=4, 0<=K<=4, 0<=L<=6, which /// can be used as unique fingerprint for the spacegroup systematic extinctions. unsigned int nbextinct446; /// Number of reflections used for the fit. unsigned int nbreflused; }; bool compareSPGScore(const SPGScore &s1, const SPGScore &s2); /// Function which determines the unique extinction fingerprint of a spacegroup, /// by calculating all present reflections between 0<=H<=4 0<=K<=4 0<=L<=6 std::vector spgExtinctionFingerprint(Crystal &c, const cctbx::sgtbx::space_group &spg); /** Algorithm class to find the correct spacegroup for an indexed powder pattern. * */ class SpaceGroupExplorer { public: /** Constructor * * \param pd: the PowderPatternDiffraction for which we are trying to find the spacegroup. */ SpaceGroupExplorer(PowderPatternDiffraction *pd); /** Run test on a single spacegroup * * \param spg: the name of the spacegroup, ideally a Hall symbol, or an Hermann-Mauguin, * or a number * \param fitprofile: if true, will perform a full profile fitting instead of just Le Bail * extraction. Much slower. * \param restore_orig: if true, will go back to the original unit cell and spacegroup at the end * \param relative_length_tolerance: relative length tolerance to determine compatible unit cells * (i.e. the a/b ratio for quadratic spacegroups) * \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees * to determine compatible unit cells. * \return: the SPGScore corresponding to this spacegroup */ SPGScore Run(const string &spg, const bool fitprofile=false, const bool verbose=false, const bool restore_orig=false, const bool update_display=true, const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5); /** Run test on a single spacegroup * * \param spg: the cctbx::sgtbx::space_group * \param fitprofile: if true, will perform a full profile fitting instead of just Le Bail * extraction. Much slower. * \param restore_orig: if true, will go back to the original unit cell and spacegroup at the end * \param update_display: if true, update the display during the search * \param relative_length_tolerance: relative length tolerance to determine compatible unit cells * (i.e. the a/b ratio for quadratic spacegroups) * \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees * to determine compatible unit cells. * \return: the SPGScore corresponding to this spacegroup */ SPGScore Run(const cctbx::sgtbx::space_group &spg, const bool fitprofile=false, const bool verbose=false, const bool restore_orig=false, const bool update_display=true, const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5); /** Run test on all spacegroups compatible with the unit cell * Note that all scores's ngof values will be multiplied by nb_refl/nb_refl_P1 to * have a better indicator of the quality taking into account the number of reflections used. * * \param fitprofile_all: if true, will perform a full profile fitting instead of just Le Bail * extraction for all spacegroups. Much slower. By default, the profile fitting is only * performed for the first spacegroup (P1) * \param verbose: 0 (default), not verbose, 1 minimal information, 2, very verbose * \param keep_best: if true, will keep the best solution at the end (default: restore the original one) * \param update_display: if true, update the display during the search * \param fitprofile_p1: if true, fit the profile for p1 (ignored if fitprofile_all=true) * \param relative_length_tolerance: relative length tolerance to determine compatible unit cells * (i.e. the a/b ratio for quadratic spacegroups) * \param absolute_angle_tolerance_degree: the absolute angular tolerance in degrees * to determine compatible unit cells. * \return: the SPGScore corresponding to this spacegroup */ void RunAll(const bool fitprofile_all=false, const bool verbose=true, const bool keep_best=false, const bool update_display=true, const bool fitprofile_p1=true, const REAL relative_length_tolerance=0.01, const REAL absolute_angle_tolerance_degree=0.5); /// Get the list of all scores obatined after using RunAll() const list& GetScores() const; private: /// Compute the integrated goodness-of-fit using P1 integration intervals. If this is called /// and the spacegroup is P1, this initialises the P1 intervals as well. If the intervals /// have not been initialised and the spaceroup is not P1, zero is returned. REAL GetP1IntegratedGoF(); /// PwderPatternDiffraction for which we explore the spacegroups PowderPatternDiffraction *mpDiff; /// Min and max of intervals for integration domains, for the P1 specegroup. This is /// used to compute a normalised integrated goodness of fit using the same intervals CrystVector_REAL mP1IntegratedProfileMin,mP1IntegratedProfileMax; /// List of scores for the explore spacegroups list mvSPG; /// Map extinction fingerprint std::map,SPGScore> mvSPGExtinctionFingerprint; }; }//namespace ObjCryst #endif // _OBJCRYST_POWDERPATTERN_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PowderPatternBackgroundBayesianMinimiser.cpp000066400000000000000000000120151417150057700316760ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* PowderPatternBackgroundBayesianMinimiser.h * Bayesian estimation of powder pattern background * */ #include "ObjCryst/ObjCryst/PowderPatternBackgroundBayesianMinimiser.h" namespace ObjCryst { PowderPatternBackgroundBayesianMinimiser:: PowderPatternBackgroundBayesianMinimiser(PowderPatternBackground &backgd): mpBackground(&backgd) { this->AddSubRefObj(*mpBackground); } PowderPatternBackgroundBayesianMinimiser::~PowderPatternBackgroundBayesianMinimiser() { this->RemoveSubRefObj(*mpBackground); } const string& PowderPatternBackgroundBayesianMinimiser::GetClassName()const { static string className="PowderPatternBackgroundBayesianMinimiser"; return className; } REAL PowderPatternBackgroundBayesianMinimiser::GetLogLikelihood()const { TAU_PROFILE("PowderPatternBackgroundBayesianMinimiser::GetLogLikelihood()","void ()",TAU_DEFAULT); REAL llk=0; const long nb=mpBackground->GetPowderPatternCalc().numElements(); const long step=1; {// Calc (obs-calc)/sigma const REAL *pBackgd=mpBackground->GetPowderPatternCalc().data(); const REAL *pObs=mpBackground->GetParentPowderPattern().GetPowderPatternObs().data(); const REAL *pSigma=mpBackground->GetParentPowderPattern().GetPowderPatternObsSigma().data(); for(long i=0;i0) { llk += PowderPatternBackgroundBayesianMinimiser ::BayesianBackgroundLogLikelihood ((*pObs-*pBackgd) / (1.4142135623730951**pSigma)); } pObs+=step; pBackgd+=step; pSigma+=step; } } return llk; } unsigned int PowderPatternBackgroundBayesianMinimiser::GetNbLSQFunction () const {return 1;} const CrystVector_REAL& PowderPatternBackgroundBayesianMinimiser::GetLSQCalc (const unsigned int id) const { const long nb=mpBackground->GetPowderPatternCalc().numElements(); const long step=1; if(mBayesianCalc.numElements()!=nb) mBayesianCalc.resize(nb); const REAL *pBackgd=mpBackground->GetPowderPatternCalc().data(); const REAL *pObs=mpBackground->GetParentPowderPattern().GetPowderPatternObs().data(); const REAL *pSigma=mpBackground->GetParentPowderPattern().GetPowderPatternObsSigma().data(); REAL *pBayesCalc=mBayesianCalc.data(); for(long i=0;i0) { *pBayesCalc = 1 + PowderPatternBackgroundBayesianMinimiser::BayesianBackgroundLogLikelihood((*pObs-*pBackgd) / (1.4142135623730951**pSigma)); } else *pBayesCalc = 1; pObs+=step; pBackgd+=step; pSigma+=step; pBayesCalc+=step; } return mBayesianCalc; } const CrystVector_REAL& PowderPatternBackgroundBayesianMinimiser::GetLSQObs (const unsigned int) const { const long nb=mpBackground->GetPowderPatternCalc().numElements(); if(mBayesianObs.numElements()!=nb) { mBayesianObs.resize(nb); mBayesianObs=1; // Avoid having all observed values==0, raises issues when computing R and Rw in LSQNumObj } return mBayesianObs; } const CrystVector_REAL& PowderPatternBackgroundBayesianMinimiser::GetLSQWeight (const unsigned int) const { const long nb=mpBackground->GetPowderPatternCalc().numElements(); if(mBayesianWeight.numElements()!=nb) { mBayesianWeight.resize(nb); mBayesianWeight=1; } return mBayesianWeight; } REAL PowderPatternBackgroundBayesianMinimiser::BayesianBackgroundLogLikelihood(const REAL t) { static const REAL vllk[11]={0.00000000e+00, 1e-4, 1.77123249e-03, 1.00997634e+00, 2.89760310e+00, 3.61881096e+00, 3.93024374e+00, 4.16063018e+00, 4.34600620e+00, 4.50155649e+00, 4.63573160e+00}; static const REAL vt[11]={ 0. , 0.01, 0.1 , 1.1 , 2.1 , 3.1 , 4.1 , 5.1 , 6.1 , 7.1 , 8.1}; static const CubicSpline spline(vt,vllk,11); static const REAL s1=spline(8)-log((REAL)8); if(t<=0) return 5*t*t; if(t<8)return spline(t); return s1+log(t); } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/PowderPatternBackgroundBayesianMinimiser.h000066400000000000000000000074641417150057700313570ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* PowderPatternBackgroundBayesianMinimiser.h * Bayesian estimation of powder pattern background * */ #ifndef __POWDERPATTERNBACKGROUNDBAYESIANMINIMISER_H #define __POWDERPATTERNBACKGROUNDBAYESIANMINIMISER_H #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/ObjCryst/PowderPattern.h" namespace ObjCryst { /** This object is used to estimate the background in a powder pattern, * using a Bayesian approach (David & Sivia, Acta Cryst A50 (1994), 703) * */ class PowderPatternBackgroundBayesianMinimiser:public RefinableObj { public: PowderPatternBackgroundBayesianMinimiser(PowderPatternBackground &backgd); ~PowderPatternBackgroundBayesianMinimiser(); virtual const string& GetClassName()const; virtual REAL GetLogLikelihood()const; virtual unsigned int GetNbLSQFunction () const ; virtual const CrystVector_REAL & GetLSQCalc (const unsigned int) const; virtual const CrystVector_REAL & GetLSQObs (const unsigned int) const; virtual const CrystVector_REAL & GetLSQWeight (const unsigned int) const; //private: /** Returns the log(likelihood) of a background by marginalizing the effect of Bragg peaks, following the method described by David and Sivia (\e J.Appl.Cryst. \b 34(2001), 318). * * \returns * - \f$ L(t) = \frac{\left(y^{calc}_{Background}-y^{obs}\right)^2}{2\sigma^2}\f$ * for \t<0 * - \f$ L(t) = A-\log{\int_\epsilon^{\infty} {\frac{1}{u} e^{-(t-u)^2} du}}\f$ for t>0, * with: \f$\epsilon = 1e-6\f$, \f$ t = \frac{y^{calc}_{Background}-y^{obs}}{\sigma\sqrt{2}}\f$ * and A a normalizing constant so that the function is continuous for t=0 (i.e. \e L(0)=0). * * \param \f$ t = \frac{y^{calc}_{Background}-y^{obs}}{\sigma\sqrt{2}}\f$ * * For small \e t>0 values, \e L(t) behaves like a quadratic function, and for large * positive values it is equivalent to \f$ \log{\frac{\sqrt{\pi}}{t}}\f$. * * As the integral diverges for \f$\epsilon=0\f$, it is necessary to use * a small, non-null \f$\epsilon\f$. The use of a smaller \f$\epsilon\f$ changes * the range over which the function behaves quadratically, as well as the maximum * value (at \e t=0), but does not affect the asymptotic value. * * See tabulated values in the source code. The function is approximated with a cubic * spline until \e t=8, and then uses the asymptotic\f$A-\log{\frac{\sqrt{\pi}}{t}}\f$ value. * * \note For a more strict calculation, we should include a normalizing constant (?) */ static REAL BayesianBackgroundLogLikelihood(const REAL t); PowderPatternBackground *mpBackground; /// Bayesian cost (-log(likelihood)) for each point mutable CrystVector_REAL mBayesianCalc; /// Obs==0 (desired -log(likelihood)) mutable CrystVector_REAL mBayesianObs; /// Weight=1 mutable CrystVector_REAL mBayesianWeight; }; }//namespace #endif //__POWDERPATTERNBACKGROUNDBAYESIANMINIMISER_H libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ReflectionProfile.cpp000066400000000000000000001611211417150057700251650ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2005 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for LibCryst++ ReflectionProfile and derived classes * */ #include #include "ObjCryst/ObjCryst/ReflectionProfile.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxPowderPattern.h" #endif #ifdef HAVE_SSE_MATHFUN #include "ObjCryst/Quirks/sse_mathfun.h" #endif namespace ObjCryst { #if defined(_MSC_VER) || defined(__BORLANDC__) #undef min // Predefined macros.... (wx?) #undef max double erfc(const double x)// in C99, but not in VC++.... { if(x<0.0) return 2.0-erfc(-x); if(x<3.8) { // Series, Abramowitz & Stegun 7.1.6 double y=x,y0=x; for(int i=1;i<=50;i++) { y0*=2*x*x/(2*i+1.0); y+=y0; } static const double spi=2/sqrt(M_PI); return 1-spi*exp(-x*x)*y; } double y=1.0,y0=1.0; for(int i=1;i<=10;i++) {// Asymptotic, Abramowitz & Stegun 7.1.23 y0*=-(2*i-1)/(2*x*x); y+=y0; } static const double invsqrtpi=1.0/sqrt(M_PI); return invsqrtpi*exp(-x*x)/x*y; } #endif extern const RefParType *gpRefParTypeScattDataProfile; extern const RefParType *gpRefParTypeScattDataProfileType; extern const RefParType *gpRefParTypeScattDataProfileWidth; extern const RefParType *gpRefParTypeScattDataProfileAsym; ObjRegistry gReflectionProfileRegistry("List of all ReflectionProfile types");; //////////////////////////////////////////////////////////////////////// // // ReflectionProfile // //////////////////////////////////////////////////////////////////////// ReflectionProfile::ReflectionProfile(): RefinableObj() {} ReflectionProfile::ReflectionProfile(const ReflectionProfile &old) {} ReflectionProfile::~ReflectionProfile() {} bool ReflectionProfile::IsAnisotropic()const {return false;} //////////////////////////////////////////////////////////////////////// // // ReflectionProfilePseudoVoigt // //////////////////////////////////////////////////////////////////////// ReflectionProfilePseudoVoigt::ReflectionProfilePseudoVoigt(): ReflectionProfile(), mCagliotiU(0),mCagliotiV(0),mCagliotiW(.01*DEG2RAD*DEG2RAD), mPseudoVoigtEta0(0.5),mPseudoVoigtEta1(0.0), mAsymBerarBaldinozziA0(0.0),mAsymBerarBaldinozziA1(0.0), mAsymBerarBaldinozziB0(0.0),mAsymBerarBaldinozziB1(0.0), mAsym0(1.0),mAsym1(0.0),mAsym2(0.0) { this->InitParameters(); } ReflectionProfilePseudoVoigt::ReflectionProfilePseudoVoigt (const ReflectionProfilePseudoVoigt &old): mCagliotiU(old.mCagliotiU),mCagliotiV(old.mCagliotiV),mCagliotiW(old.mCagliotiW), mPseudoVoigtEta0(old.mPseudoVoigtEta0),mPseudoVoigtEta1(old.mPseudoVoigtEta1), mAsymBerarBaldinozziA0(old.mAsymBerarBaldinozziA0), mAsymBerarBaldinozziA1(old.mAsymBerarBaldinozziA1), mAsymBerarBaldinozziB0(old.mAsymBerarBaldinozziB0), mAsymBerarBaldinozziB1(old.mAsymBerarBaldinozziB1), mAsym0(old.mAsym0),mAsym1(old.mAsym1),mAsym2(old.mAsym2) { this->InitParameters(); } ReflectionProfilePseudoVoigt::~ReflectionProfilePseudoVoigt() { #ifdef __WX__CRYST__ if(mpWXCrystObj!=0) { delete mpWXCrystObj; mpWXCrystObj=0; } #endif } ReflectionProfilePseudoVoigt* ReflectionProfilePseudoVoigt::CreateCopy()const { return new ReflectionProfilePseudoVoigt(*this); } const string& ReflectionProfilePseudoVoigt::GetClassName()const { static string className="ReflectionProfilePseudoVoigt"; return className; } CrystVector_REAL ReflectionProfilePseudoVoigt::GetProfile(const CrystVector_REAL &x, const REAL center,const REAL h, const REAL k, const REAL l)const { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::GetProfile(),c="<1) eta=1; if(eta<0) eta=0; profile *= 1-eta; tmpV=PowderProfileLorentz(x,fwhm,center,asym); tmpV *= eta; profile += tmpV; //profile *= AsymmetryBerarBaldinozzi(x,fwhm,center, // mAsymBerarBaldinozziA0,mAsymBerarBaldinozziA1, // mAsymBerarBaldinozziB0,mAsymBerarBaldinozziB1); VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigt::GetProfile()",2) return profile; } void ReflectionProfilePseudoVoigt::SetProfilePar(const REAL fwhmCagliotiW, const REAL fwhmCagliotiU, const REAL fwhmCagliotiV, const REAL eta0, const REAL eta1) { mCagliotiU=fwhmCagliotiU; mCagliotiV=fwhmCagliotiV; mCagliotiW=fwhmCagliotiW; mPseudoVoigtEta0=eta0; mPseudoVoigtEta1=eta1; mClockMaster.Click(); } bool ReflectionProfilePseudoVoigt::IsAnisotropic()const{return false;} REAL ReflectionProfilePseudoVoigt::GetFullProfileWidth(const REAL relativeIntensity, const REAL center,const REAL h, const REAL k, const REAL l) { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::GetFullProfileWidth()",2) const int nb=100; const int halfnb=nb/2; CrystVector_REAL x(nb); REAL n=5.0; REAL fwhm= mCagliotiW +mCagliotiV*tan(center/2.0) +mCagliotiU*pow(tan(center/2.0),2); if(fwhm<=0) fwhm=1e-6; else fwhm=sqrt(fwhm); CrystVector_REAL prof; while(true) { //Create an X array with 100 elements reaching +/- n*FWHM/2 REAL *p=x.data(); const REAL tmp=fwhm*n/nb; for(int i=0;iGetProfile(x,center,0,0,0); const REAL max=prof.max(); const REAL test=max*relativeIntensity; int n1=0,n2=0; if((prof(0)test){ p++; n2++;} VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigt::GetFullProfileWidth():"<(x,prof),2) n*=2.0; //if(n>200) exit(0); } } void ReflectionProfilePseudoVoigt::InitParameters() { { RefinablePar tmp("U",&mCagliotiU,-1/RAD2DEG/RAD2DEG,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("V",&mCagliotiV,-1/RAD2DEG/RAD2DEG,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("W",&mCagliotiW,0,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("Eta0",&mPseudoVoigtEta0,0,1.,gpRefParTypeScattDataProfileType, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Eta1",&mPseudoVoigtEta1,-1,1.,gpRefParTypeScattDataProfileType, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } #if 0 { RefinablePar tmp("AsymA0",&mAsymBerarBaldinozziA0,-0.05,0.05,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("AsymA1",&mAsymBerarBaldinozziA1,-0.05,0.05,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("AsymB0",&mAsymBerarBaldinozziB0,-0.01,0.01,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("AsymB1",&mAsymBerarBaldinozziB1,-0.01,0.01,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } #endif { RefinablePar tmp("Asym0",&mAsym0,0.01,10.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Asym1",&mAsym1,-1.0,1.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Asym2",&mAsym2,-1.0,1.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } } void ReflectionProfilePseudoVoigt::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mCagliotiU).XMLOutput(os,"U",indent); os <GetPar(&mCagliotiV).XMLOutput(os,"V",indent); os <GetPar(&mCagliotiW).XMLOutput(os,"W",indent); os <GetPar(&mPseudoVoigtEta0).XMLOutput(os,"Eta0",indent); os <GetPar(&mPseudoVoigtEta1).XMLOutput(os,"Eta1",indent); os <GetPar(&mAsym0).XMLOutput(os,"Asym0",indent); os <GetPar(&mAsym1).XMLOutput(os,"Asym1",indent); os <GetPar(&mAsym2).XMLOutput(os,"Asym2",indent); os <GetPar(&mAsymBerarBaldinozziA0).XMLOutput(os,"AsymA0",indent); os <GetPar(&mAsymBerarBaldinozziA1).XMLOutput(os,"AsymA1",indent); os <GetPar(&mAsymBerarBaldinozziB0).XMLOutput(os,"AsymB0",indent); os <GetPar(&mAsymBerarBaldinozziB1).XMLOutput(os,"AsymB1",indent); os <GetName(),5) } void ReflectionProfilePseudoVoigt::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); } while(true) { XMLCrystTag tag(is); if(("ReflectionProfilePseudoVoigt"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigt::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mCagliotiU).XMLInput(is,tag); break; } if("V"==tag.GetAttributeValue(i)) { this->GetPar(&mCagliotiV).XMLInput(is,tag); break; } if("W"==tag.GetAttributeValue(i)) { this->GetPar(&mCagliotiW).XMLInput(is,tag); break; } if("Eta0"==tag.GetAttributeValue(i)) { this->GetPar(&mPseudoVoigtEta0).XMLInput(is,tag); break; } if("Eta1"==tag.GetAttributeValue(i)) { this->GetPar(&mPseudoVoigtEta1).XMLInput(is,tag); break; } if("Asym0"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym0).XMLInput(is,tag); break; } if("Asym1"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym1).XMLInput(is,tag); break; } if("Asym2"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym2).XMLInput(is,tag); break; } #if 0 if("AsymA0"==tag.GetAttributeValue(i)) { this->GetPar(&mAsymBerarBaldinozziA0).XMLInput(is,tag); break; } if("AsymA1"==tag.GetAttributeValue(i)) { this->GetPar(&mAsymBerarBaldinozziA1).XMLInput(is,tag); break; } if("AsymB0"==tag.GetAttributeValue(i)) { this->GetPar(&mAsymBerarBaldinozziB0).XMLInput(is,tag); break; } if("AsymB1"==tag.GetAttributeValue(i)) { this->GetPar(&mAsymBerarBaldinozziB1).XMLInput(is,tag); break; } #endif } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iInitParameters(); } ReflectionProfilePseudoVoigtAnisotropic::ReflectionProfilePseudoVoigtAnisotropic(const ReflectionProfilePseudoVoigtAnisotropic &old): mCagliotiU(old.mCagliotiU),mCagliotiV(old.mCagliotiV),mCagliotiW(old.mCagliotiW),mScherrerP(old.mScherrerP),mLorentzX(old.mLorentzX),mLorentzY(old.mLorentzY), mLorentzGammaHH(old.mLorentzGammaHH),mLorentzGammaKK(old.mLorentzGammaKK),mLorentzGammaLL(old.mLorentzGammaLL),mLorentzGammaHK(old.mLorentzGammaHK),mLorentzGammaHL(old.mLorentzGammaHL),mLorentzGammaKL(old.mLorentzGammaKL), mPseudoVoigtEta0(old.mPseudoVoigtEta0),mPseudoVoigtEta1(old.mPseudoVoigtEta1),mAsym0(old.mAsym0),mAsym1(old.mAsym1),mAsym2(old.mAsym2) { this->InitParameters(); } ReflectionProfilePseudoVoigtAnisotropic::~ReflectionProfilePseudoVoigtAnisotropic() { #ifdef __WX__CRYST__ if(mpWXCrystObj!=0) { delete mpWXCrystObj; mpWXCrystObj=0; } #endif } ReflectionProfilePseudoVoigtAnisotropic* ReflectionProfilePseudoVoigtAnisotropic::CreateCopy()const { return new ReflectionProfilePseudoVoigtAnisotropic(*this); } const string& ReflectionProfilePseudoVoigtAnisotropic::GetClassName()const { static string className="ReflectionProfilePseudoVoigtAnisotropic"; return className; } CrystVector_REAL ReflectionProfilePseudoVoigtAnisotropic::GetProfile(const CrystVector_REAL &x, const REAL center, const REAL h, const REAL k, const REAL l)const { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigtAnisotropic::GetProfile()",2) const REAL tantheta=tan(center/2.0); const REAL costheta=cos(center/2.0); const REAL sintheta=sin(center/2.0); const REAL fwhmG=sqrt(abs( mCagliotiW+mCagliotiV*tantheta+mCagliotiU*tantheta*tantheta+mScherrerP/(costheta*costheta))); const REAL gam=mLorentzGammaHH*h*h+mLorentzGammaKK*k*k+mLorentzGammaLL*l*l+2*mLorentzGammaHK*h*k+2*mLorentzGammaHL*h*l+2*mLorentzGammaKL*k*l; const REAL fwhmL= mLorentzX/costheta+(mLorentzY+gam/(sintheta*sintheta))*tantheta; // Eta for gaussian/lorentzian mix. Make sure 0<=eta<=1, else profiles could be <0 ! REAL eta=mPseudoVoigtEta0+center*mPseudoVoigtEta1; if(eta>1) eta=1; if(eta<0) eta=0; CrystVector_REAL profile(x.numElements()),tmpV(x.numElements()); const REAL asym=mAsym0+mAsym1/sin(center)+mAsym2/pow((REAL)sin(center),(REAL)2.0); VFN_DEBUG_MESSAGE("ReflectionProfilePseudoVoigtAnisotropic::GetProfile():("<0) { profile=PowderProfileGauss(x,fwhmG,center,asym); profile *= 1-eta; } else profile=0; if(fwhmL>0) { tmpV=PowderProfileLorentz(x,fwhmL,center,asym); tmpV *= eta; profile += tmpV; } VFN_DEBUG_MESSAGE(FormatVertVector(x,profile),1) VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigtAnisotropic::GetProfile()",2) return profile; } void ReflectionProfilePseudoVoigtAnisotropic::SetProfilePar(const REAL fwhmCagliotiW, const REAL fwhmCagliotiU, const REAL fwhmCagliotiV, const REAL fwhmGaussP, const REAL fwhmLorentzX, const REAL fwhmLorentzY, const REAL fwhmLorentzGammaHH, const REAL fwhmLorentzGammaKK, const REAL fwhmLorentzGammaLL, const REAL fwhmLorentzGammaHK, const REAL fwhmLorentzGammaHL, const REAL fwhmLorentzGammaKL, const REAL pseudoVoigtEta0, const REAL pseudoVoigtEta1, const REAL asymA0, const REAL asymA1, const REAL asymA2 ) { mCagliotiU=fwhmCagliotiU; mCagliotiV=fwhmCagliotiV; mCagliotiW=fwhmCagliotiW; mLorentzX=fwhmLorentzX; mLorentzY=fwhmLorentzY; mLorentzGammaHH=fwhmLorentzGammaHH; mLorentzGammaKK=fwhmLorentzGammaKK; mLorentzGammaLL=fwhmLorentzGammaLL; mLorentzGammaHK=fwhmLorentzGammaHK; mLorentzGammaHL=fwhmLorentzGammaHL; mLorentzGammaKL=fwhmLorentzGammaKL; mPseudoVoigtEta0=pseudoVoigtEta0; mPseudoVoigtEta1=pseudoVoigtEta1; mAsym0=asymA0; mAsym1=asymA1; mAsym2=asymA2; mClockMaster.Click(); } REAL ReflectionProfilePseudoVoigtAnisotropic::GetFullProfileWidth(const REAL relativeIntensity, const REAL center, const REAL h, const REAL k, const REAL l) { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::GetFullProfileWidth()",2) const int nb=100; const int halfnb=nb/2; CrystVector_REAL x(nb); REAL n=5.0; const REAL tantheta=tan(center/2.0); const REAL costheta=cos(center/2.0); const REAL sintheta=sin(center/2.0); const REAL fwhmG=sqrt(abs( mCagliotiW+mCagliotiV*tantheta+mCagliotiU*tantheta*tantheta+mScherrerP/(costheta*costheta))); const REAL gam=mLorentzGammaHH*h*h+mLorentzGammaKK*k*k+mLorentzGammaLL*l*l+2*mLorentzGammaHK*h*k+2*mLorentzGammaHL*h*l+2*mLorentzGammaKL*k*l; const REAL fwhmL= mLorentzX/costheta+(mLorentzY+gam/(sintheta*sintheta))*tantheta; const REAL eta=mPseudoVoigtEta0+mPseudoVoigtEta1*center; // Obviously this is not the REAL FWHM, just a _very_ crude starting approximation REAL fwhm=fwhmL*eta+fwhmG*(1-eta); if(fwhm<=0) fwhm=1e-3; CrystVector_REAL prof; while(true) { //Create an X array with 100 elements reaching +/- n*FWHM/2 REAL *p=x.data(); const REAL tmp=fwhm*n/nb; for(int i=0;iGetProfile(x,center,h,k,l); const REAL max=prof.max(); const REAL test=max*relativeIntensity; int n1=0,n2=0; if((prof(0)test){ p++; n2++;} VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigtAnisotropic::GetFullProfileWidth():"<(x,prof),1) n*=2.0; } } bool ReflectionProfilePseudoVoigtAnisotropic::IsAnisotropic()const { return true; } void ReflectionProfilePseudoVoigtAnisotropic::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigtAnisotropic::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mCagliotiU).XMLOutput(os,"U",indent); os <GetPar(&mCagliotiV).XMLOutput(os,"V",indent); os <GetPar(&mCagliotiW).XMLOutput(os,"W",indent); os <GetPar(&mScherrerP).XMLOutput(os,"P",indent); os <GetPar(&mLorentzX).XMLOutput(os,"X",indent); os <GetPar(&mLorentzY).XMLOutput(os,"Y",indent); os <GetPar(&mLorentzGammaHH).XMLOutput(os,"G_HH",indent); os <GetPar(&mLorentzGammaKK).XMLOutput(os,"G_KK",indent); os <GetPar(&mLorentzGammaLL).XMLOutput(os,"G_LL",indent); os <GetPar(&mLorentzGammaHK).XMLOutput(os,"G_HK",indent); os <GetPar(&mLorentzGammaHL).XMLOutput(os,"G_HL",indent); os <GetPar(&mLorentzGammaKL).XMLOutput(os,"G_KL",indent); os <GetPar(&mPseudoVoigtEta0).XMLOutput(os,"Eta0",indent); os <GetPar(&mPseudoVoigtEta1).XMLOutput(os,"Eta1",indent); os <GetPar(&mAsym0).XMLOutput(os,"Asym0",indent); os <GetPar(&mAsym1).XMLOutput(os,"Asym1",indent); os <GetPar(&mAsym2).XMLOutput(os,"Asym2",indent); os <GetName(),5) } void ReflectionProfilePseudoVoigtAnisotropic::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigtAnisotropic::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); } while(true) { XMLCrystTag tag(is); if(("ReflectionProfilePseudoVoigtAnisotropic"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigtAnisotropic::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mCagliotiU).XMLInput(is,tag); break; } if("V"==tag.GetAttributeValue(i)) { this->GetPar(&mCagliotiV).XMLInput(is,tag); break; } if("W"==tag.GetAttributeValue(i)) { this->GetPar(&mCagliotiW).XMLInput(is,tag); break; } if("P"==tag.GetAttributeValue(i)) { this->GetPar(&mScherrerP).XMLInput(is,tag); break; } if("X"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzX).XMLInput(is,tag); break; } if("Y"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzY).XMLInput(is,tag); break; } if("G_HH"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaHH).XMLInput(is,tag); break; } if("G_KK"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaKK).XMLInput(is,tag); break; } if("G_LL"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaLL).XMLInput(is,tag); break; } if("G_HK"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaHK).XMLInput(is,tag); break; } if("G_HL"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaHL).XMLInput(is,tag); break; } if("G_KL"==tag.GetAttributeValue(i)) { this->GetPar(&mLorentzGammaKL).XMLInput(is,tag); break; } if("Eta0"==tag.GetAttributeValue(i)) { this->GetPar(&mPseudoVoigtEta0).XMLInput(is,tag); break; } if("Eta1"==tag.GetAttributeValue(i)) { this->GetPar(&mPseudoVoigtEta1).XMLInput(is,tag); break; } if("Asym0"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym0).XMLInput(is,tag); break; } if("Asym1"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym1).XMLInput(is,tag); break; } if("Asym2"==tag.GetAttributeValue(i)) { this->GetPar(&mAsym2).XMLInput(is,tag); break; } } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iAddPar(tmp); } { RefinablePar tmp("V",&mCagliotiV,-1/RAD2DEG/RAD2DEG,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("W",&mCagliotiW,0,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("P",&mScherrerP,-1./RAD2DEG/RAD2DEG,1./RAD2DEG/RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG*RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("X",&mLorentzX,0,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("Y",&mLorentzY,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_HH",&mLorentzGammaHH,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_KK",&mLorentzGammaKK,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_LL",&mLorentzGammaLL,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_HK",&mLorentzGammaHK,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_HL",&mLorentzGammaHL,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("G_KL",&mLorentzGammaKL,-1./RAD2DEG,1./RAD2DEG, gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,RAD2DEG); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-9); this->AddPar(tmp); } { RefinablePar tmp("Eta0",&mPseudoVoigtEta0,0,1.,gpRefParTypeScattDataProfileType, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Eta1",&mPseudoVoigtEta1,-1,1.,gpRefParTypeScattDataProfileType, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Asym0",&mAsym0,0.01,10.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Asym1",&mAsym1,-1.0,1.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("Asym2",&mAsym2,-1.0,1.0,gpRefParTypeScattDataProfileAsym, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } } #ifdef __WX__CRYST__ WXCrystObjBasic* ReflectionProfilePseudoVoigtAnisotropic::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("ReflectionProfilePseudoVoigt::WXCreate()",6) if(mpWXCrystObj==0) mpWXCrystObj=new WXProfilePseudoVoigtAnisotropic(parent,this); VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigt::WXCreate()",6) return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // ReflectionProfileDoubleExponentialPseudoVoigt // //////////////////////////////////////////////////////////////////////// ReflectionProfileDoubleExponentialPseudoVoigt::ReflectionProfileDoubleExponentialPseudoVoigt(): ReflectionProfile(), mInstrumentAlpha0(0.0), mInstrumentAlpha1(0.0952), mInstrumentBeta0(0.0239), mInstrumentBeta1(0.0043), mGaussianSigma0(0.0), mGaussianSigma1(7.0), mGaussianSigma2(0.0), mLorentzianGamma0(0.0), mLorentzianGamma1(0.0), mLorentzianGamma2(0.414), mpCell(0) { VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::ReflectionProfileDoubleExponentialPseudoVoigt()",10) this->InitParameters(); } ReflectionProfileDoubleExponentialPseudoVoigt ::ReflectionProfileDoubleExponentialPseudoVoigt(const UnitCell &cell): ReflectionProfile(), mInstrumentAlpha0(0.0), mInstrumentAlpha1(0.0952), mInstrumentBeta0(0.0239), mInstrumentBeta1(0.0043), mGaussianSigma0(0.0), mGaussianSigma1(7.0), mGaussianSigma2(0.0), mLorentzianGamma0(0.0), mLorentzianGamma1(0.0), mLorentzianGamma2(0.414), mpCell(&cell) { VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::ReflectionProfileDoubleExponentialPseudoVoigt()",10) this->InitParameters(); } ReflectionProfileDoubleExponentialPseudoVoigt::ReflectionProfileDoubleExponentialPseudoVoigt (const ReflectionProfileDoubleExponentialPseudoVoigt &old): ReflectionProfile(), mInstrumentAlpha0(old.mInstrumentAlpha0), mInstrumentAlpha1(old.mInstrumentAlpha1), mInstrumentBeta0(old.mInstrumentBeta0), mInstrumentBeta1(old.mInstrumentBeta1), mGaussianSigma0(old.mGaussianSigma0), mGaussianSigma1(old.mGaussianSigma1), mGaussianSigma2(old.mGaussianSigma2), mLorentzianGamma0(old.mLorentzianGamma0), mLorentzianGamma1(old.mLorentzianGamma1), mLorentzianGamma2(old.mLorentzianGamma2), mpCell(old.mpCell) { VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::ReflectionProfileDoubleExponentialPseudoVoigt()",10) this->InitParameters(); } ReflectionProfileDoubleExponentialPseudoVoigt::~ReflectionProfileDoubleExponentialPseudoVoigt() { #ifdef __WX__CRYST__ if(mpWXCrystObj!=0) { delete mpWXCrystObj; mpWXCrystObj=0; } #endif } ReflectionProfileDoubleExponentialPseudoVoigt* ReflectionProfileDoubleExponentialPseudoVoigt::CreateCopy()const { return new ReflectionProfileDoubleExponentialPseudoVoigt(*this); } const string& ReflectionProfileDoubleExponentialPseudoVoigt::GetClassName()const { static string className="ReflectionProfileDoubleExponentialPseudoVoigt"; return className; } CrystVector_REAL ReflectionProfileDoubleExponentialPseudoVoigt ::GetProfile(const CrystVector_REAL &x, const REAL center, const REAL h, const REAL k, const REAL l)const { VFN_DEBUG_ENTRY("ReflectionProfileDoubleExponentialPseudoVoigt::GetProfile()",4) REAL dcenter=0; if(mpCell!=0) { REAL hh=h,kk=k,ll=l;// orthonormal coordinates in reciprocal space mpCell->MillerToOrthonormalCoords(hh,kk,ll); dcenter=1.0/sqrt(hh*hh+kk*kk+ll*ll);//d_hkl, in Angstroems } const REAL alpha=mInstrumentAlpha0+mInstrumentAlpha1/dcenter; const REAL beta=mInstrumentBeta0+mInstrumentBeta1/pow(dcenter,4); const REAL siggauss2= mGaussianSigma0 +mGaussianSigma1*pow(dcenter,2) +mGaussianSigma2*pow(dcenter,4); static const REAL log2=log(2.0); const REAL hg=sqrt(8*siggauss2*log2); const REAL hl= mLorentzianGamma0 +mLorentzianGamma1*dcenter +mLorentzianGamma2*dcenter*dcenter; const REAL hcom=pow(pow(hg,5)+2.69269*pow(hg,4)*hl+2.42843*pow(hg,3)*hl*hl +4.47163*hg*hg*pow(hl,3)+0.07842*hg*pow(hl,4)+pow(hl,5),0.2); const REAL sigcom2=hcom*hcom/(8.0*log2); const REAL eta=1.36603*hl/hcom-0.47719*pow(hl/hcom,2)+0.11116*pow(hl/hcom,3); const long nbPoints=x.numElements(); VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::GetProfile():alpha=" <10.0) expnu_erfcz=exp(nu-z*z)/(z*sqrt(M_PI)); else expnu_erfcz=exp(nu)*erfc(z); if(y>10.0) expu_erfcy=exp(u-y*y)/(y*sqrt(M_PI)); else expu_erfcy=exp(u)*erfc(y); #if 0 double tmp=(1-eta)*alpha*beta/(2*(alpha+beta))*(expu_erfcy+expnu_erfcz) -eta*alpha*beta/(M_PI*(alpha+beta))*(e1p.imag()+e1q.imag()); if(isnan(*pp))// Is this portable ? Test for numeric_limits::quiet_NaN() { cout<<"*pp==numeric_limits::quiet_NaN()"<::infinity()) { cout<<"*pp==numeric_limits::infinity()"<1e30) exit(0); #endif *pp++=(1-eta)*alpha*beta/(2*(alpha+beta))*(expu_erfcy+expnu_erfcz) -eta*alpha*beta/(M_PI*(alpha+beta))*(e1p.imag()+e1q.imag()); } VFN_DEBUG_EXIT("ReflectionProfileDoubleExponentialPseudoVoigt::GetProfile()",4) return prof; } void ReflectionProfileDoubleExponentialPseudoVoigt ::SetProfilePar(const REAL instrumentAlpha0, const REAL instrumentAlpha1, const REAL instrumentBeta0, const REAL instrumentBeta1, const REAL gaussianSigma0, const REAL gaussianSigma1, const REAL gaussianSigma2, const REAL lorentzianGamma0, const REAL lorentzianGamma1, const REAL lorentzianGamma2) { mInstrumentAlpha0=instrumentAlpha0; mInstrumentAlpha1=instrumentAlpha1; mInstrumentBeta0=instrumentBeta0; mInstrumentBeta1=instrumentBeta1; mGaussianSigma0=gaussianSigma0; mGaussianSigma1=gaussianSigma1; mGaussianSigma2=gaussianSigma2; mLorentzianGamma0=lorentzianGamma0; mLorentzianGamma1=lorentzianGamma1; mLorentzianGamma2=lorentzianGamma2; mClockMaster.Click(); } REAL ReflectionProfileDoubleExponentialPseudoVoigt ::GetFullProfileWidth(const REAL relativeIntensity, const REAL center, const REAL h, const REAL k, const REAL l) { VFN_DEBUG_ENTRY("ReflectionProfileDoubleExponentialPseudoVoigt::GetFullProfileWidth()",5) REAL dcenter=0; if(mpCell!=0) { REAL hh=h,kk=k,ll=l;// orthonormal coordinates in reciprocal space VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::GetFullProfileWidth(),"<GetName(),5) mpCell->MillerToOrthonormalCoords(hh,kk,ll); VFN_DEBUG_MESSAGE("ReflectionProfileDoubleExponentialPseudoVoigt::GetFullProfileWidth(),"<GetProfile(x,center,h,k,l); const REAL max=prof.max(); const REAL test=max*relativeIntensity; int n1=0,n2=0; if((prof(0)test){ p++; n2++;} VFN_DEBUG_EXIT("ReflectionProfilePseudoVoigt::GetFullProfileWidth():"<(x,prof),5) n*=2.0; //if(n>200) exit(0); } // unreachable code. // VFN_DEBUG_EXIT("ReflectionProfileDoubleExponentialPseudoVoigt::GetFullProfileWidth()",5) } bool ReflectionProfileDoubleExponentialPseudoVoigt ::IsAnisotropic()const{return false;} void ReflectionProfileDoubleExponentialPseudoVoigt ::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("ReflectionProfileDoubleExponentialPseudoVoigt::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mInstrumentAlpha0).XMLOutput(os,"Alpha0",indent); os <GetPar(&mInstrumentAlpha1).XMLOutput(os,"Alpha1",indent); os <GetPar(&mInstrumentBeta0).XMLOutput(os,"Beta0",indent); os <GetPar(&mInstrumentBeta1).XMLOutput(os,"Beta1",indent); os <GetPar(&mGaussianSigma0).XMLOutput(os,"GaussianSigma0",indent); os <GetPar(&mGaussianSigma1).XMLOutput(os,"GaussianSigma1",indent); os <GetPar(&mGaussianSigma2).XMLOutput(os,"GaussianSigma2",indent); os <GetPar(&mLorentzianGamma0).XMLOutput(os,"LorentzianGamma0",indent); os <GetPar(&mLorentzianGamma1).XMLOutput(os,"LorentzianGamma1",indent); os <GetPar(&mLorentzianGamma2).XMLOutput(os,"LorentzianGamma2",indent); os <GetName(),5) } void ReflectionProfileDoubleExponentialPseudoVoigt ::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ReflectionProfileDoubleExponentialPseudoVoigt::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); } while(true) { XMLCrystTag tag(is); if(("ReflectionProfileDoubleExponentialPseudoVoigt"==tag.GetName())&&tag.IsEndTag()) { this->UpdateDisplay(); VFN_DEBUG_EXIT("ReflectionProfileDoubleExponentialPseudoVoigt::Exit():"<GetName(),5) return; } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(tag.GetAttributeValue(i)).XMLInput(is,tag); } } continue; } if("Option"==tag.GetName()) { for(unsigned int i=0;iAddPar(tmp); } { RefinablePar tmp("Alpha1",&mInstrumentAlpha1,0,1e6,gpRefParTypeScattDataProfile, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("Beta0",&mInstrumentBeta0,0,1e6,gpRefParTypeScattDataProfile, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("Beta1",&mInstrumentBeta1,0,1e6,gpRefParTypeScattDataProfile, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-6); this->AddPar(tmp); } { RefinablePar tmp("GaussianSigma0",&mGaussianSigma0,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("GaussianSigma1",&mGaussianSigma1,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("GaussianSigma2",&mGaussianSigma2,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("LorentzianGamma0",&mLorentzianGamma0,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("LorentzianGamma1",&mLorentzianGamma1,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } { RefinablePar tmp("LorentzianGamma2",&mLorentzianGamma2,0,1e6,gpRefParTypeScattDataProfileWidth, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false); tmp.AssignClock(mClockMaster); tmp.SetDerivStep(1e-4); this->AddPar(tmp); } } #ifdef __WX__CRYST__ WXCrystObjBasic* ReflectionProfileDoubleExponentialPseudoVoigt::WXCreate(wxWindow* parent) { if(mpWXCrystObj==0) mpWXCrystObj=new WXProfileDoubleExponentialPseudoVoigt(parent,this); return mpWXCrystObj; } #endif //###################################################################### // Basic PROFILE FUNCTIONS //###################################################################### CrystVector_REAL PowderProfileGauss (const CrystVector_REAL ttheta,const REAL fw, const REAL center, const REAL asym) { TAU_PROFILE("PowderProfileGauss()","Vector (Vector,REAL)",TAU_DEFAULT); REAL fwhm=fw; if(fwhm<=0) fwhm=1e-6; const long nbPoints=ttheta.numElements(); CrystVector_REAL result(nbPoints); result=ttheta; result+= -center; result *= result; REAL *p; if(false)// fabs(asym-1.) < 1e-5) { //reference: IUCr Monographs on Crystallo 5 - The Rietveld Method (ed RA Young) result *= -4.*log(2.)/fwhm/fwhm; } else { // Adapted from Toraya J. Appl. Cryst 23(1990),485-491 const REAL c1= -(1.+asym)/asym*(1.+asym)/asym*log(2.)/fwhm/fwhm; const REAL c2= -(1.+asym) *(1.+asym) *log(2.)/fwhm/fwhm; long i; p=result.data(); const REAL *pt=ttheta.data(); for(i=0;icenter) break;} i++; for( ;i3;i-=4) { #ifdef HAVE_SSE_MATHFUN v4sf x=_mm_loadu_ps(p); _mm_storeu_ps(p,exp_ps(x)); p+=4; #else for(unsigned int j=0;j<4;++j) {// Fixed-length loop enables vectorization *p = exp(*p) ; p++ ; } #endif } for(;i>0;i--) { *p = exp(*p) ; p++ ;} #endif #if 0 #if 1 //def _MSC_VER // Bug from Hell (in MSVC++) ! // The *last* point ends up sometimes with an arbitrary large value... long i=0; for(;icenter) break;} i++; for( ;iz(1.0,0.0); complexce1=ExponentialIntegral1(z); cout<<"CE1("<z(0.0,1.0); complexce1=ExponentialIntegral1(z); cout<<"CE1("<z(1.0,1.0); complexce1=ExponentialIntegral1(z); cout<<"CE1("<z(100.0,1.0); complexce1=ExponentialIntegral1(z); cout<<"CE1("<z(10.0,20.0); complexce1=ExponentialIntegral1(z); cout<<"CE1("<std::complexExponentialIntegral1(const complex z) { return exp(-z)*ExponentialIntegral1_ExpZ(z); } template std::complexExponentialIntegral1_ExpZ(const complex z) { const T zr=z.real(); const T zn=abs(z); complex ce1; if(zn==0.0) return 1e100;// Should return an error ? std::numeric_limits::quiet_NaN() ? if((zn<10.0)||((zr<0.0)&&(zn<20.0)))// Abramowitz & Stegun 5.1.11 { ce1=complex(1,0); complex y(1,0); for(unsigned int i=1;i<=150;i++) { y=-y*(T)i*z / (T)((i+1)*(i+1)); ce1+=y; if(abs(y)<=abs(ce1)*1e-15) break; } static const T EulerMascheroni=0.5772156649015328606065120900; return exp(z)*(z*ce1-EulerMascheroni-log(z));// Euler-Mascheroni constant } else// Abramowitz & Stegun 5.1.51 { if(zn>500) return 1.0/z; complex y(0.0,0.0); for(unsigned int i=120;i>=1;i--) y=(T)i/((T)1+(T)i/(z+y)); ce1/=(z+y); if((zr<0)&&(z.imag()==0)) ce1 -= complex(0.0,M_PI)*exp(z); return ce1; } } } libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ReflectionProfile.h000066400000000000000000000342231417150057700246340ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2005 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _OBJCRYST_REFLECTIONPROFILE_H_ #define _OBJCRYST_REFLECTIONPROFILE_H_ #include #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/ObjCryst/UnitCell.h" #include "ObjCryst/RefinableObj/RefinableObj.h" namespace ObjCryst { //###################################################################### // basic functions used for profiles //###################################################################### ///Gaussian, normalized (ie integral is equal to 1), as a function of theta /// and of the FWHM. The input is an array of the theta values. The maximum of the ///function is in theta=center. If asymmetry is used, negative tth values must be first. CrystVector_REAL PowderProfileGauss (const CrystVector_REAL theta, const REAL fwhm, const REAL center, const REAL asym=1.0); ///Lorentzian, normalized (ie integral is equal to 1), as a function of theta /// and of the FWHM. The input is an array of the theta values. The maximum of the ///function is in theta=center. If asymmetry is used, negative tth values must be first. CrystVector_REAL PowderProfileLorentz(const CrystVector_REAL theta, const REAL fwhm, const REAL center, const REAL asym=1.0); /// Asymmetry function [Ref J. Appl. Cryst 26 (1993), 128-129 CrystVector_REAL AsymmetryBerarBaldinozzi(const CrystVector_REAL theta, const REAL fwhm, const REAL center, const REAL A0, const REAL A1, const REAL B0, const REAL B1); /** Complex exponential integral E1(z) (Abramowitz & Stegun, chap. 5) * * Using A&S 5.1.11 (series) and 5.1.51 (asymptotic) expansions */ template std::complexExponentialIntegral1(const complex z); /** E1(z)*exp(z) * * This can be computed for large z values to avoid floating-point exceptions. */ template std::complexExponentialIntegral1_ExpZ(const complex z); /** Abstract base class for reflection profiles. * */ class ReflectionProfile:public RefinableObj { public: ReflectionProfile(); ReflectionProfile(const ReflectionProfile &old); virtual ~ReflectionProfile(); virtual ReflectionProfile* CreateCopy()const=0; /** Get the reflection profile * *\param x: the vector of x coordinates (i.e. either 2theta or time-of-flight) *\param xcenter: coordinate (2theta, tof) of the center of the peak *\param h,k,l: reflection Miller indices *\note: derived classes who need either d_hkl or the orthonormal coordinates * of the scattering vector should be passed a ObjCryst::UnitCell object in * the constructor so that they can use ObjCryst::UnitCell::MillerToOrthonormalCoords() */ virtual CrystVector_REAL GetProfile(const CrystVector_REAL &x, const REAL xcenter, const REAL h, const REAL k, const REAL l)const=0; /// Get the (approximate) full profile width at a given percentage /// of the profile maximum (e.g. FWHM=GetFullProfileWidth(0.5)). virtual REAL GetFullProfileWidth(const REAL relativeIntensity, const REAL xcenter, const REAL h, const REAL k, const REAL l)=0; /// Is the profile anisotropic ? virtual bool IsAnisotropic()const; virtual void XMLOutput(ostream &os,int indent=0)const=0; virtual void XMLInput(istream &is,const XMLCrystTag &tag)=0; private: #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent)=0; #endif }; /** Pseudo-Voigt reflection profile. * */ class ReflectionProfilePseudoVoigt:public ReflectionProfile { public: ReflectionProfilePseudoVoigt(); ReflectionProfilePseudoVoigt(const ReflectionProfilePseudoVoigt &old); virtual ~ReflectionProfilePseudoVoigt(); virtual ReflectionProfilePseudoVoigt* CreateCopy()const; virtual const string& GetClassName()const; CrystVector_REAL GetProfile(const CrystVector_REAL &x, const REAL xcenter, const REAL h, const REAL k, const REAL l)const; /** Set reflection profile parameters * * \param fwhmCagliotiW,fwhmCagliotiU,fwhmCagliotiV : these are the U,V and W * parameters in the Caglioti's law : * \f$ fwhm^2= U \tan^2(\theta) + V \tan(\theta) +W \f$ * if only W is given, the width is constant * \param eta0,eta1: these are the mixing parameters. */ void SetProfilePar(const REAL fwhmCagliotiW, const REAL fwhmCagliotiU=0, const REAL fwhmCagliotiV=0, const REAL eta0=0.5, const REAL eta1=0.); virtual REAL GetFullProfileWidth(const REAL relativeIntensity, const REAL xcenter, const REAL h, const REAL k, const REAL l); bool IsAnisotropic()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); private: /// Initialize parameters void InitParameters(); ///FWHM parameters, following Caglioti's law REAL mCagliotiU,mCagliotiV,mCagliotiW; ///Pseudo-Voigt mixing parameter : eta=eta0 +2*theta*eta1 /// eta=1 -> pure Lorentzian ; eta=0 -> pure Gaussian REAL mPseudoVoigtEta0,mPseudoVoigtEta1; /** Asymmetry parameters, following the Bérar \& Baldinozzi approach * ( Bérar \& baldinozzi, J. Appl. Cryst 26 (1993), 128-129) * * \note: these are not used right now. */ REAL mAsymBerarBaldinozziA0,mAsymBerarBaldinozziA1, mAsymBerarBaldinozziB0,mAsymBerarBaldinozziB1; /** Asymmetry parameters, following the analytical function for asymmetric pseudo-voigt * given by Toraya in J. Appl. Cryst 23(1990),485-491 * * Asymmetric coefficient: * \f[ A=A_0+A_1/\sin(2\vartheta)+A_2/\sin^2(2\vartheta) \f] * * Asymmetric profile: * \f[ Prof(\vartheta-\vartheta_{max}<=0)=Prof_0(\frac{1+A}{A})(\vartheta-\vartheta_{max})) \f] * \f[ Prof(\vartheta-\vartheta_{max}>=0)=Prof_0((1+A) (\vartheta-\vartheta_{max})) \f] */ REAL mAsym0,mAsym1,mAsym2; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent); #endif }; /** Pseudo-Voigt reflection profile, with 6-parameters anisotropic Lorentzian broadening and Toraya asymmetric modelling. * */ class ReflectionProfilePseudoVoigtAnisotropic:public ReflectionProfile { public: ReflectionProfilePseudoVoigtAnisotropic(); ReflectionProfilePseudoVoigtAnisotropic(const ReflectionProfilePseudoVoigtAnisotropic &old); virtual ~ReflectionProfilePseudoVoigtAnisotropic(); virtual ReflectionProfilePseudoVoigtAnisotropic* CreateCopy()const; virtual const string& GetClassName()const; CrystVector_REAL GetProfile(const CrystVector_REAL &x, const REAL xcenter, const REAL h, const REAL k, const REAL l)const; /** Set reflection profile parameters * * if only W is given, the width is constant * * See documentation for mCagliotiU,mCagliotiV,mCagliotiW,mScherrerP,mLorentzX,mLorentzY, * mLorentzGammaHH,mLorentzGammaKK,mLorentzGammaLL,mLorentzGammaHK,mLorentzGammaHL,mLorentzGammaKL * mAsym0,mAsym1,mAsym2. */ void SetProfilePar(const REAL fwhmCagliotiW, const REAL fwhmCagliotiU=0, const REAL fwhmCagliotiV=0, const REAL fwhmGaussP=0, const REAL fwhmLorentzX=0, const REAL fwhmLorentzY=0, const REAL fwhmLorentzGammaHH=0, const REAL fwhmLorentzGammaKK=0, const REAL fwhmLorentzGammaLL=0, const REAL fwhmLorentzGammaHK=0, const REAL fwhmLorentzGammaHL=0, const REAL fwhmLorentzGammaKL=0, const REAL pseudoVoigtEta0=0, const REAL pseudoVoigtEta1=0, const REAL asymA0=0, const REAL asymA1=0, const REAL asymA2=0 ); virtual REAL GetFullProfileWidth(const REAL relativeIntensity, const REAL xcenter, const REAL h, const REAL k, const REAL l); bool IsAnisotropic()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); private: /// Initialize parameters void InitParameters(); /** FWHM parameters: * * Profile:\f$ Prof(\vartheta) = \eta Lorentz(\vartheta) + (1-\eta) Gauss(\vartheta) \f$ * * This pseudo-Voigt profile is the linear combination of a Gaussian and a Lorentzian: * \f[ Profile(\vartheta)= Lorentz(\vartheta) + Gauss(\vartheta)\f] * * Gaussian FWHM parameters, following Caglioti's law and Scherrer broadening coefficient: * \f[ fwhm_g^2= U \tan^2(\theta) + V \tan(\theta) +W +\frac{P}{\cos^2\vartheta} \f] * See Cagliotti, Pauletti & Ricci, Nucl. Instrum. 3 (1958), 223. * * Lorentzian FWHM parameters * * \f[ fwhm_l= \frac{X}{\cos\vartheta} +(Y + \frac{\gamma_L}{\sin^2\vartheta})\tan\vartheta \f] * with anisotropic broadening factor: * \f[ \gamma_L = \gamma_{HH}h^2 + \gamma_{KK}k^2 + \gamma_{LL}l^2 + 2\gamma_{HK}hk + 2\gamma_{hl} + 2\gamma_{kl}kl\f] * * \note: in the above formula we use \f$ \frac{\gamma_L}{\sin^2\vartheta} \f$ rather than the more usual\f$ \gamma_L d^2 \f$ * for computing purposes (the model being purely phenomenological). */ REAL mCagliotiU,mCagliotiV,mCagliotiW,mScherrerP,mLorentzX,mLorentzY, mLorentzGammaHH,mLorentzGammaKK,mLorentzGammaLL,mLorentzGammaHK,mLorentzGammaHL,mLorentzGammaKL; ///Pseudo-Voigt mixing parameter : \f$ \eta=\eta_0 +2*\vartheta*\eta_1\f$ /// eta=1 -> pure Lorentzian ; eta=0 -> pure Gaussian REAL mPseudoVoigtEta0,mPseudoVoigtEta1; /** Asymmetry parameters, following the analytical function for asymmetric pseudo-voigt * given by Toraya in J. Appl. Cryst 23(1990),485-491 * * Asymmetric coefficient: * \f[ A=A_0+A_1/\sin(2\vartheta)+A_2/\sin^2(2\vartheta) \f] * * Asymmetric profile: * \f[ Prof(\vartheta-\vartheta_{max}<=0)=Prof_0(\frac{1+A}{A})(\vartheta-\vartheta_{max})) \f] * \f[ Prof(\vartheta-\vartheta_{max}>=0)=Prof_0((1+A) (\vartheta-\vartheta_{max})) \f] */ REAL mAsym0,mAsym1,mAsym2; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent); #endif }; /** Double-Exponential Pseudo-Voigt profile for TOF. * * Ref Mark Pitt */ class ReflectionProfileDoubleExponentialPseudoVoigt:public ReflectionProfile { public: /** Constructor, without unit cell */ ReflectionProfileDoubleExponentialPseudoVoigt(); /** Constructor, with unit cell */ ReflectionProfileDoubleExponentialPseudoVoigt(const UnitCell &cell); ReflectionProfileDoubleExponentialPseudoVoigt (const ReflectionProfileDoubleExponentialPseudoVoigt &old); virtual ~ReflectionProfileDoubleExponentialPseudoVoigt(); virtual ReflectionProfileDoubleExponentialPseudoVoigt* CreateCopy()const; virtual const string& GetClassName()const; CrystVector_REAL GetProfile(const CrystVector_REAL &x, const REAL xcenter, const REAL h, const REAL k, const REAL l)const; /** Set reflection profile parameters * */ void SetProfilePar(const REAL instrumentAlpha0, const REAL instrumentAlpha1, const REAL instrumentBeta0, const REAL instrumentBeta1, const REAL gaussianSigma0, const REAL gaussianSigma1, const REAL gaussianSigma2, const REAL lorentzianGamma0, const REAL lorentzianGamma1, const REAL lorentzianGamma2); virtual REAL GetFullProfileWidth(const REAL relativeIntensity, const REAL xcenter, const REAL h, const REAL k, const REAL l); bool IsAnisotropic()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); /** Set unit cell. This is used to compute d_hkl for reflections. * */ void SetUnitCell(const UnitCell &cell); private: /// Initialize parameters void InitParameters(); REAL mInstrumentAlpha0; REAL mInstrumentAlpha1; REAL mInstrumentBeta0; REAL mInstrumentBeta1; REAL mGaussianSigma0; REAL mGaussianSigma1; REAL mGaussianSigma2; REAL mLorentzianGamma0; REAL mLorentzianGamma1; REAL mLorentzianGamma2; const UnitCell *mpCell; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent); #endif }; /// Global registry for all ReflectionProfile objects extern ObjRegistry gReflectionProfileRegistry; }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/Scatterer.cpp000066400000000000000000000127051417150057700235110ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // // source file for the base Scatterer classe #include #include #include #include //for sprintf() #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Scatterer.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs.. #include "ObjCryst/Quirks/VFNDebug.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxScatterer.h" #endif #include "ObjCryst/ObjCryst/Colours.h" #include #include namespace ObjCryst { const RefParType *gpRefParTypeScatt=0; const RefParType *gpRefParTypeScattTransl=0; const RefParType *gpRefParTypeScattTranslX=0; const RefParType *gpRefParTypeScattTranslY=0; const RefParType *gpRefParTypeScattTranslZ=0; const RefParType *gpRefParTypeScattOrient=0; const RefParType *gpRefParTypeScattConform=0; const RefParType *gpRefParTypeScattConformBondLength=0; const RefParType *gpRefParTypeScattConformBondAngle=0; const RefParType *gpRefParTypeScattConformDihedAngle=0; const RefParType *gpRefParTypeScattConformX=0; const RefParType *gpRefParTypeScattConformY=0; const RefParType *gpRefParTypeScattConformZ=0; const RefParType *gpRefParTypeScattOccup=0; long NiftyStaticGlobalObjectsInitializer_Scatterer::mCount=0; //////////////////////////////////////////////////////////////////////// // // SCATTERER : generic type of scatterer // // //////////////////////////////////////////////////////////////////////// ObjRegistry gScattererRegistry("Global Scatterer Registry"); Scatterer::Scatterer():mXYZ(3),mOccupancy(1.0),mColourName("White"),mpCryst(0) { VFN_DEBUG_MESSAGE("Scatterer::Scatterer()",5) mXYZ=0; this->InitRGBColour(); gScattererRegistry.Register(*this); mClockMaster.AddChild(mClockScatterer); } Scatterer::Scatterer(const Scatterer &old): //RefinableObj(), mXYZ(old.mXYZ), mOccupancy(old.mOccupancy), mColourName(old.mColourName),mpCryst(old.mpCryst) { VFN_DEBUG_MESSAGE("Scatterer::Scatterer(&old)",5) mName=old.GetName(); this->InitRGBColour(); gScattererRegistry.Register(*this); mClockMaster.AddChild(mClockScatterer); } Scatterer::~Scatterer() { VFN_DEBUG_MESSAGE("Scatterer::~Scatterer():("<GetPar(mXYZ.data()).MutateTo(x);} void Scatterer::SetY(const REAL y) { this->GetPar(mXYZ.data()+1).MutateTo(y);} void Scatterer::SetZ(const REAL z) { this->GetPar(mXYZ.data()+2).MutateTo(z);} void Scatterer::SetOccupancy(const REAL occupancy) { mClockScatterer.Click(); mOccupancy=occupancy; } Scatterer::operator string() const {return this->GetName();} /* void Scatterer::Print() const { cout << "Scatterer : " << FormatString(this->GetName()) << " at :" ; cout << FormatFloat(this->X()); cout << FormatFloat(this->Y()); cout << FormatFloat(this->Z()); cout << endl; } */ const string& Scatterer::GetColour()const{ return mColourName;} const float* Scatterer::GetColourRGB()const{ return mColourRGB;} const RefinableObjClock& Scatterer::GetClockScatterer()const {return mClockScatterer;} RefinableObjClock& Scatterer::GetClockScatterer() {return mClockScatterer;} void Scatterer::SetCrystal(Crystal &cryst){mpCryst=&cryst;} const Crystal& Scatterer::GetCrystal()const{return *mpCryst;} Crystal& Scatterer::GetCrystal(){return *mpCryst;} void Scatterer::InitRGBColour() { //mClockScatterer.Click(); VFN_DEBUG_MESSAGE("Scatterer::InitRGBColour()",2) for(long i=0;;) { if(gPOVRayColours[i].mName==mColourName) { mColourRGB[0]=gPOVRayColours[i].mRGB[0]; mColourRGB[1]=gPOVRayColours[i].mRGB[1]; mColourRGB[2]=gPOVRayColours[i].mRGB[2]; break; } i++; if(strncmp(gPOVRayColours[i].mName,"",3 )==0) {//could not find colour ! cout << "Could not find colour:"<RGBColour:"< namespace ObjCryst { class Crystal ; //forward declaration.:KLUDGE: ? extern const RefParType *gpRefParTypeScatt; extern const RefParType *gpRefParTypeScattTransl; extern const RefParType *gpRefParTypeScattTranslX; extern const RefParType *gpRefParTypeScattTranslY; extern const RefParType *gpRefParTypeScattTranslZ; extern const RefParType *gpRefParTypeScattOrient; extern const RefParType *gpRefParTypeScattConform; extern const RefParType *gpRefParTypeScattConformBondLength; extern const RefParType *gpRefParTypeScattConformBondAngle; extern const RefParType *gpRefParTypeScattConformDihedAngle; extern const RefParType *gpRefParTypeScattConformX; extern const RefParType *gpRefParTypeScattConformY; extern const RefParType *gpRefParTypeScattConformZ; extern const RefParType *gpRefParTypeScattOccup; class NiftyStaticGlobalObjectsInitializer_Scatterer { public: NiftyStaticGlobalObjectsInitializer_Scatterer() { if (mCount++ == 0) { gpRefParTypeScatt=new RefParType(gpRefParTypeObjCryst,"Scatterer"); gpRefParTypeScattTransl=new RefParType(gpRefParTypeScatt,"Translation"); gpRefParTypeScattTranslX=new RefParType(gpRefParTypeScattTransl,"Translation along X"); gpRefParTypeScattTranslY=new RefParType(gpRefParTypeScattTransl,"Translation along Y"); gpRefParTypeScattTranslZ=new RefParType(gpRefParTypeScattTransl,"Translation along Z"); gpRefParTypeScattOrient=new RefParType(gpRefParTypeScatt,"Orientation"); gpRefParTypeScattConform=new RefParType(gpRefParTypeScatt,"Conformation"); gpRefParTypeScattConformBondLength=new RefParType(gpRefParTypeScattConform,"BondLengths"); gpRefParTypeScattConformBondAngle=new RefParType(gpRefParTypeScattConform,"Bond Angles"); gpRefParTypeScattConformDihedAngle=new RefParType(gpRefParTypeScattConform,"Dihedral Angles "); gpRefParTypeScattConformX=new RefParType(gpRefParTypeScattConform,"Orth. X coordinates"); gpRefParTypeScattConformY=new RefParType(gpRefParTypeScattConform,"Orth. Y coordinates"); gpRefParTypeScattConformZ=new RefParType(gpRefParTypeScattConform,"Orth. Z coordinates"); gpRefParTypeScattOccup=new RefParType(gpRefParTypeScatt,"Occupancy"); } } ~NiftyStaticGlobalObjectsInitializer_Scatterer() { if (--mCount == 0) { delete gpRefParTypeScatt; delete gpRefParTypeScattTransl; delete gpRefParTypeScattTranslX; delete gpRefParTypeScattTranslY; delete gpRefParTypeScattTranslZ; delete gpRefParTypeScattOrient; delete gpRefParTypeScattConform; delete gpRefParTypeScattConformBondLength; delete gpRefParTypeScattConformBondAngle; delete gpRefParTypeScattConformDihedAngle; delete gpRefParTypeScattConformX; delete gpRefParTypeScattConformY; delete gpRefParTypeScattConformZ; delete gpRefParTypeScattOccup; gpRefParTypeScatt=0; gpRefParTypeScattTransl=0; gpRefParTypeScattTranslX=0; gpRefParTypeScattTranslY=0; gpRefParTypeScattTranslZ=0; gpRefParTypeScattOrient=0; gpRefParTypeScattConform=0; gpRefParTypeScattConformBondLength=0; gpRefParTypeScattConformBondAngle=0; gpRefParTypeScattConformDihedAngle=0; gpRefParTypeScattConformX=0; gpRefParTypeScattConformY=0; gpRefParTypeScattConformZ=0; gpRefParTypeScattOccup=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_Scatterer NiftyStaticGlobalObjectsInitializer_Scatterer_counter; //###################################################################### // // SCATTERER /** \brief Generic type of scatterer: can be an atom, or a more complex assembly of atoms. * * A Scatterer is able to give its position (in fractionnal coordinates) * in the unit cell, and more generally the position of all point * scattering centers (ScatteringComponent), along with the ScatteringPower * associated with each position. * * For simple atoms, there is only one scattering position with the associated * scattering power (scattering factor, anomalous, thermic). For complex * scatterers (molecules: ZScatterer) there are as many positions as atoms. * * A scatterer also has a few functions to display itself in 3D * * This is an abstract base class. */ //###################################################################### class Scatterer:virtual public RefinableObj { public: /// Constructor Scatterer(); /// Copy Constructor Scatterer(const Scatterer &old); /// Destructor virtual ~Scatterer(); /// \internal so-called Virtual copy constructor, needed to make copies /// of arrays of Scatterers virtual Scatterer* CreateCopy() const=0; virtual const string& GetClassName() const; /// Number of components in the scatterer (eg number of point scatterers) virtual int GetNbComponent() const=0; /** \brief Get the list of all scattering components for this scatterer. * * This is the most important function of this class, giving the list of * scattering positions along with the associated ScatteringPower. * */ virtual const ScatteringComponentList& GetScatteringComponentList() const=0; /// Name for the i-th component of this scatterer. If the component is an Atom, /// Then the name is that of the atom. Else, it is the name of the scatterer /// plus the component number in the scatterer plus the name of the ScatteringPower. /// \note It would be better to return a reference, but we don't want to keep /// a name for all components... Weeelll, needs some more thinking... see what /// performance hit results (if any). /// /// \bug does not take into account dummy atoms !! virtual string GetComponentName(const int i) const=0; /// X coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. REAL GetX() const; /// Y coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. REAL GetY() const; /// Z coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. REAL GetZ() const; /** \brief Get the occupancy of the scatterer (0. -> 1.0) * * The occupancy is given in %, and must take into account the * 'special position' character of atoms (ie an atom on a 2fold axis * should have at most a .5 population, etc...). * For a multi-atom scatterer (polyhedra), this is the \b overall occupancy * of the scatterer, affecting all atoms. */ REAL GetOccupancy() const ; /// X coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. virtual void SetX(const REAL x); /// Y coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. virtual void SetY(const REAL y); /// Z coordinate (fractionnal) of the scatterer (for complex scatterers, /// this corresponds to the position of one atom of the Scatterer, ideally /// it should be near the center of the Scatterer. virtual void SetZ(const REAL z); /** \brief Change the occupancy of the scatterer (0. -> 1.0) * * The occupancy is given in %, and must take into account the * 'special position' character of atoms (ie an atom on a 2fold axis * should have at most a .5 population, etc...). * For a multi-atom scatterer (polyhedra), this is the \b overall occupancy * of the scatterer, affecting all atoms. */ virtual void SetOccupancy(const REAL occupancy) ; /// Conversion function.-> returns the scatt name /// /// \warning EXPERIMENTAL. DO NOT USE, as this may be removed. operator string()const; /// Print some info about the scatterer (ideally this should be one line...). virtual void Print() const=0; /** \brief Colour associated to this scatterer (using POVRay names) * */ virtual const string& GetColour()const; /** \brief Colour associated to this scatterer, 3 RGB Coordinates. * */ virtual const float* GetColourRGB()const; /** \brief \internal Output a description of the scatterer for POVRay. * This should only be called by the Crystal Object to which belongs this * scatterer. * */ virtual ostream& POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const=0; #ifdef OBJCRYST_GL /** \internal Create an OpenGL Display List of the scatterer. This should only * be called by a Crystal object. * * \param noSymmetrics: if false (the default), then all symmetrics are shown in the * 3D display, within the limits defined by the min/max parameters * \ param xMin,xMax,yMin,yMax,zMin,zMax: in fractionnal coordinates, the region * in which we want scaterrer to be displayed. The test is made on the center * of the scatterer (eg a ZScatterer (molecule) will not be 'cut' on the border). * \param displayNames: if true, only the names of the scatterers will be displayed, * at the position of the scatterers (to actually see them, they will have to * be translated with respect to the drawing of the scatterers). * \param hideHydrogens: if true, do not display hydrogens/deuterium and their bonds * \param fadeDistance: atoms which are beyond the display limits are still showm, but * with transparency which is progressively fading up to a certain distance. * \param fullMoleculeInLimits: if true, molecules which are centered inside the * display limits will be shown completely without fading. (default=false) */ virtual void GLInitDisplayList(const bool noSymmetrics=false, const REAL xMin=-.1,const REAL xMax=1.1, const REAL yMin=-.1,const REAL yMax=1.1, const REAL zMin=-.1,const REAL zMax=1.1, const bool displayEnantiomer=false, const bool displayNames=false, const bool hideHydrogens=false, const REAL fadeDistance=0, const bool fullMoleculeInLimits=false)const=0; #endif // OBJCRYST_GL /// Last time anything in the scatterer was changed (atoms, positions, scattering power) const RefinableObjClock& GetClockScatterer()const; /// Last time anything in the scatterer was changed (atoms, positions, scattering power) RefinableObjClock& GetClockScatterer(); /// Set the crystal in which is included this Scatterer void SetCrystal(Crystal&); /// In which crystal is this Scatterer included ? const Crystal& GetCrystal()const; /// In which crystal is this Scatterer included ? Crystal& GetCrystal(); protected: /// \internal Prepare refinable parameters for the scatterer object virtual void InitRefParList()=0; /** Get RGB Colour coordinates from Colour Name. Note that the colour * used for display is usually that of the ScatteringPower, not that of the Scatterer * */ virtual void InitRGBColour(); /// Last time the ScatteringComponentList was generated const RefinableObjClock& GetClockScattCompList()const; ///coordinates of the scatterer (or of its center..) CrystVector_REAL mXYZ; /** \brief Occupancy : 0 <= occ <= 1 * For a multi-atom scatterer (polyhedron,..), this is the \b overall occupancy * of the scatterer (affects all components of the scatterer). */ REAL mOccupancy; /// Colour for this scatterer (from POVRay) string mColourName; /// Colour for this scatterer using RGB float mColourRGB[3]; /// Last time anything (number of atoms, positions, scattering power) was changed RefinableObjClock mClockScatterer; /// \internal Last time the ScatteringComponentList was generated mutable RefinableObjClock mClockScattCompList; /// The crystal in which the Scatterer is /// This is needed so that we can know which scattering powers are available /// in the crystal, and also to convert fractionnal to orthonormal /// coordinates (for some scatterers only). /// It cannot be const since some scatterers may want to modify /// the list of scattering powers of the crystal... Crystal *mpCryst; private: #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXScatterer; #endif }; /// Global registry for all Scatterer objects extern ObjRegistry gScattererRegistry; }//namespace #include "ObjCryst/ObjCryst/Crystal.h" #endif //_OBJCRYST_SCATTERER_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringCorr.cpp000066400000000000000000001063221417150057700245050ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ObjCryst/ObjCryst/ScatteringCorr.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include //for sprintf() #include #ifdef __WX__CRYST__ namespace ObjCryst { class TexturePhaseMarchDollase; } #include "ObjCryst/wxCryst/wxPowderPattern.h" #endif namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // ScatteringCorr // //////////////////////////////////////////////////////////////////////// ScatteringCorr::ScatteringCorr(const ScatteringData & data): mpData(&data) { VFN_DEBUG_MESSAGE("ScatteringCorr::ScatteringCorr(&scattData)",5) } ScatteringCorr::~ScatteringCorr() { VFN_DEBUG_MESSAGE("ScatteringCorr::~ScatteringCorr()",5) } const CrystVector_REAL& ScatteringCorr::GetCorr() const { this->CalcCorr(); return mCorr; } const RefinableObjClock& ScatteringCorr::GetClockCorr()const {return mClockCorrCalc;} //////////////////////////////////////////////////////////////////////// // // LorentzCorr // //////////////////////////////////////////////////////////////////////// LorentzCorr::LorentzCorr(const ScatteringData & data): ScatteringCorr(data) {} LorentzCorr::~LorentzCorr() {} const string & LorentzCorr::GetName() const { //So far, we do not need a personalized name... const static string mName="LorentzCorr"; return mName; } const string & LorentzCorr::GetClassName() const { const static string className="LorentzCorr"; return className; } void LorentzCorr::CalcCorr() const { const CrystVector_REAL *theta=&(mpData->GetTheta()); if(mpData->GetClockTheta()GetNbRefl()); for(long i=0;iGetNbRefl();i++)mCorr(i) =1/sin(2*(*theta)(i)); mClockCorrCalc.Click(); } //////////////////////////////////////////////////////////////////////// // // PolarizationCorr // //////////////////////////////////////////////////////////////////////// PolarizationCorr::PolarizationCorr(const ScatteringData & data): ScatteringCorr(data),mPolarAfactor(1) {} PolarizationCorr::~PolarizationCorr() {} const string & PolarizationCorr::GetName() const { //So far, we do not need a personalized name... const static string mName="PolarizationCorr"; return mName; } const string & PolarizationCorr::GetClassName() const { const static string className="PolarizationCorr"; return className; } void PolarizationCorr::CalcCorr() const { const CrystVector_REAL *theta=&(mpData->GetTheta()); const REAL f=mpData->GetRadiation().GetLinearPolarRate(); if( (mpData->GetClockTheta()GetNbRefl()); // cos^2(2*theta)=0.5+0.5*cos(4*theta) for(long i=0;iGetNbRefl();i++) mCorr(i) =(1.+mPolarAfactor*(0.5+0.5*cos(4*(*theta)(i))))/(1.+mPolarAfactor); mClockCorrCalc.Click(); } //////////////////////////////////////////////////////////////////////// // // PowderSlitApertureCorr // //////////////////////////////////////////////////////////////////////// PowderSlitApertureCorr::PowderSlitApertureCorr(const ScatteringData & data): ScatteringCorr(data) {} PowderSlitApertureCorr::~PowderSlitApertureCorr() {} const string & PowderSlitApertureCorr::GetName() const { //So far, we do not need a personalized name... const static string mName="PowderSlitApertureCorr"; return mName; } const string & PowderSlitApertureCorr::GetClassName() const { const static string className="PowderSlitApertureCorr"; return className; } void PowderSlitApertureCorr::CalcCorr() const { const CrystVector_REAL *theta=&(mpData->GetTheta()); if(mpData->GetClockTheta()GetNbRefl()); for(long i=0;iGetNbRefl();i++)mCorr(i) =1/sin((*theta)(i)); mClockCorrCalc.Click(); } //////////////////////////////////////////////////////////////////////// // // TexturePhaseMarchDollase // //////////////////////////////////////////////////////////////////////// TexturePhaseMarchDollase::TexturePhaseMarchDollase(const REAL f, const REAL c, const REAL h, const REAL k, const REAL l, TextureMarchDollase &tex): mFraction(f),mMarchCoeff(c),mH(h),mK(k),mL(l),mpTextureMarchDollase(&tex) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif {} TexturePhaseMarchDollase::~TexturePhaseMarchDollase() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } const string& TexturePhaseMarchDollase::GetClassName()const { const static string className="March-Dollase Texture Phase"; return className; } const string& TexturePhaseMarchDollase::GetName()const { const static string name="March-Dollase Texture Phase"; return name; } void TexturePhaseMarchDollase::SetPar(const REAL f, const REAL c,const REAL h,const REAL k, const REAL l) {mFraction=f;mMarchCoeff=c;mH=h;mK=k;mL=l;} void TexturePhaseMarchDollase::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("TexturePhaseMarchDollase::XMLOutput():"<GetName(),5) for(int i=0;iGetPar(&mFraction).XMLOutput(os,"Fraction",indent); os <GetPar(&mMarchCoeff).XMLOutput(os,"MarchCoeff",indent); os <GetPar(&mH).XMLOutput(os,"H",indent); os <GetPar(&mK).XMLOutput(os,"K",indent); os <GetPar(&mL).XMLOutput(os,"L",indent); os <GetName(),5) } void TexturePhaseMarchDollase::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("TexturePhaseMarchDollase::XMLInput():",5) for(unsigned int i=0;iGetPar(&mFraction).XMLInput(is,tag); break; } if("MarchCoeff"==tag.GetAttributeValue(i)) { mpTextureMarchDollase->GetPar(&mMarchCoeff).XMLInput(is,tag); break; } if("H"==tag.GetAttributeValue(i)) { mpTextureMarchDollase->GetPar(&mH).XMLInput(is,tag); break; } if("K"==tag.GetAttributeValue(i)) { mpTextureMarchDollase->GetPar(&mK).XMLInput(is,tag); break; } if("L"==tag.GetAttributeValue(i)) { mpTextureMarchDollase->GetPar(&mL).XMLInput(is,tag); break; } } } continue; } } } #ifdef __WX__CRYST__ WXCrystObjBasic* TexturePhaseMarchDollase::WXCreate(wxWindow* parent) { mpWXCrystObj=new WXTexturePhaseMarchDollase(parent,this,mpTextureMarchDollase); return mpWXCrystObj; } WXCrystObjBasic* TexturePhaseMarchDollase::WXGet() { return mpWXCrystObj; } void TexturePhaseMarchDollase::WXDelete() { if(0!=mpWXCrystObj) { VFN_DEBUG_MESSAGE("TexturePhaseMarchDollase::WXDelete()",5) delete mpWXCrystObj; } } void TexturePhaseMarchDollase::WXNotifyDelete(){mpWXCrystObj=0;} #endif //////////////////////////////////////////////////////////////////////// // // TextureMarchDollase // //////////////////////////////////////////////////////////////////////// TextureMarchDollase::TextureMarchDollase(const ScatteringData & data): ScatteringCorr(data),mNbReflUsed(0) { mClockMaster.AddChild(mClockTexturePar); } TextureMarchDollase::~TextureMarchDollase() { } const string & TextureMarchDollase::GetName() const { //So far, we do not need a personalized name... const static string name="TextureMarchDollase"; return name; } const string & TextureMarchDollase::GetClassName() const { //So far, we do not need a personalized name... const static string name="TextureMarchDollase"; return name; } void TextureMarchDollase::AddPhase(const REAL f, const REAL c, const REAL h,const REAL k, const REAL l) { VFN_DEBUG_ENTRY("TextureMarchDollase::AddPhase()",5) TexturePhaseMarchDollase* phase=new TexturePhaseMarchDollase(f,c,h,k,l,*this); this->Print(); //Add parameters const unsigned int nbPhase=this->GetNbPhase(); char buf [5]; sprintf(buf,"%d",nbPhase); { RefinablePar tmp("Fraction_"+(string)buf,&(phase->mFraction),0.,1., gpRefParTypeScattDataCorrIntPO_Fraction, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.); tmp.AssignClock(mClockTexturePar); tmp.SetDerivStep(1e-7); tmp.SetGlobalOptimStep(.05); this->AddPar(tmp); } { RefinablePar tmp("MarchCoeff_"+(string)buf,&(phase->mMarchCoeff),.1,10., gpRefParTypeScattDataCorrIntPO_Amplitude, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.); tmp.AssignClock(mClockTexturePar); tmp.SetDerivStep(1e-7); tmp.SetGlobalOptimStep(.1); this->AddPar(tmp); } { RefinablePar tmp("H_"+(string)buf,&(phase->mH),-10.,10., gpRefParTypeScattDataCorrIntPO_Direction, REFPAR_DERIV_STEP_ABSOLUTE,false,true,true,false,1.); tmp.AssignClock(mClockTexturePar); tmp.SetDerivStep(1e-7); tmp.SetGlobalOptimStep(.01); this->AddPar(tmp); } { RefinablePar tmp("K_"+(string)buf,&(phase->mK),-10.,10., gpRefParTypeScattDataCorrIntPO_Direction, REFPAR_DERIV_STEP_ABSOLUTE,false,true,true,false,1.); tmp.AssignClock(mClockTexturePar); tmp.SetDerivStep(1e-7); tmp.SetGlobalOptimStep(.01); this->AddPar(tmp); } { RefinablePar tmp("L_"+(string)buf,&(phase->mL),-10.,10., gpRefParTypeScattDataCorrIntPO_Direction, REFPAR_DERIV_STEP_ABSOLUTE,false,true,true,false,1.); tmp.AssignClock(mClockTexturePar); tmp.SetDerivStep(1e-7); tmp.SetGlobalOptimStep(.01); this->AddPar(tmp); } this->Print(); mPhaseRegistry.Register(*phase); VFN_DEBUG_EXIT("TextureMarchDollase::AddPhase()=",5) } void TextureMarchDollase::SetPhasePar(const unsigned int i, const REAL f, const REAL c, const REAL h,const REAL k, const REAL l) { mPhaseRegistry.GetObj(i).SetPar(f,c,h,k,l); } //void DeletePhase(const unsigned int i); unsigned int TextureMarchDollase::GetNbPhase() const {return mPhaseRegistry.GetNb();} REAL TextureMarchDollase::GetFraction(const unsigned int i)const {return mPhaseRegistry.GetObj(i).mFraction;} REAL TextureMarchDollase::GetMarchCoeff(const unsigned int i)const {return mPhaseRegistry.GetObj(i).mMarchCoeff;} REAL TextureMarchDollase::GetPhaseH(const unsigned int i)const {return mPhaseRegistry.GetObj(i).mH;} REAL TextureMarchDollase::GetPhaseK(const unsigned int i)const {return mPhaseRegistry.GetObj(i).mK;} REAL TextureMarchDollase::GetPhaseL(const unsigned int i)const {return mPhaseRegistry.GetObj(i).mL;} void TextureMarchDollase::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; if(!(gpRefParTypeScattDataCorrInt->IsDescendantFromOrSameAs(type))) { mRandomMoveIsDone=true; return; } //if((rand()/(REAL)RAND_MAX)<.3)//only 30% proba to make a random move { VFN_DEBUG_MESSAGE("TextureMarchDollase::GlobalOptRandomMove()",1) for(unsigned int i=0;iGetNbPhase();i++) { // :TODO: Give some probability (1% ?) to invert the March coefficient // with a direction perpendicular to the current one ? RefinablePar *pF=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mFraction))); RefinablePar *pM=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mMarchCoeff))); RefinablePar *pH=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mH))); RefinablePar *pK=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mK))); RefinablePar *pL=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mL))); if(pF->IsFixed()==false) { const REAL delta=pF->GetGlobalOptimStep()*mutationAmplitude; const REAL sig=4*delta; const REAL y0=mPhaseRegistry.GetObj(i).mBiasFraction; REAL y,ymin,ymax; y=pF->GetValue(); ymax=.5+1/M_PI*atan((y+delta-y0)/(2.*sig)); ymin=.5+1/M_PI*atan((y-delta-y0)/(2.*sig)); y=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); y-=.5; if(y<-.499)y=-.499;//Should not happen but make sure we remain in [-pi/2;pi/2] if(y> .499)y= .499; pF->MutateTo(y0+2*sig*tan(M_PI*y)); } if((pH->IsFixed()==false)||(pK->IsFixed()==false)||(pL->IsFixed()==false)) { REAL tx=pH->GetValue(); REAL ty=pK->GetValue(); REAL tz=pL->GetValue(); mpData->GetCrystal().MillerToOrthonormalCoords(tx,ty,tz); { REAL tx0=mPhaseRegistry.GetObj(i).mBiasH; REAL ty0=mPhaseRegistry.GetObj(i).mBiasK; REAL tz0=mPhaseRegistry.GetObj(i).mBiasL; mpData->GetCrystal().MillerToOrthonormalCoords(tx0,ty0,tz0); const REAL delta=pH->GetGlobalOptimStep()*mutationAmplitude*mPhaseRegistry.GetObj(i).mNorm; const REAL sig=2*delta; REAL y,ymin,ymax; ymax=.5+1/M_PI*atan((tx+delta-tx0)/(2.*sig)); ymin=.5+1/M_PI*atan((tx-delta-tx0)/(2.*sig)); y=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); y-=.5; if(y<-.499)y=-.499; if(y> .499)y= .499; tx=tx0+2*sig*tan(M_PI*y); ymax=.5+1/M_PI*atan((ty+delta-ty0)/(2.*sig)); ymin=.5+1/M_PI*atan((ty-delta-ty0)/(2.*sig)); y=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); y-=.5; if(y<-.499)y=-.499; if(y> .499)y= .499; ty=ty0+2*sig*tan(M_PI*y); ymax=.5+1/M_PI*atan((tz+delta-tz0)/(2.*sig)); ymin=.5+1/M_PI*atan((tz-delta-tz0)/(2.*sig)); y=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); y-=.5; if(y<-.499)y=-.499; if(y> .499)y= .499; tz=tz0+2*sig*tan(M_PI*y); } const REAL factor=mPhaseRegistry.GetObj(i).mNorm/sqrt(tx*tx+ty*ty+tz*tz); tx *= factor; ty *= factor; tz *= factor; mpData->GetCrystal().OrthonormalToMillerCoords(tx,ty,tz); pH->MutateTo(tx); pK->MutateTo(ty); pL->MutateTo(tz); } if(pM->IsFixed()==false) { // Given the nature of this param, we use a proportionnal max step const REAL delta=pM->GetGlobalOptimStep()*mutationAmplitude; const REAL sig=2*delta; REAL y,ymin,ymax; y=log(pM->GetValue()); const REAL y0=log(mPhaseRegistry.GetObj(i).mBiasMarchCoeff); ymin=.5+1/M_PI*atan((y-delta-y0)/(2.*sig)); ymax=.5+1/M_PI*atan((y+delta-y0)/(2.*sig)); y=ymin+rand()/(REAL)RAND_MAX*(ymax-ymin); y-=.5; if(y<-.499)y=-.499; if(y> .499)y= .499; pM->MutateTo(exp(y0+2*sig*tan(M_PI*y))); } } } //this->RefinableObj::Print(); mRandomMoveIsDone=true; } REAL TextureMarchDollase::GetBiasingCost()const { REAL cost=0; REAL tmp; for(unsigned int i=0; iGetNbPhase();i++) { tmp =(mPhaseRegistry.GetObj(i).mBiasFraction-mPhaseRegistry.GetObj(i).mFraction)/.04; cost += tmp*tmp; tmp =log10(mPhaseRegistry.GetObj(i).mBiasMarchCoeff/mPhaseRegistry.GetObj(i).mMarchCoeff)/.04; cost += tmp*tmp; REAL tx=mPhaseRegistry.GetObj(i).mH-mPhaseRegistry.GetObj(i).mBiasH; REAL ty=mPhaseRegistry.GetObj(i).mK-mPhaseRegistry.GetObj(i).mBiasK; REAL tz=mPhaseRegistry.GetObj(i).mL-mPhaseRegistry.GetObj(i).mBiasL; mpData->GetCrystal().MillerToOrthonormalCoords(tx,ty,tz); cost +=(tx*tx+ty*ty+tz*tz)/mPhaseRegistry.GetObj(i).mNorm/.04; } VFN_DEBUG_MESSAGE("TextureMarchDollase::GetBiasingCost()="<GetName(),5) } void TextureMarchDollase::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("TextureMarchDollase::XMLInput():"<GetName(),5) for(unsigned int i=0;iAddPhase(0.,1.,1.,0.,0.); mPhaseRegistry.GetObj(nb).XMLInput(is,tag); } } } void TextureMarchDollase::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { for(unsigned int i=0; iGetNbPhase();i++) { RefinablePar *pH=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mH))); RefinablePar *pK=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mK))); RefinablePar *pL=&(this->GetPar(&(mPhaseRegistry.GetObj(i).mL))); if((pH->IsFixed()==false)||(pK->IsFixed()==false)||(pL->IsFixed()==false)) { pH->SetIsFixed(false); pK->SetIsFixed(false); pL->SetIsFixed(false); } REAL tx=pH->GetValue(); REAL ty=pK->GetValue(); REAL tz=pL->GetValue(); mpData->GetCrystal().MillerToOrthonormalCoords(tx,ty,tz); mPhaseRegistry.GetObj(i).mNorm=sqrt(tx*tx+ty*ty+tz*tz); // Something went wrong, preferred orientation vector has null norm ! if(mPhaseRegistry.GetObj(i).mNorm<1e-6) mPhaseRegistry.GetObj(i).mNorm=1; } this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); } void TextureMarchDollase::TagNewBestConfig()const { for(unsigned int i=0; iGetNbPhase();i++) { mPhaseRegistry.GetObj(i).mBiasFraction =mPhaseRegistry.GetObj(i).mFraction; mPhaseRegistry.GetObj(i).mBiasMarchCoeff=mPhaseRegistry.GetObj(i).mMarchCoeff; mPhaseRegistry.GetObj(i).mBiasH =mPhaseRegistry.GetObj(i).mH; mPhaseRegistry.GetObj(i).mBiasK =mPhaseRegistry.GetObj(i).mK; mPhaseRegistry.GetObj(i).mBiasL =mPhaseRegistry.GetObj(i).mL; } } void TextureMarchDollase::CalcCorr() const { if(this->GetNbPhase()==0) { mCorr.resize(0); return; } const long nbReflUsed=mpData->GetNbReflBelowMaxSinThetaOvLambda(); if( (mClockTextureParGetClockTheta()GetNbPhase();i++) fractionNorm+=this->GetFraction(i); if(fractionNorm<1) { nonTexturedFraction= 1.-fractionNorm; fractionNorm=1.; } else nonTexturedFraction=0.; //compute correction for each phase const long nbRefl=mpData->GetNbRefl(); mCorr.resize(nbRefl); mCorr=nonTexturedFraction; CrystVector_REAL reflNorm(nbRefl); { const REAL *xx=mpData->GetReflX().data(); const REAL *yy=mpData->GetReflY().data(); const REAL *zz=mpData->GetReflZ().data(); for(long i=0;iGetNbPhase();i++) { // We are using multiplicity for powder diffraction, therefore with only // unique reflections. But Equivalent reflections do not have the same // texture correction ! So we must use the symmetry oprators, and it is simpler // to apply the symmetries to the texture vector than to all reflections hkl=mpData->GetCrystal().GetSpaceGroup() .GetAllEquivRefl(this->GetPhaseH(i),this->GetPhaseK(i),this->GetPhaseL(i),true); //coefficients const REAL march=1./(this->GetMarchCoeff(i)+1e-6); const REAL march2=this->GetMarchCoeff(i)*this->GetMarchCoeff(i)-march; // Normalized by the number of symmetrical reflections const REAL frac=this->GetFraction(i)/(fractionNorm+1e-6)/hkl.rows(); for(long j=0;jGetReflX().data(); const REAL *yy=mpData->GetReflY().data(); const REAL *zz=mpData->GetReflZ().data(); const REAL *xyznorm=reflNorm.data(); { mpData->GetCrystal().MillerToOrthonormalCoords(tx,ty,tz); const REAL norm=sqrt(tx*tx+ty*ty+tz*tz); tx/=(norm+1e-6); ty/=(norm+1e-6); tz/=(norm+1e-6); } // Calculation REAL tmp; for(long k=0;kIsbeingRefined()==false) //{ // cout <(mpData->GetH(), // mpData->GetK(), // mpData->GetL(), // mpData->GetSinThetaOverLambda(), // mCorr)<Print(); //} mClockCorrCalc.Click(); VFN_DEBUG_EXIT("TextureMarchDollase::CalcCorr()",3) } void TextureMarchDollase::DeleteAllPhase() { } #ifdef __WX__CRYST__ WXCrystObjBasic* TextureMarchDollase::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 //mpWXCrystObj=new WXTextureMarchDollase(parent,this); return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // TextureEllipsoid // //////////////////////////////////////////////////////////////////////// TextureEllipsoid::TextureEllipsoid(const ScatteringData & data, const REAL EPR1, const REAL EPR2, const REAL EPR3, const REAL EPR4, const REAL EPR5, const REAL EPR6): ScatteringCorr(data),mNbReflUsed(0) { mClockMaster.AddChild(mClockTextureEllipsoidPar); mEPR[0]=EPR1; mEPR[1]=EPR2; mEPR[2]=EPR3; mEPR[3]=EPR4; mEPR[4]=EPR5; mEPR[5]=EPR6; InitRefParList(); } TextureEllipsoid::~TextureEllipsoid() { #ifdef __WX__CRYST__ if(mpWXCrystObj!=0) { delete mpWXCrystObj; mpWXCrystObj=0; } #endif } const string & TextureEllipsoid::GetName() const { //So far, we do not need a personalized name... const static string name="TextureEllipsoid"; return name; } const string & TextureEllipsoid::GetClassName() const { //So far, we do not need a personalized name... const static string name="TextureEllipsoid"; return name; } void TextureEllipsoid::SetParams(const REAL EPR1, const REAL EPR2, const REAL EPR3, const REAL EPR4, const REAL EPR5, const REAL EPR6) { mEPR[0]=EPR1; mEPR[1]=EPR2; mEPR[2]=EPR3; mEPR[3]=EPR4; mEPR[4]=EPR5; mEPR[5]=EPR6; UpdateEllipsoidPar(); } void TextureEllipsoid::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; /* if(!(gpRefParTypeScattDataCorrInt->IsDescendantFromOrSameAs(type))) { mRandomMoveIsDone=true; return; } */ { VFN_DEBUG_MESSAGE("TextureEllipsoid::GlobalOptRandomMove()",1) RefinablePar *pEPR[6]; for (int i=0; i<6; i++) { pEPR[i] = &(this->GetPar(&(mEPR[i]))); if (pEPR[i]->IsFixed()==false) pEPR[i]->Mutate(pEPR[i]->GetGlobalOptimStep()*2*(rand()/(REAL)RAND_MAX-0.5)*mutationAmplitude); } UpdateEllipsoidPar(); } //this->RefinableObj::Print(); mRandomMoveIsDone=true; } void TextureEllipsoid::XMLOutput(ostream &os,int indent)const { if((mEPR[0]==0) && (mEPR[1]==0) && (mEPR[2]==0) && (mEPR[3]==0) && (mEPR[4]==0) && (mEPR[5]==0)) return; VFN_DEBUG_ENTRY("TextureEllipsoid::XMLOutput():"<GetName(),5) for(int i=0;iGetName(),5) } void TextureEllipsoid::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("TextureEllipsoid::XMLInput():"<GetName(),5) for(unsigned int i=0;iRefinableObj::BeginOptimization(allowApproximations,enableRestraints); } void TextureEllipsoid::CalcCorr() const { if((mEPR[0]==0) && (mEPR[1]==0) && (mEPR[2]==0) && (mEPR[3]==0) && (mEPR[4]==0) && (mEPR[5]==0)) { mCorr.resize(0); return; } const long nbReflUsed=mpData->GetNbReflBelowMaxSinThetaOvLambda(); if( (mClockTextureEllipsoidParGetClockTheta()GetClockNbReflBelowMaxSinThetaOvLambda()GetNbRefl(); mCorr.resize(nbRefl); ///mCorr=1.0; /// Icorr = Iobs[1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2]^-1.5 REAL tmp, dhkl; REAL sum=0; REAL *pCorr=mCorr.data(); const REAL *pH=mpData->GetH().data(); const REAL *pK=mpData->GetH().data(); const REAL *pL=mpData->GetH().data(); const REAL *pstol=mpData->GetSinThetaOverLambda().data(); for(long i=0;iHasCrystal()) num = mpData->GetCrystal().GetSpaceGroup().GetSpaceGroupNumber(); bool bEPR [6]; for (int i=0; i<6; i++) bEPR[i] = true; if(num <=2) { } else if((num <=15) && (0==mpData->GetCrystal().GetSpaceGroup().GetUniqueAxis())) { mEPR[4]=0.0; mEPR[5]=0.0; bEPR[4]=false; bEPR[5]=false; } else if((num <=15) && (1==mpData->GetCrystal().GetSpaceGroup().GetUniqueAxis())) { mEPR[3]=0.0; mEPR[5]=0.0; bEPR[3]=false; bEPR[5]=false; } else if((num <=15) && (2==mpData->GetCrystal().GetSpaceGroup().GetUniqueAxis())) { mEPR[3]=0.0; mEPR[4]=0.0; bEPR[3]=false; bEPR[4]=false; } else if(num <=74) { mEPR[3]=0.0; mEPR[4]=0.0; mEPR[5]=0.0; bEPR[3]=false; bEPR[4]=false; bEPR[5]=false; } else if(num <= 142) { mEPR[1]=mEPR[0]; mEPR[3]=0.0; mEPR[4]=0.0; mEPR[5]=0.0; bEPR[1]=false; bEPR[3]=false; bEPR[4]=false; bEPR[5]=false; } else if(num <= 194) {//Hexagonal axes, for hexagonal and non-rhomboedral trigonal cells mEPR[1]=mEPR[0]; mEPR[3]=mEPR[0]*0.5; mEPR[4]=0.0; mEPR[5]=0.0; bEPR[1]=false; bEPR[3]=false; bEPR[4]=false; bEPR[5]=false; } else { mEPR[1]=mEPR[0]; mEPR[2]=mEPR[0]; mEPR[3]=0.0; mEPR[4]=0.0; mEPR[5]=0.0; bEPR[1]=false; bEPR[2]=false; bEPR[3]=false; bEPR[4]=false; bEPR[5]=false; } for (int i=0; i<6; i++) this->GetPar(i).SetIsUsed(bEPR[i]); VFN_DEBUG_EXIT("TextureEllipsoid::UpdateEllipsoidPar().",3) } void TextureEllipsoid::InitRefParList() { VFN_DEBUG_ENTRY("TextureEllipsoid::InitRefParList()",5) if(this->GetNbPar()==0) { char buf [5]; for (int i=0; i<6; i++) { sprintf(buf,"%d",i+1); RefinablePar tmp("EPR"+(string)buf, &(mEPR[i]), -10., 10., gpRefParTypeScattDataCorrInt_Ellipsoid, REFPAR_DERIV_STEP_ABSOLUTE, false, true, true, false, 1.0); tmp.AssignClock(mClockTextureEllipsoidPar); tmp.SetDerivStep(1e-4); tmp.SetGlobalOptimStep(0.1); this->AddPar(tmp); } } VFN_DEBUG_EXIT("TextureEllipsoid::InitRefParList():Finished",5) } #ifdef __WX__CRYST__ WXCrystObjBasic* TextureEllipsoid::WXCreate(wxWindow* parent) { VFN_DEBUG_ENTRY("TextureEllipsoid::WXCreate()",6) if(mpWXCrystObj==0) mpWXCrystObj=new WXTextureEllipsoid(parent,this); VFN_DEBUG_EXIT("TextureEllipsoid::WXCreate()",6) return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // Time Of Flight correction // //////////////////////////////////////////////////////////////////////// TOFCorr::TOFCorr(const ScatteringData & data): ScatteringCorr(data) {} TOFCorr::~TOFCorr() {} const string & TOFCorr::GetName() const { //So far, we do not need a personalized name... const static string mName="TOFCorr"; return mName; } const string & TOFCorr::GetClassName() const { const static string className="TOFCorr"; return className; } void TOFCorr::CalcCorr() const { const REAL *pstol=mpData->GetSinThetaOverLambda().data(); if(mpData->GetClockTheta()GetNbRefl()); for(long i=0;iGetNbRefl();i++) mCorr(i) = pow((float)(1.0/(2.0* *pstol++)),(int)4); mClockCorrCalc.Click(); } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringCorr.h000066400000000000000000000241351417150057700241530ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _OBJCRYST_SCATTERING_CORR_H_ #define _OBJCRYST_SCATTERING_CORR_H_ #include "ObjCryst/ObjCryst/ScatteringData.h" namespace ObjCryst { /** Base class to compute all kind of corrections to intensities: Lorentz, Polar, * absorption, texcture, extinction, etc... * * The computed intensities are to be multiplied by all the ScatteringCorr calculated. * * * This is an abstract base class. */ class ScatteringCorr { public: /// Constructor, with the associated ScatteringData object. ScatteringCorr(const ScatteringData & data); virtual ~ScatteringCorr(); /// Get the name of this object virtual const string & GetName() const=0; /// Get the name of the class virtual const string & GetClassName() const=0; /// Get the vector of corrections for all reflections. Calculated values must /// be multiplied by these values. /// If the vector is empty (size==0), then no correction should be applied const CrystVector_REAL& GetCorr() const; /// Get the value of the clock corresponding to the last time the correction /// was actually computed const RefinableObjClock& GetClockCorr()const; protected: /// Do the computation of corrected intensities virtual void CalcCorr() const=0; /// The associated ScatteringData object const ScatteringData *mpData; /// The vector of correction to intensities. mutable CrystVector_REAL mCorr; /// The clock marking the last time the correction was calculated mutable RefinableObjClock mClockCorrCalc; }; /** Lorentz Correction * * So far, it only considers the correction for equatorial diffraction: * \f$ L = \frac{1}{\sin(2\theta)} \f$ */ class LorentzCorr:public ScatteringCorr { public: LorentzCorr(const ScatteringData & data); virtual ~LorentzCorr(); virtual const string & GetName() const; virtual const string & GetClassName() const; protected: virtual void CalcCorr() const; }; /** Polarization Correction * * So far, it only considers the correction for equatorial diffraction: *\f$ P = \frac{1}{1+A}\left(1+A\cos^2(2\theta)\right) \f$ (Polarization factor), with * \f$ A = \frac{1-f}{1+f} \f$, where f is the polarization rate of the incident *beam in the plane which (i) includes the incident beam, and (ii) is perpendicular to *the diffracting plane. For an X-Ray Tube without monochromator, A=1, and *if there is a monochromator : \f$ A = \cos^2(2\theta_{mono}) \f$ * * Currently, the linear polarization factor is directly read from the radiation object, * and the linear polarization (if any) is assumed to be perpendicular to the diffracting * plane (standard synchrotron geometry). * * \todo: extend this to take into account other diffracting & monochromatic geometries. */ class PolarizationCorr:public ScatteringCorr { public: PolarizationCorr(const ScatteringData & data); virtual ~PolarizationCorr(); virtual const string & GetName() const; virtual const string & GetClassName() const; protected: virtual void CalcCorr() const; mutable REAL mPolarAfactor; }; /** Slit aperture correction (for powder) * * This correction takes into account the fact that diffraction * rings (cones) have a portion of the ring proportionnal to * \f$ SlitAp = \frac{1}{\sin(\theta)} \f$ which falls into the detector * (due to slits in the direction perpendicular to the incident beam/ detector plane). */ class PowderSlitApertureCorr:public ScatteringCorr { public: PowderSlitApertureCorr(const ScatteringData & data); virtual ~PowderSlitApertureCorr(); virtual const string & GetName() const; virtual const string & GetClassName() const; protected: virtual void CalcCorr() const; }; class TextureMarchDollase; /** One texture phase for the March-Dollase model. * */ struct TexturePhaseMarchDollase { TexturePhaseMarchDollase(const REAL f, const REAL c,const REAL h,const REAL k, const REAL l, TextureMarchDollase &); ~TexturePhaseMarchDollase(); const string& GetClassName()const; const string& GetName()const; void SetPar(const REAL f, const REAL c,const REAL h,const REAL k, const REAL l); void XMLOutput(ostream &os,int indent=0)const; void XMLInput(istream &is,const XMLCrystTag &tag); REAL mFraction,mMarchCoeff,mH,mK,mL; /// Norm of the (HKL) vector, to keep it constant during optimization mutable REAL mNorm; /// The parent TextureMarchDollase object. TextureMarchDollase *mpTextureMarchDollase; /// Values of parameters towards which the optimization is biased (if biasing /// is used). These are normally dynamically updated to the last "best" values found. mutable REAL mBiasFraction,mBiasMarchCoeff,mBiasH,mBiasK,mBiasL; #ifdef __WX__CRYST__ WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); WXCrystObjBasic *mpWXCrystObj; #endif }; /** Texture correction using the March-Dollase model. * * This can include several phases. * */ class TextureMarchDollase:public ScatteringCorr,public RefinableObj { public: TextureMarchDollase(const ScatteringData & data); virtual ~TextureMarchDollase(); virtual const string & GetName() const; virtual const string & GetClassName() const; void AddPhase(const REAL fraction, const REAL coeffMarch, const REAL h,const REAL k, const REAL l); void SetPhasePar(const unsigned int i, const REAL fraction, const REAL coeffMarch, const REAL h,const REAL k, const REAL l); void DeletePhase(const unsigned int i); unsigned int GetNbPhase() const; REAL GetFraction(const unsigned int i)const; REAL GetMarchCoeff(const unsigned int i)const; REAL GetPhaseH(const unsigned int i)const; REAL GetPhaseK(const unsigned int i)const; REAL GetPhaseL(const unsigned int i)const; virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); virtual REAL GetBiasingCost()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); virtual void TagNewBestConfig()const; protected: virtual void CalcCorr() const; void DeleteAllPhase(); ObjRegistry mPhaseRegistry; RefinableObjClock mClockTexturePar; /// Number of reflexion for which the calculation is actually done. /// This is automaticaly updated during CalcCorr, from the parent /// ScatteringData::GetMaxSinThetaOvLambda() mutable unsigned long mNbReflUsed; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXTextureMarchDollase; #endif }; /** Texture correction using the Ellipsoidal preferred orientation function. * * Icorr = Iobs[ 1 + (EPR1*h^2 + EPR2*k^2 + EPR3*l^2 + EPR4*2hk + EPR5*2hl + EPR6*2kl) * 0.001d^2 ]^-1.5 * */ class TextureEllipsoid:public ScatteringCorr,public RefinableObj { public: TextureEllipsoid(const ScatteringData & data, const REAL EPR1=0.0, const REAL EPR2=0.0, const REAL EPR3=0.0, const REAL EPR4=0.0, const REAL EPR5=0.0, const REAL EPR6=0.0); virtual ~TextureEllipsoid(); virtual const string & GetName() const; virtual const string & GetClassName() const; void SetParams(const REAL EPR1, const REAL EPR2, const REAL EPR3, const REAL EPR4, const REAL EPR5, const REAL EPR6); REAL mEPR[6]; virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); /// Prepare the refinable parameters list void InitRefParList(); /// Update ellipsoid parameters for tetragonal, trigonal, hexagonal, cubic lattices. /// This is needed during Refinement, since for example in a quadratic spg, /// only a is refined and we need to have b=a... void UpdateEllipsoidPar(); protected: virtual void CalcCorr() const; RefinableObjClock mClockTextureEllipsoidPar; /// Number of reflexion for which the calculation is actually done. /// This is automaticaly updated during CalcCorr, from the parent /// ScatteringData::GetMaxSinThetaOvLambda() mutable unsigned long mNbReflUsed; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent); #endif }; /** Time-Of-Flight Correction * * * \f$ T = d^4\sin(\theta) \f$ * * The \theta angle of the detector is ignored, as it is just a scale factor. */ class TOFCorr:public ScatteringCorr { public: TOFCorr(const ScatteringData & data); virtual ~TOFCorr(); virtual const string & GetName() const; virtual const string & GetClassName() const; protected: virtual void CalcCorr() const; }; }//namespace #endif //_OBJCRYST_SCATTERING_CORR_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringData.cpp000066400000000000000000003066651417150057700244650ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for LibCryst++ ScatteringData class * */ #include #include #include "cctbx/sgtbx/space_group.h" #include "cctbx/miller/index_generator.h" #include "cctbx/miller/sym_equiv.h" #include "cctbx/eltbx/wavelengths.h" #include "ObjCryst/ObjCryst/ScatteringData.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/Chronometer.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxPowderPattern.h" #include "ObjCryst/wxCryst/wxRadiation.h" #endif #include #include #include //for sprintf() #ifdef HAVE_SSE_MATHFUN #include "ObjCryst/Quirks/sse_mathfun.h" #endif #define POSSIBLY_UNUSED(expr) (void)(expr) namespace ObjCryst { const RefParType *gpRefParTypeScattData= 0; const RefParType *gpRefParTypeScattDataScale=0; const RefParType *gpRefParTypeScattDataProfile=0; const RefParType *gpRefParTypeScattDataProfileType=0; const RefParType *gpRefParTypeScattDataProfileWidth=0; const RefParType *gpRefParTypeScattDataProfileAsym=0; const RefParType *gpRefParTypeScattDataCorr=0; const RefParType *gpRefParTypeScattDataCorrInt=0; const RefParType *gpRefParTypeScattDataCorrIntPO_Direction=0; const RefParType *gpRefParTypeScattDataCorrIntPO_Fraction=0; const RefParType *gpRefParTypeScattDataCorrIntPO_Amplitude=0; const RefParType *gpRefParTypeScattDataCorrInt_Ellipsoid=0; const RefParType *gpRefParTypeScattDataCorrIntAbsorp=0; const RefParType *gpRefParTypeScattDataCorrIntPolar=0; const RefParType *gpRefParTypeScattDataCorrIntExtinc=0; const RefParType *gpRefParTypeScattDataCorrPos=0; const RefParType *gpRefParTypeScattDataBackground=0; const RefParType *gpRefParTypeRadiation=0; const RefParType *gpRefParTypeRadiationWavelength=0; long NiftyStaticGlobalObjectsInitializer_ScatteringData::mCount=0; #ifndef HAVE_SSE_MATHFUN //###################################################################### // Tabulated math functions for faster (&less precise) F(hkl) calculation //These function are defined and used in cristallo-spacegroup.cpp //Currently tabulating sine and cosine only //###################################################################### //static bool sLibCrystTabulCosineIsInit=false; //conversion value static REAL sLibCrystTabulCosineRatio; // Number of tabulated values of cosine between [0;2pi] // 100 000 is far enough for a model search, yielding a maximum // error less than .05%... 10000 should be enough, too, with (probably) a higher cache hit #define sLibCrystNbTabulSine 8192 #define sLibCrystNbTabulSineMASK 8191 //storage of tabulated values of cosine, and a table with interlaced csoine/sine values static REAL *spLibCrystTabulCosine; static REAL *spLibCrystTabulCosineSine; void InitLibCrystTabulCosine() { VFN_DEBUG_MESSAGE("InitLibCrystTabulCosine()",10) spLibCrystTabulCosine=new REAL[sLibCrystNbTabulSine]; spLibCrystTabulCosineSine=new REAL[sLibCrystNbTabulSine*2]; REAL *tmp=spLibCrystTabulCosine; sLibCrystTabulCosineRatio=sLibCrystNbTabulSine/2./M_PI; for(REAL i=0;iInitOptions(); mRadiationType.SetChoice(RAD_XRAY); mClockMaster.AddChild(mClockWavelength); mClockMaster.AddChild(mClockRadiation); this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC); } Radiation::Radiation(const RadiationType rad,const REAL wavelength) { this->InitOptions(); mRadiationType.SetChoice(rad); mWavelength=wavelength; mXRayTubeName=""; mXRayTubeDeltaLambda=0.;//useless here mXRayTubeAlpha2Alpha1Ratio=0.5;//useless here mLinearPolarRate=0.95;//assume it's synchrotron ? mClockMaster.AddChild(mClockWavelength); mClockMaster.AddChild(mClockRadiation); this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC); } Radiation::Radiation(const string &XRayTubeElementName,const REAL alpha2Alpha2ratio) { this->InitOptions(); this->SetWavelength(XRayTubeElementName,alpha2Alpha2ratio); mClockMaster.AddChild(mClockWavelength); mClockMaster.AddChild(mClockRadiation); } Radiation::Radiation(const Radiation &old): mRadiationType(old.mRadiationType), mWavelengthType(old.mWavelengthType), mWavelength(old.mWavelength), mXRayTubeName(old.mXRayTubeName), mXRayTubeDeltaLambda(old.mXRayTubeDeltaLambda), mXRayTubeAlpha2Alpha1Ratio(old.mXRayTubeAlpha2Alpha1Ratio), mLinearPolarRate(old.mLinearPolarRate) { mClockWavelength.Click(); mClockMaster.AddChild(mClockWavelength); mClockMaster.AddChild(mClockRadiation); this->SetWavelengthType((WavelengthType)old.mWavelengthType.GetChoice()); } Radiation::~Radiation() {} const string& Radiation::GetClassName() const { const static string className="Radiation"; return className; } void Radiation::operator=(const Radiation &old) { mRadiationType =old.mRadiationType; mWavelength =old.mWavelength; mXRayTubeName =old.mXRayTubeName; mXRayTubeDeltaLambda =old.mXRayTubeDeltaLambda; mXRayTubeAlpha2Alpha1Ratio =old.mXRayTubeAlpha2Alpha1Ratio; mClockWavelength.Click(); mRadiationType.SetChoice(old.mRadiationType.GetChoice()); this->SetWavelengthType((WavelengthType) old.mWavelengthType.GetChoice()); } RadiationType Radiation::GetRadiationType()const {return (RadiationType) mRadiationType.GetChoice();} void Radiation::SetRadiationType(const RadiationType rad) { mRadiationType.SetChoice(rad); if(rad == RAD_NEUTRON) mLinearPolarRate=0; if(rad == RAD_ELECTRON) { mLinearPolarRate=0; this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC); } else this->UpdateDisplay(); } void Radiation::SetWavelengthType(const WavelengthType &type) { mWavelengthType.SetChoice((unsigned long) type); if(type==WAVELENGTH_TOF) { this->SetRadiationType(RAD_NEUTRON); this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false); this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false); } if(type==WAVELENGTH_ALPHA12) { this->SetRadiationType(RAD_XRAY); this->GetPar("XRayTubeDeltaLambda").SetIsUsed(true); this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(true); } if(type==WAVELENGTH_MONOCHROMATIC) { this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false); this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false); } this->UpdateDisplay(); } WavelengthType Radiation::GetWavelengthType()const {return (WavelengthType) mWavelengthType.GetChoice();} const CrystVector_REAL& Radiation::GetWavelength() const {return mWavelength;} void Radiation::SetWavelength(const REAL l) { mWavelength.resize(1); mWavelength=l; mClockWavelength.Click(); this->GetPar("XRayTubeDeltaLambda").SetIsUsed(false); this->GetPar("XRayTubeAlpha2Alpha1Ratio").SetIsUsed(false); } void Radiation::SetWavelength(const string &XRayTubeElementName, const REAL alpha2Alpha2ratio) { VFN_DEBUG_MESSAGE("Radiation::SetWavelength(tubeName,ratio):",5) mXRayTubeName=XRayTubeElementName; this->SetRadiationType(RAD_XRAY); mWavelength.resize(1); mLinearPolarRate=0; if(XRayTubeElementName.length() >=3) //:KLUDGE: { if(XRayTubeElementName=="CoA1") { mWavelength=1.78901; this->SetWavelengthType(WAVELENGTH_MONOCHROMATIC); } else { try { cctbx::eltbx::wavelengths::characteristic ch(mXRayTubeName); if(!ch.is_valid()) { cout << "WARNING: could not interpret X-Ray tube name:"<SetWavelengthType(WAVELENGTH_MONOCHROMATIC); } catch(cctbx::error) { cout << "WARNING: could not interpret X-Ray tube name:"<SetWavelengthType(WAVELENGTH_ALPHA12); } mClockWavelength.Click(); } REAL Radiation::GetXRayTubeDeltaLambda()const {return mXRayTubeDeltaLambda;} REAL Radiation::GetXRayTubeAlpha2Alpha1Ratio()const {return mXRayTubeAlpha2Alpha1Ratio;} const RefinableObjClock& Radiation::GetClockWavelength() const {return mClockWavelength;} const RefinableObjClock& Radiation::GetClockRadiation()const {return mRadiationType.GetClock();} void Radiation::Print()const { VFN_DEBUG_MESSAGE("Radiation::Print():"<GetName(),5) cout << "Radiation:" << " " ; switch(mRadiationType.GetChoice()) { case RAD_NEUTRON: cout<< "Neutron,";break; case RAD_XRAY: cout<< "X-Ray,";break; case RAD_ELECTRON: cout<< "Electron,";break; } cout << "Wavelength=" <<" "; switch(mWavelengthType.GetChoice()) { case WAVELENGTH_MONOCHROMATIC: cout<< "monochromatic:"<<" "<AddOption(&mRadiationType); this->AddOption(&mWavelengthType); {//Fixed by default RefinablePar tmp("Wavelength",mWavelength.data(),0.05,20., gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockWavelength); this->AddPar(tmp); } {//Fixed by default RefinablePar tmp("XRayTubeDeltaLambda",&mXRayTubeDeltaLambda,0.001,20., gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockWavelength); this->AddPar(tmp); } {//Fixed by default RefinablePar tmp("XRayTubeAlpha2Alpha1Ratio",&mXRayTubeAlpha2Alpha1Ratio,0.5,0.5, gpRefParTypeRadiationWavelength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockWavelength); this->AddPar(tmp); } } #ifdef __WX__CRYST__ WXCrystObjBasic* Radiation::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXRadiation(parent,this); return mpWXCrystObj; } #endif //////////////////////////////////////////////////////////////////////// // // ScatteringData // //////////////////////////////////////////////////////////////////////// ScatteringData::ScatteringData(): mNbRefl(0), mpCrystal(0),mGlobalBiso(0),mUseFastLessPreciseFunc(false), mIgnoreImagScattFact(false),mMaxSinThetaOvLambda(10) { VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData()",10) {//This should be done elsewhere... RefinablePar tmp("Global Biso",&mGlobalBiso,-1.,1., gpRefParTypeScattPowTemperatureIso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockGlobalBiso); this->AddPar(tmp); } mClockMaster.AddChild(mClockHKL); mClockMaster.AddChild(mClockGlobalBiso); mClockMaster.AddChild(mClockNbReflUsed); mClockMaster.AddChild(mClockFhklObsSq); } ScatteringData::ScatteringData(const ScatteringData &old): mNbRefl(old.mNbRefl), mpCrystal(old.mpCrystal),mUseFastLessPreciseFunc(old.mUseFastLessPreciseFunc), //Do not copy temporary arrays mClockHKL(old.mClockHKL), mIgnoreImagScattFact(old.mIgnoreImagScattFact), mMaxSinThetaOvLambda(old.mMaxSinThetaOvLambda) { VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData(&old)",10) mClockStructFactor.Reset(); mClockTheta.Reset(); mClockScattFactor.Reset(); mClockScattFactorResonant.Reset(); mClockThermicFact.Reset(); this->SetHKL(old.GetH(),old.GetK(),old.GetL()); VFN_DEBUG_MESSAGE("ScatteringData::ScatteringData(&old):End",5) {//This should be done elsewhere... RefinablePar tmp("Global Biso",&mGlobalBiso,-1.,1., gpRefParTypeScattPowTemperatureIso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockGlobalBiso); this->AddPar(tmp); } mClockMaster.AddChild(mClockHKL); mClockMaster.AddChild(mClockGlobalBiso); mClockMaster.AddChild(mClockNbReflUsed); mClockMaster.AddChild(mClockFhklObsSq); } ScatteringData::~ScatteringData() { VFN_DEBUG_MESSAGE("ScatteringData::~ScatteringData()",10) } void ScatteringData::SetHKL(const CrystVector_REAL &h, const CrystVector_REAL &k, const CrystVector_REAL &l) { VFN_DEBUG_ENTRY("ScatteringData::SetHKL(h,k,l)",5) mNbRefl=h.numElements(); mH=h; mK=k; mL=l; mClockHKL.Click(); this->PrepareHKLarrays(); VFN_DEBUG_EXIT("ScatteringData::SetHKL(h,k,l):End",5) } void ScatteringData::GenHKLFullSpace2(const REAL maxSTOL,const bool unique) { //(*fpObjCrystInformUser)("Generating Full HKL list..."); VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace2()",5) TAU_PROFILE("ScatteringData::GenHKLFullSpace2()","void (REAL,bool)",TAU_DEFAULT); if(0==mpCrystal) { throw ObjCrystException("ScatteringData::GenHKLFullSpace2() \ no crystal assigned yet to this ScatteringData object."); } cctbx::uctbx::unit_cell uc=cctbx::uctbx::unit_cell(scitbx::af::double6(mpCrystal->GetLatticePar(0), mpCrystal->GetLatticePar(1), mpCrystal->GetLatticePar(2), mpCrystal->GetLatticePar(3)*RAD2DEG, mpCrystal->GetLatticePar(4)*RAD2DEG, mpCrystal->GetLatticePar(5)*RAD2DEG)); cctbx::miller::index_generator igen(uc, this->GetCrystal().GetSpaceGroup().GetCCTbxSpg().type(), !(this->IsIgnoringImagScattFact()), 1/(2*maxSTOL)); if(unique) { mNbRefl=0; CrystVector_long H(mNbRefl); CrystVector_long K(mNbRefl); CrystVector_long L(mNbRefl); mMultiplicity.resize(mNbRefl); for(;;) { if(mNbRefl==H.numElements()) { H.resizeAndPreserve(mNbRefl+100); K.resizeAndPreserve(mNbRefl+100); L.resizeAndPreserve(mNbRefl+100); mMultiplicity.resizeAndPreserve(mNbRefl+100); } cctbx::miller::index<> h = igen.next(); if (h.is_zero()) break; H(mNbRefl)=h[0]; K(mNbRefl)=h[1]; L(mNbRefl)=h[2]; cctbx::miller::sym_equiv_indices sei(this->GetCrystal().GetSpaceGroup().GetCCTbxSpg(),h); mMultiplicity(mNbRefl)=sei.multiplicity(!(this->IsIgnoringImagScattFact())); mNbRefl++; } H.resizeAndPreserve(mNbRefl); K.resizeAndPreserve(mNbRefl); L.resizeAndPreserve(mNbRefl); mMultiplicity.resizeAndPreserve(mNbRefl); this->SetHKL(H,K,L); this->SortReflectionBySinThetaOverLambda(maxSTOL); } else { mNbRefl=0; CrystVector_long H(mNbRefl); CrystVector_long K(mNbRefl); CrystVector_long L(mNbRefl); mMultiplicity.resize(mNbRefl); for(;;) { cctbx::miller::index<> h = igen.next(); if (h.is_zero()) break; cctbx::miller::sym_equiv_indices sei(this->GetCrystal().GetSpaceGroup().GetCCTbxSpg(),h); for(int i=0;i k = sei(i).h(); if(mNbRefl==H.numElements()) { H.resizeAndPreserve(mNbRefl+100); K.resizeAndPreserve(mNbRefl+100); L.resizeAndPreserve(mNbRefl+100); mMultiplicity.resizeAndPreserve(mNbRefl+100); } mMultiplicity(mNbRefl)=sei.multiplicity(!(this->IsIgnoringImagScattFact())); H(mNbRefl)=k[0]; K(mNbRefl)=k[1]; L(mNbRefl++)=k[2]; } } H.resizeAndPreserve(mNbRefl); K.resizeAndPreserve(mNbRefl); L.resizeAndPreserve(mNbRefl); mMultiplicity.resizeAndPreserve(mNbRefl); this->SetHKL(H,K,L); this->SortReflectionBySinThetaOverLambda(maxSTOL); } mClockHKL.Click(); /*{ char buf [200]; sprintf(buf,"Generating Full HKL list...Done (kept %d reflections)",(int)mNbRefl); (*fpObjCrystInformUser)((string)buf); }*/ VFN_DEBUG_EXIT("ScatteringData::GenHKLFullSpace2():End",5) } void ScatteringData::GenHKLFullSpace(const REAL maxTheta,const bool useMultiplicity) { VFN_DEBUG_ENTRY("ScatteringData::GenHKLFullSpace()",5) if(this->GetRadiation().GetWavelength()(0) <=.01) { throw ObjCrystException("ScatteringData::GenHKLFullSpace() \ no wavelength assigned yet to this ScatteringData object.");; } this->GenHKLFullSpace2(sin(maxTheta)/this->GetRadiation().GetWavelength()(0),useMultiplicity); VFN_DEBUG_EXIT("ScatteringData::GenHKLFullSpace()",5) } RadiationType ScatteringData::GetRadiationType()const {return this->GetRadiation().GetRadiationType();} void ScatteringData::SetCrystal(Crystal &crystal) { VFN_DEBUG_MESSAGE("ScatteringData::SetCrystal()",5) if(mpCrystal!=0) mpCrystal->DeRegisterClient(*this); mpCrystal=&crystal; this->AddSubRefObj(crystal); crystal.RegisterClient(*this); mClockMaster.AddChild(mpCrystal->GetClockLatticePar()); mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); } const Crystal& ScatteringData::GetCrystal()const {return *mpCrystal;} Crystal& ScatteringData::GetCrystal() {return *mpCrystal;} bool ScatteringData::HasCrystal()const {return mpCrystal!=0;} long ScatteringData::GetNbRefl() const {return mNbRefl;} const CrystVector_REAL& ScatteringData::GetH() const {return mH;} const CrystVector_REAL& ScatteringData::GetK() const {return mK;} const CrystVector_REAL& ScatteringData::GetL() const {return mL;} const CrystVector_REAL& ScatteringData::GetH2Pi() const {return mH2Pi;} const CrystVector_REAL& ScatteringData::GetK2Pi() const {return mK2Pi;} const CrystVector_REAL& ScatteringData::GetL2Pi() const {return mH2Pi;} const CrystVector_REAL& ScatteringData::GetReflX() const { VFN_DEBUG_ENTRY("ScatteringData::GetReflX()",1) this->CalcSinThetaLambda(); VFN_DEBUG_EXIT("ScatteringData::GetReflX()",1) return mX; } const CrystVector_REAL& ScatteringData::GetReflY() const { VFN_DEBUG_ENTRY("ScatteringData::GetReflY()",1) this->CalcSinThetaLambda(); VFN_DEBUG_EXIT("ScatteringData::GetReflY()",1) return mY; } const CrystVector_REAL& ScatteringData::GetReflZ() const { VFN_DEBUG_ENTRY("ScatteringData::GetReflZ()",1) this->CalcSinThetaLambda(); VFN_DEBUG_EXIT("ScatteringData::GetReflZ()",1) return mZ; } const CrystVector_REAL& ScatteringData::GetSinThetaOverLambda()const { VFN_DEBUG_ENTRY("ScatteringData::GetSinThetaOverLambda()",1) this->CalcSinThetaLambda(); VFN_DEBUG_EXIT("ScatteringData::GetSinThetaOverLambda()",1) return mSinThetaLambda; } const CrystVector_REAL& ScatteringData::GetTheta()const { VFN_DEBUG_ENTRY("ScatteringData::GetTheta()",1) this->CalcSinThetaLambda(); VFN_DEBUG_EXIT("ScatteringData::GetTheta()",1) return mTheta; } const RefinableObjClock& ScatteringData::GetClockTheta()const { return mClockTheta; } const CrystVector_REAL& ScatteringData::GetFhklCalcSq() const { VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcSq()",2) this->CalcStructFactor(); if(mClockStructFactorSq>mClockStructFactor) return mFhklCalcSq; #ifdef __LIBCRYST_VECTOR_USE_BLITZ__ mFhklCalcSq=pow2(mFhklCalcReal)+pow2(mFhklCalcImag); #else const REAL *pr,*pi; REAL *p; pr=mFhklCalcReal.data(); pi=mFhklCalcImag.data(); p=mFhklCalcSq.data(); for(long i=0;i& ScatteringData::GetFhklCalcSq_FullDeriv(std::set &vPar) { TAU_PROFILE("ScatteringData::GetFhklCalcSq_FullDeriv()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcSq()",2) this->CalcStructFactor_FullDeriv(vPar); mFhklCalcSq_FullDeriv[0]=this->GetFhklCalcSq(); mFhklCalcSq_FullDeriv.clear();// :TODO: avoid complete clear const REAL *pr,*pi,*prd,*pid; REAL *p; for(std::set::iterator par=vPar.begin();par!=vPar.end();par++) { if((*par)==0) continue; if(mFhklCalcReal_FullDeriv[*par].size()==0) { mFhklCalcSq_FullDeriv[*par].resize(0); continue; } mFhklCalcSq_FullDeriv[*par].resize(mNbRefl);//Should use mNbRefleUsed instead ? pr=mFhklCalcReal.data(); pi=mFhklCalcImag.data(); prd=mFhklCalcReal_FullDeriv[*par].data(); pid=mFhklCalcImag_FullDeriv[*par].data(); p=mFhklCalcSq_FullDeriv[*par].data(); for(long i=0;iCalcStructFactor(); VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcReal()",2) return mFhklCalcReal; } const CrystVector_REAL& ScatteringData::GetFhklCalcImag() const { VFN_DEBUG_ENTRY("ScatteringData::GetFhklCalcImag()",2) this->CalcStructFactor(); VFN_DEBUG_EXIT("ScatteringData::GetFhklCalcImag()",2) return mFhklCalcImag; } const CrystVector_REAL& ScatteringData::GetFhklObsSq() const { return mFhklObsSq; } void ScatteringData::SetFhklObsSq(const CrystVector_REAL &obs) { if(obs.numElements() != mNbRefl) throw ObjCrystException("ScatteringData::SetFhklObsSq(): incorrect number of reflections !"); mFhklObsSq = obs; mClockFhklObsSq.Click(); } const map& ScatteringData::GetScatteringFactor() const { this->CalcScattFactor(); return mvScatteringFactor; } CrystVector_REAL ScatteringData::GetWavelength()const {return this->GetRadiation().GetWavelength();} #if 0 void ScatteringData::SetUseFastLessPreciseFunc(const bool useItOrNot) { mUseFastLessPreciseFunc=useItOrNot; mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); } #endif void ScatteringData::SetIsIgnoringImagScattFact(const bool b) { VFN_DEBUG_MESSAGE("ScatteringData::SetIsIgnoringImagScattFact():"<GetFhklCalcSq(); CrystVector_REAL theta; theta=mTheta; theta *= RAD2DEG; os <<" Number of reflections:"< (mH,mK,mL,mFhklCalcSq,mFhklCalcReal,mFhklCalcImag,theta,mSinThetaLambda,12,4,mNbReflUsed); VFN_DEBUG_EXIT("ScatteringData::PrintFhklCalc()",5) } void ScatteringData::PrintFhklCalcDetail(ostream &os)const { VFN_DEBUG_ENTRY("ScatteringData::PrintFhklCalcDetail()",5) this->GetFhklCalcSq(); CrystVector_REAL theta; theta=mTheta; theta *= RAD2DEG; vector v; v.push_back(&mH); v.push_back(&mK); v.push_back(&mL); v.push_back(&mSinThetaLambda); v.push_back(&theta); v.push_back(&mFhklCalcSq); v.push_back(&mFhklCalcReal); v.push_back(&mFhklCalcImag); os <<" Number of reflections:"< sf; sf.resize(mvRealGeomSF.size()*2); long i=0; for(map::const_iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) { os << FormatString("Re(F)_"+pos->first->GetName(),14) << FormatString("Im(F)_"+pos->first->GetName(),14); cout<first->GetName()<<":"<first->GetForwardScatteringFactor(RAD_XRAY)<first]; sf[2*i] *= mvScatteringFactor[pos->first]; sf[2*i] *= mvTemperatureFactor[pos->first]; sf[2*i+1] = mvImagGeomSF[pos->first]; sf[2*i+1] *= mvScatteringFactor[pos->first]; sf[2*i+1] *= mvTemperatureFactor[pos->first]; v.push_back(&(sf[2*i])); v.push_back(&(sf[2*i+1])); //v.push_back(mvRealGeomSF[pos->first]); //v.push_back(mvImagGeomSF[pos->first]); //v.push_back(mvScatteringFactor[pos->first]); i++; } os<(v,12,4,mNbReflUsed); VFN_DEBUG_EXIT("ScatteringData::PrintFhklCalcDetail()",5) } void ScatteringData::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { if(mUseFastLessPreciseFunc!=allowApproximations) { mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=allowApproximations; this->RefinableObj::BeginOptimization(allowApproximations,enableRestraints); } void ScatteringData::EndOptimization() { if(mOptimizationDepth==1) { if(mUseFastLessPreciseFunc==true) { mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=false; } this->RefinableObj::EndOptimization(); } void ScatteringData::SetApproximationFlag(const bool allow) { if(mUseFastLessPreciseFunc!=allow) { mClockGeomStructFact.Reset(); mClockStructFactor.Reset(); mClockMaster.Click(); } mUseFastLessPreciseFunc=allow; this->RefinableObj::SetApproximationFlag(allow); } void ScatteringData::PrepareHKLarrays() { VFN_DEBUG_ENTRY("ScatteringData::PrepareHKLarrays()"<GetSpaceGroup().GetClockSpaceGroup()0) && (abs(mFhklObsSq.numElements()-mNbRefl)<(0.1*mNbRefl)) && (noSpgChange) ) mFhklObsSq.resizeAndPreserve(mNbRefl); else mFhklObsSq.resize(0); mClockFhklObsSq.Click(); mNbReflUsed=mNbRefl; mExpectedIntensityFactor.resize(mNbRefl); for(long i=0;iGetSpaceGroup().GetExpectedIntensityFactor(mH(i),mK(i),mL(i)); } /* { mpCrystal->GetSpaceGroup().Print(); for(long i=0;iIsBeingRefined()) return mNbReflUsed; VFN_DEBUG_MESSAGE("ScatteringData::GetNbReflBelowMaxSinThetaOvLambda()",4) this->CalcSinThetaLambda(); if((mNbReflUsed>0)&&(mNbReflUsedmMaxSinThetaOvLambda) &&(mSinThetaLambda(mNbReflUsed-1)<=mMaxSinThetaOvLambda)) return mNbReflUsed; } if((mNbReflUsed==mNbRefl)&&(mSinThetaLambda(mNbRefl-1)<=mMaxSinThetaOvLambda)) return mNbReflUsed; long i; for(i=0;imMaxSinThetaOvLambda) break; if(i!=mNbReflUsed) { mNbReflUsed=i; mClockNbReflUsed.Click(); VFN_DEBUG_MESSAGE("->Changed Max sin(theta)/lambda="<CalcSinThetaLambda(); CrystVector_long sortedSubs; sortedSubs=SortSubs(mSinThetaLambda); CrystVector_long oldH,oldK,oldL,oldMult; oldH=mH; oldK=mK; oldL=mL; oldMult=mMultiplicity; long subs; long shift=0; //get rid of [0,0,0] reflection VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 1",2) if(0==mSinThetaLambda(sortedSubs(0))) { shift=1; mNbRefl -= 1; mH.resize(mNbRefl); mK.resize(mNbRefl); mL.resize(mNbRefl); mMultiplicity.resize(mNbRefl); } VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 2",2) for(long i=0;iPrepareHKLarrays(); this->CalcSinThetaLambda(); VFN_DEBUG_MESSAGE("ScatteringData::SortReflectionBySinThetaOverLambda() 4",2) if(0PrepareHKLarrays(); } VFN_DEBUG_EXIT("ScatteringData::SortReflectionBySinThetaOverLambda():"<GetCrystal().GetSpaceGroup().IsReflSystematicAbsent(mH(j),mK(j),mL(j))==false ) subscriptKeptRefl(nbKeptRefl++)=j; } VFN_DEBUG_MESSAGE("ScatteringData::EliminateExtinctReflections():4",5) //Keep only the elected reflections mNbRefl=nbKeptRefl; { CrystVector_long oldH,oldK,oldL; CrystVector_int oldMulti; long subs; oldH=mH; oldK=mK; oldL=mL; oldMulti=mMultiplicity; mMultiplicity.resize(mNbRefl); mH.resize(mNbRefl); mK.resize(mNbRefl); mL.resize(mNbRefl); for(long i=0;iPrepareHKLarrays(); VFN_DEBUG_EXIT("ScatteringData::EliminateExtinctReflections():End",7) return subscriptKeptRefl; } void ScatteringData::CalcSinThetaLambda()const { if(mClockTheta>mClockMaster) return; if( 0 == mpCrystal) throw ObjCrystException("ScatteringData::CalcSinThetaLambda() \ Cannot compute sin(theta)/lambda : there is no crystal affected to this \ ScatteringData object yet."); if( 0 == this->GetNbRefl()) throw ObjCrystException("ScatteringData::CalcSinThetaLambda() \ Cannot compute sin(theta)/lambda : there are no reflections !"); if( (mClockTheta>this->GetRadiation().GetClockWavelength()) &&(mClockTheta>mClockHKL) &&(mClockTheta>mpCrystal->GetClockLatticePar()) &&(mClockTheta>mpCrystal->GetSpaceGroup().GetClockSpaceGroup())) return; VFN_DEBUG_ENTRY("ScatteringData::CalcSinThetaLambda()",3) TAU_PROFILE("ScatteringData::CalcSinThetaLambda()","void (bool)",TAU_DEFAULT); mSinThetaLambda.resize(mNbRefl); const CrystMatrix_REAL bMatrix= this->GetBMatrix(); mX.resize(this->GetNbRefl()); mY.resize(this->GetNbRefl()); mZ.resize(this->GetNbRefl()); for(int i=0;iGetNbRefl();i++) { //:TODO: faster,nicer mX(i)=bMatrix(0,0)*mH(i)+bMatrix(0,1)*mK(i)+bMatrix(0,2)*mL(i); mY(i)=bMatrix(1,0)*mH(i)+bMatrix(1,1)*mK(i)+bMatrix(1,2)*mL(i); mZ(i)=bMatrix(2,0)*mH(i)+bMatrix(2,1)*mK(i)+bMatrix(2,2)*mL(i); } //cout << bMatrix << endl << xyz<GetNbRefl());i++) mSinThetaLambda(i)=sqrt(pow(mX(i),2)+pow(mY(i),2)+pow(mZ(i),2))/2; #if 0 // Direct calculation from a,b,c,alpha,beta,gamma const REAL a=mpCrystal->GetLatticePar(0); const REAL b=mpCrystal->GetLatticePar(1); const REAL c=mpCrystal->GetLatticePar(2); const REAL ca=cos(mpCrystal->GetLatticePar(3)); const REAL sa=sin(mpCrystal->GetLatticePar(3)); const REAL cb=cos(mpCrystal->GetLatticePar(4)); const REAL sb=sin(mpCrystal->GetLatticePar(4)); const REAL cg=cos(mpCrystal->GetLatticePar(5)); const REAL sg=sin(mpCrystal->GetLatticePar(5)); for(int i=0;i< (this->GetNbRefl());i++) { const REAL h=mH(i),k=mK(i),l=mL(i); mSinThetaLambda(i)=0.5*sqrt((h*h/(a*a)*sa*sa+k*k/(b*b)*sb*sb+l*l/(c*c)*sg*sg+2*k*l/(b*c)*(cb*cg-ca)+2*l*h/(c*a)*(cg*ca-cb)+2*h*k/(a*b)*(ca*cb-cg))/(1-ca*ca-cb*cb-cg*cg+2*ca*cb*cg)); } #endif if(this->GetRadiation().GetWavelengthType()!=WAVELENGTH_TOF) { if(this->GetRadiation().GetWavelength()(0) > 0) { mTheta.resize(mNbRefl); for(int i=0;i< (this->GetNbRefl());i++) { if( (mSinThetaLambda(i)*this->GetRadiation().GetWavelength()(0))>1) { //:KLUDGE: :TODO: mTheta(i)=M_PI; /* ofstream out("log.txt"); out << "Error when computing Sin(theta) :" << "i="<GetRadiation().GetWavelength()(0)=" << this->GetRadiation().GetWavelength()(0) << " ,H="<GetBMatrix(); const REAL x=bMatrix(0,0)*h+bMatrix(0,1)*k+bMatrix(0,2)*l; const REAL y=bMatrix(1,0)*h+bMatrix(1,1)*k+bMatrix(1,2)*l; const REAL z=bMatrix(2,0)*h+bMatrix(2,1)*k+bMatrix(2,2)*l; return sqrt(x*x+y*y+z*z)/2; } const CrystMatrix_REAL& ScatteringData::GetBMatrix() const { return this->GetCrystal().GetBMatrix(); } void ScatteringData::CalcScattFactor()const { //if(mClockScattFactor>mClockMaster) return; if( (mClockScattFactor>this->GetRadiation().GetClockWavelength()) &&(mClockScattFactor>mClockHKL) &&(mClockScattFactor>mClockTheta) &&(mClockScattFactor>mpCrystal->GetClockLatticePar()) &&(mClockThermicFact>mpCrystal->GetMasterClockScatteringPower())) return; TAU_PROFILE("ScatteringData::CalcScattFactor()","void (bool)",TAU_DEFAULT); VFN_DEBUG_ENTRY("ScatteringData::CalcScattFactor()",4) this->CalcResonantScattFactor(); mvScatteringFactor.clear(); for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); mvScatteringFactor[pScattPow]=pScattPow->GetScatteringFactor(*this); //Directly add Fprime mvScatteringFactor[pScattPow]+= this->mvFprime[pScattPow]; VFN_DEBUG_MESSAGE("-> H K L sin(t/l) f0+f'" <(mH,mK,mL,mSinThetaLambda, mvScatteringFactor[pScattPow],10,4,mNbReflUsed),1); } mClockScattFactor.Click(); VFN_DEBUG_EXIT("ScatteringData::CalcScattFactor()",4) } void ScatteringData::CalcTemperatureFactor()const { //if(mClockThermicFact>mClockMaster) return; if( (mClockThermicFact>this->GetRadiation().GetClockWavelength()) &&(mClockThermicFact>mClockHKL) &&(mClockThermicFact>mClockTheta) &&(mClockThermicFact>mpCrystal->GetClockLatticePar()) &&(mClockThermicFact>mpCrystal->GetMasterClockScatteringPower())) return; TAU_PROFILE("ScatteringData::CalcTemperatureFactor()","void (bool)",TAU_DEFAULT); VFN_DEBUG_ENTRY("ScatteringData::CalcTemperatureFactor()",4) mvTemperatureFactor.clear(); for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); mvTemperatureFactor[pScattPow]=pScattPow->GetTemperatureFactor(*this); VFN_DEBUG_MESSAGE("-> H K L sin(t/l) DebyeWaller"<(mH,mK,mL,mSinThetaLambda, mvTemperatureFactor[pScattPow],10,4,mNbReflUsed),1); } mClockThermicFact.Click(); VFN_DEBUG_EXIT("ScatteringData::CalcTemperatureFactor()",4) } void ScatteringData::CalcResonantScattFactor()const { if( (mClockScattFactorResonant>mpCrystal->GetMasterClockScatteringPower()) &&(mClockScattFactorResonant>this->GetRadiation().GetClockWavelength())) return; VFN_DEBUG_ENTRY("ScatteringData::CalcResonantScattFactor()",4) TAU_PROFILE("ScatteringData::CalcResonantScattFactor()","void (bool)",TAU_DEFAULT); mvFprime.clear(); mvFsecond.clear(); if(this->GetRadiation().GetWavelength()(0) == 0) { VFN_DEBUG_EXIT("ScatteringData::CalcResonantScattFactor()->Lambda=0. fprime=fsecond=0",4) return; } else { for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { const ScatteringPower *pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); mvFprime [pScattPow]=pScattPow->GetResonantScattFactReal(*this)(0); mvFsecond[pScattPow]=pScattPow->GetResonantScattFactImag(*this)(0); } } mClockScattFactorResonant.Click(); VFN_DEBUG_EXIT("ScatteringData::CalcResonantScattFactor()",4) } void ScatteringData::CalcGlobalTemperatureFactor() const { this->GetNbReflBelowMaxSinThetaOvLambda();//update mNbReflUsed, also recalc sin(theta)/lambda if(mClockGlobalTemperatureFact>mClockMaster) return; if( (mClockGlobalBisoGetSinThetaOverLambda().data(); REAL *fact=mGlobalTemperatureFactor.data(); for(long i=0;iGetNbReflBelowMaxSinThetaOvLambda();//check mNbReflUsed, also recalc sin(theta)/lambda if(mClockStructFactor>mClockMaster) return; //:TODO: Anisotropic Thermic factors //TAU_PROFILE_TIMER(timer1,"ScatteringData::CalcStructFactor1:Prepare","", TAU_FIELD); //TAU_PROFILE_TIMER(timer2,"ScatteringData::CalcStructFactor2:GeomStructFact","", TAU_FIELD); //TAU_PROFILE_TIMER(timer3,"ScatteringData::CalcStructFactor3:Scatt.Factors","", TAU_FIELD); //TAU_PROFILE_TIMER(timer4,"ScatteringData::CalcStructFactor4:Finish,DynCorr","", TAU_FIELD); //TAU_PROFILE_START(timer1); const long nbRefl=this->GetNbRefl(); this->CalcSinThetaLambda(); //TAU_PROFILE_STOP(timer1); //TAU_PROFILE_START(timer2); this->CalcGeomStructFactor(); //TAU_PROFILE_STOP(timer2); //TAU_PROFILE_START(timer3); this->CalcScattFactor(); this->CalcResonantScattFactor(); this->CalcTemperatureFactor(); this->CalcGlobalTemperatureFactor(); this->CalcLuzzatiFactor(); this->CalcStructFactVariance(); //TAU_PROFILE_STOP(timer3); //OK, really must recompute SFs? VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():Fhkl Recalc ?"<mClockGlobalTemperatureFact) &&(mClockStructFactor>mClockGeomStructFact) &&(mClockStructFactor>mClockScattFactorResonant) &&(mClockStructFactor>mClockThermicFact) &&(mClockStructFactor>mClockFhklCalcVariance) &&(mClockStructFactor>mClockLuzzatiFactor)) return; VFN_DEBUG_ENTRY("ScatteringData::CalcStructFactor()",3) TAU_PROFILE("ScatteringData::CalcStructFactor()","void ()",TAU_DEFAULT); //TAU_PROFILE_START(timer4); //reset Fcalc mFhklCalcReal.resize(nbRefl); mFhklCalcImag.resize(nbRefl); mFhklCalcReal=0; mFhklCalcImag=0; //Add all contributions for(map::const_iterator pos=mvRealGeomSF.begin(); pos!=mvRealGeomSF.end();++pos) { const ScatteringPower* pScattPow=pos->first; VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():Fhkl Recalc, "<GetName(),2) const REAL * RESTRICT pGeomR=mvRealGeomSF[pScattPow].data(); const REAL * RESTRICT pGeomI=mvImagGeomSF[pScattPow].data(); const REAL * RESTRICT pScatt=mvScatteringFactor[pScattPow].data(); const REAL * RESTRICT pTemp=mvTemperatureFactor[pScattPow].data(); REAL * RESTRICT pReal=mFhklCalcReal.data(); REAL * RESTRICT pImag=mFhklCalcImag.data(); VFN_DEBUG_MESSAGE("->mvRealGeomSF[i] " <mvImagGeomSF[i] " <mvScatteringFactor[i]" <mvTemperatureFactor[i]" <mFhklCalcReal "<mFhklCalcImag "< H K L sin(t/l) Re(F) Im(F) scatt Temp->"<GetName(),1) VFN_DEBUG_MESSAGE(FormatVertVectorHKLFloats(mH,mK,mL,mSinThetaLambda, mvRealGeomSF[pScattPow], mvImagGeomSF[pScattPow], mvScatteringFactor[pScattPow], mvTemperatureFactor[pScattPow],10,4,mNbReflUsed ),1); if(mvLuzzatiFactor[pScattPow].numElements()>0) {// using maximum likelihood const REAL* RESTRICT pLuzzati=mvLuzzatiFactor[pScattPow].data(); if(false==mIgnoreImagScattFact) { const REAL fsecond=mvFsecond[pScattPow]; VFN_DEBUG_MESSAGE("->fsecond= "<0;j--) { VFN_DEBUG_MESSAGE("-->"<0;j--) { *pReal++ += *pGeomR++ * *pTemp * *pScatt * *pLuzzati; *pImag++ += *pGeomI++ * *pTemp++ * *pScatt++ * *pLuzzati++; } } VFN_DEBUG_MESSAGE("ScatteringData::CalcStructFactor():"<fsecond= "<0;j--) { *pReal += (*pGeomR * *pScatt - *pGeomI * fsecond)* *pTemp; *pImag += (*pGeomI * *pScatt + *pGeomR * fsecond)* *pTemp; VFN_DEBUG_MESSAGE("-->"<0;j--) { *pReal++ += *pGeomR++ * *pTemp * *pScatt; *pImag++ += *pGeomI++ * *pTemp++ * *pScatt++; } } VFN_DEBUG_MESSAGE(FormatVertVectorHKLFloats(mH,mK,mL,mSinThetaLambda, mvRealGeomSF[pScattPow], mvImagGeomSF[pScattPow], mvScatteringFactor[pScattPow], mvTemperatureFactor[pScattPow], mFhklCalcReal, mFhklCalcImag,10,4,mNbReflUsed ),2); } } //TAU_PROFILE_STOP(timer4); { //this->CalcGlobalTemperatureFactor(); if(mGlobalTemperatureFactor.numElements()>0) {//else for some reason it's useless REAL *pReal=mFhklCalcReal.data(); REAL *pImag=mFhklCalcImag.data(); const REAL *pTemp=mGlobalTemperatureFactor.data(); for(long j=0;j &vPar) { TAU_PROFILE("ScatteringData::CalcStructFactor_FullDeriv()","void ()",TAU_DEFAULT); this->GetNbReflBelowMaxSinThetaOvLambda(); this->CalcSinThetaLambda(); this->CalcGeomStructFactor_FullDeriv(vPar); this->CalcStructFactor();//called after CalcGeomStructFactor_FullDeriv, so that CalcGeomStructFactor is not redone mFhklCalcReal_FullDeriv.clear();//:TODO: avoid full clear mFhklCalcImag_FullDeriv.clear(); mFhklCalcReal_FullDeriv[0]=mFhklCalcReal; mFhklCalcImag_FullDeriv[0]=mFhklCalcImag; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { if(*par==0) continue; if((*par)->GetType()->IsDescendantFromOrSameAs(gpRefParTypeScatt)==false) {//:TODO: allow derivatives from other parameters (ML, temperature factors, etc..) // No derivatives -> empty vectors mFhklCalcReal_FullDeriv[*par].resize(0); mFhklCalcImag_FullDeriv[*par].resize(0); continue; } for(map::const_iterator pos=mvRealGeomSF.begin(); pos!=mvRealGeomSF.end();++pos) { const ScatteringPower* pScattPow=pos->first; if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0) { continue;//null derivative, so the array was empty } if(mFhklCalcReal_FullDeriv[*par].size()==0) { mFhklCalcReal_FullDeriv[*par].resize(mNbRefl); mFhklCalcImag_FullDeriv[*par].resize(mNbRefl); mFhklCalcReal_FullDeriv[*par]=0; mFhklCalcImag_FullDeriv[*par]=0; } const REAL * RESTRICT pGeomRd=mvRealGeomSF_FullDeriv[*par][pScattPow].data(); const REAL * RESTRICT pGeomId=mvImagGeomSF_FullDeriv[*par][pScattPow].data(); const REAL * RESTRICT pScatt=mvScatteringFactor[pScattPow].data(); const REAL * RESTRICT pTemp=mvTemperatureFactor[pScattPow].data(); REAL * RESTRICT pReal=mFhklCalcReal_FullDeriv[*par].data(); REAL * RESTRICT pImag=mFhklCalcImag_FullDeriv[*par].data(); if(mvLuzzatiFactor[pScattPow].numElements()>0) {// using maximum likelihood const REAL* RESTRICT pLuzzati=mvLuzzatiFactor[pScattPow].data(); if(false==mIgnoreImagScattFact) { const REAL fsecond=mvFsecond[pScattPow]; for(long j=mNbReflUsed;j>0;j--) { *pReal++ += (*pGeomRd * *pScatt - *pGeomId * fsecond)* *pTemp * *pLuzzati; *pImag++ += (*pGeomId++ * *pScatt++ + *pGeomRd++ * fsecond)* *pTemp++ * *pLuzzati++; } } else { for(long j=mNbReflUsed;j>0;j--) { *pReal++ += *pGeomRd++ * *pTemp * *pScatt * *pLuzzati; *pImag++ += *pGeomId++ * *pTemp++ * *pScatt++ * *pLuzzati++; } } } else { if(false==mIgnoreImagScattFact) { const REAL fsecond=mvFsecond[pScattPow]; for(long j=mNbReflUsed;j>0;j--) { *pReal += (*pGeomRd * *pScatt - *pGeomId * fsecond)* *pTemp; *pImag += (*pGeomId * *pScatt + *pGeomRd * fsecond)* *pTemp; pGeomRd++;pGeomId++;pTemp++;pScatt++;pReal++;pImag++; } } else { for(long j=mNbReflUsed;j>0;j--) { *pReal++ += *pGeomRd++ * *pTemp * *pScatt; *pImag++ += *pGeomId++ * *pTemp++ * *pScatt++; } } } } //TAU_PROFILE_STOP(timer4); { //this->CalcGlobalTemperatureFactor(); if( (mGlobalTemperatureFactor.numElements()>0) &&(mFhklCalcReal_FullDeriv[*par].size()>0) &&(mFhklCalcImag_FullDeriv[*par].size()>0)) {//else for some reason it's useless REAL * RESTRICT pReal=mFhklCalcReal_FullDeriv[*par].data(); REAL * RESTRICT pImag=mFhklCalcImag_FullDeriv[*par].data(); const REAL *pTemp=mGlobalTemperatureFactor.data(); for(long j=0;j v; v.push_back(&mH); v.push_back(&mK); v.push_back(&mL); std::map oldDerivR,oldDerivI; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); this->CalcStructFactor(); oldDerivR[*par]=mFhklCalcReal; oldDerivI[*par]=mFhklCalcImag; (*par)->Mutate(-2*step); this->CalcStructFactor(); oldDerivR[*par]-=mFhklCalcReal; oldDerivR[*par]/=2*step; oldDerivI[*par]-=mFhklCalcImag; oldDerivI[*par]/=2*step; (*par)->Mutate(step); v.push_back(&(mFhklCalcReal_FullDeriv[*par])); v.push_back(&(oldDerivR[*par])); v.push_back(&(mFhklCalcImag_FullDeriv[*par])); v.push_back(&(oldDerivI[*par])); if(v.size()>14) break; } cout<<"############################ Fhkl Deriv Real, Imag ##############################" <(v,14,4,20) <<"############################ END Fhkl Deriv Real, Imag ##############################"<GetCrystal().GetScatteringComponentList()); if( (mClockGeomStructFact>mpCrystal->GetClockScattCompList()) &&(mClockGeomStructFact>mClockHKL) &&(mClockGeomStructFact>mClockNbReflUsed) &&(mClockGeomStructFact>mpCrystal->GetMasterClockScatteringPower())) return; TAU_PROFILE("ScatteringData::GeomStructFactor()","void (Vx,Vy,Vz,data,M,M,bool)",TAU_DEFAULT); VFN_DEBUG_ENTRY("ScatteringData::GeomStructFactor(Vx,Vy,Vz,...)",3) VFN_DEBUG_MESSAGE("-->Using fast functions:"<Number of translation vectors:" <GetCrystal().GetSpaceGroup().GetNbTranslationVectors()-1,2) VFN_DEBUG_MESSAGE("-->Has an inversion Center:" <GetCrystal().GetSpaceGroup().HasInversionCenter(),2) VFN_DEBUG_MESSAGE("-->Number of symetry operations (w/o transl&inv cent.):"\ <GetCrystal().GetSpaceGroup().GetNbSymmetrics(true,true),2) VFN_DEBUG_MESSAGE("-->Number of Scattering Components :" <GetCrystal().GetScatteringComponentList().GetNbComponent(),2) VFN_DEBUG_MESSAGE("-->Number of reflections:" <GetNbRefl()<<" (actually used:"<Number of GeomStructFactor calculations so far:"<IsCentrosymmetric())return; // (*mfpImagGeomStructFactor)(x,y,z,data.H2Pi(),data.K2Pi(),data.L2Pi(),isf); // return; //} //else { const SpaceGroup *pSpg=&(this->GetCrystal().GetSpaceGroup()); const int nbSymmetrics=pSpg->GetNbSymmetrics(true,true); const int nbTranslationVectors=pSpg->GetNbTranslationVectors(); const long nbComp=pScattCompList->GetNbComponent(); const std::vector *pTransVect=&(pSpg->GetTranslationVectors()); CrystMatrix_REAL allCoords(nbSymmetrics,3); CrystVector_REAL tmpVect(mNbReflUsed); #ifndef HAVE_SSE_MATHFUN const int nbRefl=this->GetNbRefl(); CrystVector_long intVect(nbRefl);//not used if mUseFastLessPreciseFunc==false #endif // which scattering powers are actually used ? map vUsed; // Add existing previously used scattering power to the test; for(map::const_iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) vUsed[pos->first]=false;// this will be changed to true later if they are actually used for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) {// Here we make sure scattering power that only contribute ghost atoms are taken into account const ScatteringPower*pow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); if(pow->GetMaximumLikelihoodNbGhostAtom()>0) vUsed[pow]=true; else vUsed[pow]=false; } for(long i=0;i::const_iterator pos=vUsed.begin();pos!=vUsed.end();++pos) { if(pos->second) {// this will create the entry if it does not already exist mvRealGeomSF[pos->first].resize(mNbReflUsed); mvImagGeomSF[pos->first].resize(mNbReflUsed); mvRealGeomSF[pos->first]=0; mvImagGeomSF[pos->first]=0; } else {// erase entries that are not useful any more (e.g. ScatteringPower that were // used but are not any more). map::iterator poubelle=mvRealGeomSF.find(pos->first); if(poubelle!=mvRealGeomSF.end()) mvRealGeomSF.erase(poubelle); poubelle=mvImagGeomSF.find(pos->first); if(poubelle!=mvImagGeomSF.end()) mvImagGeomSF.erase(poubelle); } } REAL centrMult=1.0; if(true==pSpg->HasInversionCenter()) centrMult=2.0; for(long i=0;iGetAllSymmetrics(x,y,z,true,true); if((true==pSpg->HasInversionCenter()) && (false==pSpg->IsInversionCenterAtOrigin())) { const REAL STBF=2.*pSpg->GetCCTbxSpg().inv_t().den(); for(int j=0;jGetCCTbxSpg().inv_t()[0])/STBF; allCoords(j,1) -= ((REAL)pSpg->GetCCTbxSpg().inv_t()[1])/STBF; allCoords(j,2) -= ((REAL)pSpg->GetCCTbxSpg().inv_t()[2])/STBF; } } for(int j=0;j0;jj--) *tmpInt++ = (*intH++ * intX + *intK++ * intY + *intL++ *intZ) &sLibCrystNbTabulSineMASK; if(false==pSpg->HasInversionCenter()) { tmpInt=intVect.data(); for(int jj=mNbReflUsed;jj>0;jj--) { const REAL *pTmp=&spLibCrystTabulCosineSine[*tmpInt++ <<1]; *rrsf++ += popu * *pTmp++; *iisf++ += popu * *pTmp; } } else { tmpInt=intVect.data(); for(int jj=mNbReflUsed;jj>0;jj--) *rrsf++ += popu * spLibCrystTabulCosine[*tmpInt++]; } } else #endif { const REAL x=allCoords(j,0); const REAL y=allCoords(j,1); const REAL z=allCoords(j,2); const REAL *hh=mH2Pi.data(); const REAL *kk=mK2Pi.data(); const REAL *ll=mL2Pi.data(); #ifdef HAVE_SSE_MATHFUN #if 0 // This not much faster and is incorrect (does not take into account sign of h k l) //cout<<__FILE__<<":"<<__LINE__<<":"<HasInversionCenter()) {// Slow ? REAL *rsf=mvRealGeomSF[pScattPow].data(); REAL *isf=mvImagGeomSF[pScattPow].data(); const long *h=mIntH.data(); const long *k=mIntK.data(); const long *l=mIntL.data(); int jj; const v4sf v4popu=_mm_set1_ps(popu); for(jj=mNbReflUsed;jj>3;jj-=4) { //cout<<__FILE__<<":"<<__LINE__<<":"<0;jj--) { const float ch=pcnxyz0[*h *4]; const float sh=psnxyz0[*h++ *4]; const float ck=pcnxyz0[*k *4+1]; const float sk=psnxyz0[*k++ *4+1]; const float cl=pcnxyz0[*l *4+2]; const float sl=psnxyz0[*l++ *4+2]; *rsf++ += popu*(ch*(ck*cl-sk*sl)-sh*(sk*cl+ck*sl)); *isf++ += popu*(sh*(ck*cl-sk*sl)+ch*(sk*cl+ck*sl)); } } else { REAL *rsf=mvRealGeomSF[pScattPow].data(); const long *h=mIntH.data(); const long *k=mIntK.data(); const long *l=mIntL.data(); int jj; const v4sf v4popu=_mm_set1_ps(popu); for(jj=mNbReflUsed;jj>3;jj-=4) { //cout<<__FILE__<<":"<<__LINE__<<":"<0;jj--) { const float ch=pcnxyz0[*h *4]; const float sh=psnxyz0[*h++ *4]; const float ck=pcnxyz0[*k *4+1]; const float sk=psnxyz0[*k++ *4+1]; const float cl=pcnxyz0[*l *4+2]; const float sl=psnxyz0[*l++ *4+2]; *rsf++ += popu*(ch*(ck*cl-sk*sl)-sh*(sk*cl+ck*sl)); } } #else const v4sf v4x=_mm_load1_ps(&x); const v4sf v4y=_mm_load1_ps(&y); const v4sf v4z=_mm_load1_ps(&z); const v4sf v4popu=_mm_load1_ps(&popu);// Can't multiply directly a vector by a scalar ? if(false==pSpg->HasInversionCenter()) { REAL *rsf=mvRealGeomSF[pScattPow].data(); REAL *isf=mvImagGeomSF[pScattPow].data(); int jj=mNbReflUsed; for(;jj>3;jj-=4) { v4sf v4sin,v4cos; // sincos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z, // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z, // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z, // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z),&v4sin,&v4cos); sincos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(hh),v4x), _mm_mul_ps(_mm_loadu_ps(kk),v4y) ), _mm_mul_ps(_mm_loadu_ps(ll),v4z) ),&v4sin,&v4cos);// A bit faster _mm_storeu_ps(rsf,_mm_add_ps(_mm_mul_ps(v4cos,v4popu),_mm_loadu_ps(rsf))); _mm_storeu_ps(isf,_mm_add_ps(_mm_mul_ps(v4sin,v4popu),_mm_loadu_ps(isf))); hh+=4;kk+=4;ll+=4;rsf+=4;isf+=4; } for(;jj>0;jj--) { const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z; *rsf++ += popu * cos(tmp); *isf++ += popu * sin(tmp); } } else { REAL *rsf=mvRealGeomSF[pScattPow].data(); int jj=mNbReflUsed; for(;jj>3;jj-=4) { // const v4sf v4cos=cos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z, // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z, // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z, // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z)); const v4sf v4cos=cos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(hh),v4x), _mm_mul_ps(_mm_loadu_ps(kk),v4y) ), _mm_mul_ps(_mm_loadu_ps(ll),v4z))); _mm_storeu_ps(rsf,_mm_add_ps(_mm_loadu_ps(rsf),_mm_mul_ps(v4cos,v4popu))); hh+=4;kk+=4;ll+=4;rsf+=4; } for(;jj>0;jj--) { const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z; *rsf++ += popu * cos(tmp); } } #endif #else REAL *tmp=tmpVect.data(); for(int jj=0;jjHasInversionCenter()) { sf=mvImagGeomSF[pScattPow].data(); tmp=tmpVect.data(); for(int jj=0;jj 1) { tmpVect=1; if( (pSpg->GetSpaceGroupNumber()>= 143) && (pSpg->GetSpaceGroupNumber()<= 167)) {//Special case for trigonal groups R3,... REAL * RESTRICT p1=tmpVect.data(); const REAL * RESTRICT hh=mH2Pi.data(); const REAL * RESTRICT kk=mK2Pi.data(); const REAL * RESTRICT ll=mL2Pi.data(); for(long j=mNbReflUsed;j>0;j--) *p1++ += 2*cos((*hh++ - *kk++ - *ll++)/3.); } else { for(int j=1;j0;j--) *p1++ += cos(*hh++ *x + *kk++ *y + *ll++ *z ); } } for(map::iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) pos->second *= tmpVect; if(false==pSpg->HasInversionCenter()) for(map::iterator pos=mvImagGeomSF.begin();pos!=mvImagGeomSF.end();++pos) pos->second *= tmpVect; } if(true==pSpg->HasInversionCenter()) { // we already multiplied real geom struct factor by 2 if(false==pSpg->IsInversionCenterAtOrigin()) { VFN_DEBUG_MESSAGE("ScatteringData::GeomStructFactor(Vx,Vy,Vz):\ Inversion Center not at the origin...",2) //fix the phase of each reflection when the inversion center is not //at the origin, using : // Re(F) = RSF*cos(2pi(h*Xc+k*Yc+l*Zc)) // Re(F) = RSF*sin(2pi(h*Xc+k*Yc+l*Zc)) //cout << "Glop Glop"<GetCCTbxSpg().inv_t().den(); { const REAL xc=((REAL)pSpg->GetCCTbxSpg().inv_t()[0])/STBF; const REAL yc=((REAL)pSpg->GetCCTbxSpg().inv_t()[1])/STBF; const REAL zc=((REAL)pSpg->GetCCTbxSpg().inv_t()[2])/STBF; #ifdef __LIBCRYST_VECTOR_USE_BLITZ__ tmpVect = mH2Pi() * xc + mK2PI() * yc + mL2PI() * zc; #else { const REAL * RESTRICT hh=mH2Pi.data(); const REAL * RESTRICT kk=mK2Pi.data(); const REAL * RESTRICT ll=mL2Pi.data(); REAL * RESTRICT ttmpVect=tmpVect.data(); for(long ii=mNbReflUsed;ii>0;ii--) *ttmpVect++ = *hh++ * xc + *kk++ * yc + *ll++ * zc; } #endif } CrystVector_REAL cosTmpVect; CrystVector_REAL sinTmpVect; cosTmpVect=cos(tmpVect); sinTmpVect=sin(tmpVect); map::iterator posi=mvImagGeomSF.begin(); map::iterator posr=mvRealGeomSF.begin(); for(;posi!=mvImagGeomSF.end();) { posi->second = posr->second; posi->second *= sinTmpVect; posr->second *= cosTmpVect; posi++;posr++; } } } } //cout << FormatVertVector(*mvRealGeomSF,*mvImagGeomSF)< &vPar) { TAU_PROFILE("ScatteringData::CalcGeomStructFactor_FullDeriv()","void (..)",TAU_DEFAULT); TAU_PROFILE_TIMER(timer1,"ScatteringData::CalcGeomStructFactor_FullDeriv:1-ScattCompList deriv","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"ScatteringData::CalcGeomStructFactor_FullDeriv:2-Geom SF","", TAU_FIELD); this->CalcGeomStructFactor();//:TODO: avoid calling CalcGeomStructFactor() //:TODO: this->GetCrystal().GetScatteringComponentList_FullDeriv() const ScatteringComponentList *pScattCompList =&(this->GetCrystal().GetScatteringComponentList()); const SpaceGroup *pSpg=&(this->GetCrystal().GetSpaceGroup()); const int nbSymmetrics=pSpg->GetNbSymmetrics(true,true); const int nbTranslationVectors=pSpg->GetNbTranslationVectors(); const unsigned long nbComp=pScattCompList->GetNbComponent(); const std::vector *pTransVect=&(pSpg->GetTranslationVectors()); CrystMatrix_REAL allCoords(nbSymmetrics,3); const bool hasinv=pSpg->HasInversionCenter(); TAU_PROFILE_START(timer1); // Calculate derivatives of the scattering component list vs all parameters std::map vdx,vdy,vdz,vdocc; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) {// :TODO: get this done in Crystal or Scatterers, and use analytical derivatives if(*par==0) continue; CrystVector_REAL *pdx =&(vdx[*par]); CrystVector_REAL *pdy =&(vdy[*par]); CrystVector_REAL *pdz =&(vdz[*par]); CrystVector_REAL *pdocc=&(vdocc[*par]); pdx->resize(nbComp); pdy->resize(nbComp); pdz->resize(nbComp); pdocc->resize(nbComp); const REAL p0=(*par)->GetValue(); const REAL step=(*par)->GetDerivStep(); (*par)->Mutate(step); pScattCompList=&(this->GetCrystal().GetScatteringComponentList()); REAL *ppdx =pdx->data(); REAL *ppdy =pdy->data(); REAL *ppdz =pdz->data(); REAL *ppdocc=pdocc->data(); for(unsigned long i=0;iMutate(-2*step); pScattCompList=&(this->GetCrystal().GetScatteringComponentList()); ppdx =pdx->data(); ppdy =pdy->data(); ppdz =pdz->data(); ppdocc=pdocc->data(); for(unsigned long i=0;iSetValue(p0); if( (MaxAbs(vdx[*par])==0)&&(MaxAbs(vdy[*par])==0)&&(MaxAbs(vdz[*par])==0)&&(MaxAbs(vdocc[*par])==0)) { pdx->resize(0); pdy->resize(0); pdz->resize(0); pdocc->resize(0); } } TAU_PROFILE_STOP(timer1); TAU_PROFILE_START(timer2); CrystVector_REAL transMult(mNbReflUsed); if(!hasinv) transMult=1; else transMult=2; if(nbTranslationVectors > 1) { if( (pSpg->GetSpaceGroupNumber()>= 143) && (pSpg->GetSpaceGroupNumber()<= 167)) {//Special case for trigonal groups R3,... REAL * RESTRICT p1=transMult.data(); const REAL * RESTRICT hh=mH2Pi.data(); const REAL * RESTRICT kk=mK2Pi.data(); const REAL * RESTRICT ll=mL2Pi.data(); for(long j=mNbReflUsed;j>0;j--) *p1++ += 2*cos((*hh++ - *kk++ - *ll++)/3.); } else { for(int j=1;j0;j--) *p1++ += cos(*hh++ *x + *kk++ *y + *ll++ *z ); } } } pScattCompList=&(this->GetCrystal().GetScatteringComponentList()); mvRealGeomSF_FullDeriv.clear();//:TODO: avoid clearing memory as much as possible mvImagGeomSF_FullDeriv.clear(); CrystVector_REAL c(mNbReflUsed),s(mNbReflUsed); CrystMatrix_REAL allCoordsDeriv(nbSymmetrics,3); for(unsigned long i=0;iGetAllSymmetrics(x0,y0,z0,true,true); for(int j=0;j3;jj-=4) { v4sf v4sin,v4cos; // sincos_ps(_mm_setr_ps(*(hh )*x+ *(kk )*y + *(ll )*z, // *(hh+1)*x+ *(kk+1)*y + *(ll+1)*z, // *(hh+2)*x+ *(kk+2)*y + *(ll+2)*z, // *(hh+3)*x+ *(kk+3)*y + *(ll+3)*z),&v4sin,&v4cos); sincos_ps(_mm_add_ps(_mm_add_ps(_mm_mul_ps(_mm_load_ps(hh),v4x), _mm_mul_ps(_mm_load_ps(kk),v4y) ), _mm_mul_ps(_mm_load_ps(ll),v4z) ),&v4sin,&v4cos); _mm_store_ps(pc,v4cos); _mm_store_ps(ps,v4sin); hh+=4;kk+=4;ll+=4;pc+=4;ps+=4; } for(;jj>0;jj--) { const REAL tmp = *hh++ * x + *kk++ * y + *ll++ *z; *pc++ =cos(tmp); *ps++ =sin(tmp); } #else for(int jj=0;jj::iterator par=vPar.begin();par!=vPar.end();++par) { if((*par)==0) continue; if(vdx[*par].size()==0) continue; REAL dx =vdx[*par](i); REAL dy =vdy[*par](i); REAL dz =vdz[*par](i); const REAL dpopu=vdocc[*par](i); if((abs(dx)+abs(dy)+abs(dz)+abs(dpopu))==0) continue; if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0) { mvRealGeomSF_FullDeriv[*par][pScattPow].resize(mNbRefl); mvRealGeomSF_FullDeriv[*par][pScattPow]=0; } if(mvImagGeomSF_FullDeriv[*par][pScattPow].size()==0) { mvImagGeomSF_FullDeriv[*par][pScattPow].resize(mNbRefl); mvImagGeomSF_FullDeriv[*par][pScattPow]=0; } pSpg->GetSymmetric(j,dx,dy,dz,true,true,true); const REAL *hh=mH2Pi.data(); const REAL *kk=mK2Pi.data(); const REAL *ll=mL2Pi.data(); const REAL *pmult=transMult.data(); REAL *rsf=mvRealGeomSF_FullDeriv[*par][pScattPow].data(); REAL *isf=mvImagGeomSF_FullDeriv[*par][pScattPow].data(); VFN_DEBUG_MESSAGE("ScatteringData::CalcGeomStructFactor_FullDeriv()comp="<GetName()<<":"<HasInversionCenter()) { if(false==pSpg->IsInversionCenterAtOrigin()) { //:TODO: if there is an inversion center not in (0,0,0), apply a constant phase } } TAU_PROFILE_STOP(timer2); #if 0 std::vector v; v.push_back(&mH); v.push_back(&mK); v.push_back(&mL); std::map< std::pair,CrystVector_REAL> mr,mi; mUseFastLessPreciseFunc=false; for(std::set::iterator par=vPar.begin();par!=vPar.end();++par) { for(std::map::iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) { const ScatteringPower *pScattPow=pos->first; cout<<(*par)->GetName()<<","<GetName(); if(mvRealGeomSF_FullDeriv[*par][pScattPow].size()==0) { cout<<" => skipped (deriv==0)"<GetDerivStep(); (*par)->Mutate(step); this->CalcGeomStructFactor(); mr[make_pair(pScattPow,*par)]=mvRealGeomSF[pScattPow]; mi[make_pair(pScattPow,*par)]=mvImagGeomSF[pScattPow]; (*par)->Mutate(-2*step); this->CalcGeomStructFactor(); mr[make_pair(pScattPow,*par)]-=mvRealGeomSF[pScattPow]; mr[make_pair(pScattPow,*par)]/=step*2; mi[make_pair(pScattPow,*par)]-=mvImagGeomSF[pScattPow]; mi[make_pair(pScattPow,*par)]/=step*2; (*par)->Mutate(step); v.push_back(&(mvRealGeomSF_FullDeriv[*par][pScattPow])); v.push_back(&(mr[make_pair(pScattPow,*par)])); if(!hasinv) { v.push_back(&(mvImagGeomSF_FullDeriv[*par][pScattPow])); v.push_back(&(mi[make_pair(pScattPow,*par)])); } if(v.size()>20)break; } if(v.size()>20)break; } cout<<"############################ Geom Fhkl Deriv Real, Imag ##############################" <(v,11,4,20) <<"############################ END GeomF hkl Deriv Real, Imag ##############################"<(vdx[*(vPar.begin())],vdy[*(vPar.begin())],vdz[*(vPar.begin())],vdocc[*(vPar.begin())],8,4,20)<::const_iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) { if(pos->first->GetMaximumLikelihoodPositionError()!=0) { useLuzzati=true; break; } } if(!useLuzzati) { mvLuzzatiFactor.clear(); VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): not needed, no positionnal errors",3) return; } bool recalc=false; if( (mClockTheta >mClockLuzzatiFactor) ||(mClockGeomStructFact>mClockLuzzatiFactor)//checks if occupancies changed ||(mClockNbReflUsed>mClockLuzzatiFactor)) { //if(mClockTheta >mClockLuzzatiFactor)cout<<"1"<mClockLuzzatiFactor)cout<<"2"<mClockLuzzatiFactor)cout<<"3"<GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { if(mpCrystal->GetScatteringPowerRegistry().GetObj(i) .GetMaximumLikelihoodParClock()>mClockLuzzatiFactor) { recalc=true; break; } } } if(false==recalc) { VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): no recalc needed",3) return; } TAU_PROFILE("ScatteringData::CalcLuzzatiFactor()","void ()",TAU_DEFAULT); for(int i=mpCrystal->GetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { const ScatteringPower* pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); if(0 == pScattPow->GetMaximumLikelihoodPositionError()) { mvLuzzatiFactor[pScattPow].resize(0); } else { mvLuzzatiFactor[pScattPow].resize(mNbRefl); const REAL b=-(8*M_PI*M_PI)* pScattPow->GetMaximumLikelihoodPositionError() * pScattPow->GetMaximumLikelihoodPositionError(); const REAL *stol=this->GetSinThetaOverLambda().data(); REAL *fact=mvLuzzatiFactor[pScattPow].data(); for(long j=0;jGetName()<(mH,mK,mL,mSinThetaLambda, mvRealGeomSF[pScattPow],mvImagGeomSF[pScattPow], mvScatteringFactor[pScattPow],mvLuzzatiFactor[pScattPow],10,4,mNbReflUsed ),2); } } mClockLuzzatiFactor.Click(); VFN_DEBUG_EXIT("ScatteringData::CalcLuzzatiFactor(): no recalc needed",3) } void ScatteringData::CalcStructFactVariance()const { // this is called by CalcStructFactor(), after the calculation of the structure factors, // and the recomputation of Luzzati factors has already been asked // So we only recompute if these clocks have changed. // // The Crystal::mMasterClockScatteringPower will tell the last time the number of ghost // atoms has been changed in any of the scattpow. if( (mClockFhklCalcVariance>mClockLuzzatiFactor) &&(mClockFhklCalcVariance>mClockStructFactor) &&(mClockFhklCalcVariance>mpCrystal->GetMasterClockScatteringPower())) return; bool hasGhostAtoms=false; for(map::const_iterator pos=mvRealGeomSF.begin();pos!=mvRealGeomSF.end();++pos) { if(pos->first->GetMaximumLikelihoodNbGhostAtom()!=0) { hasGhostAtoms=true; break; } } if( (0==mvLuzzatiFactor.size())&&(!hasGhostAtoms)) { mFhklCalcVariance.resize(0); return; } VFN_DEBUG_ENTRY("ScatteringData::CalcStructFactVariance()",3) TAU_PROFILE("ScatteringData::CalcStructFactVariance()","void ()",TAU_DEFAULT); bool needVar=false; map vComp; { const ScatteringComponentList *pList= & (this->GetCrystal().GetScatteringComponentList()); const long nbComp=pList->GetNbComponent(); const ScatteringComponent *pComp; for(long i=0;impScattPow]=0; } for(long i=0;impScattPow]+= pComp->mOccupancy * pComp->mDynPopCorr; } for(map::iterator pos=vComp.begin();pos!=vComp.end();++pos) pos->second *= this->GetCrystal().GetSpaceGroup().GetNbSymmetrics(); } // Ghost atoms map vGhost; { const long nbScattPow=mpCrystal->GetScatteringPowerRegistry().GetNb(); const long mult=this->GetCrystal().GetSpaceGroup().GetNbSymmetrics(); for(int i=0;iGetScatteringPowerRegistry().GetObj(i)); const REAL nb=pow->GetMaximumLikelihoodNbGhostAtom(); vGhost[pow]=nb*mult; } } if(mFhklCalcVariance.numElements() == mNbRefl) { REAL *pVar=mFhklCalcVariance.data(); for(long j=0;jGetScatteringPowerRegistry().GetNb()-1;i>=0;i--) { const ScatteringPower* pScattPow=&(mpCrystal->GetScatteringPowerRegistry().GetObj(i)); if( (mvLuzzatiFactor[pScattPow].numElements()==0) &&(vGhost[pScattPow]==0)) continue; needVar=true; if(mFhklCalcVariance.numElements() != mNbRefl) { mFhklCalcVariance.resize(mNbRefl); REAL *pVar=mFhklCalcVariance.data(); for(long j=0;j #include //#include //#include //#include //#include //#include namespace ObjCryst { #ifndef HAVE_SSE_MATHFUN //initialize tabulated values of cosine void InitLibCrystTabulCosine(); void DeleteLibCrystTabulCosine(); void InitLibCrystTabulExp(); void DeleteLibCrystTabulExp(); #endif /// Generic type for scattering data extern const RefParType *gpRefParTypeScattData; /// Type for scattering data scale factors extern const RefParType *gpRefParTypeScattDataScale; /// Type for reflection profile extern const RefParType *gpRefParTypeScattDataProfile; /// Type for reflection profiles type (e.g. gaussian/lorentzian mix) extern const RefParType *gpRefParTypeScattDataProfileType; /// Type for reflection profile width extern const RefParType *gpRefParTypeScattDataProfileWidth; /// Type for reflection profile asymmetry extern const RefParType *gpRefParTypeScattDataProfileAsym; /// Generic type for scattering data correction parameter extern const RefParType *gpRefParTypeScattDataCorr; /// Generic type for correction to calculated intensities extern const RefParType *gpRefParTypeScattDataCorrInt; /// Parameter type for preferred orientation direction extern const RefParType *gpRefParTypeScattDataCorrIntPO_Direction; /// Parameter type for fraction of preferred orientation extern const RefParType *gpRefParTypeScattDataCorrIntPO_Fraction; /// Parameter type for the amplitude of preferred orientation extern const RefParType *gpRefParTypeScattDataCorrIntPO_Amplitude; /// Parameter type for the ellipsoid coefficient extern const RefParType *gpRefParTypeScattDataCorrInt_Ellipsoid; /// Parameter type for absorption correction extern const RefParType *gpRefParTypeScattDataCorrIntAbsorp; /// Parameter type for polarization correction extern const RefParType *gpRefParTypeScattDataCorrIntPolar; /// Parameter type for extinction correction extern const RefParType *gpRefParTypeScattDataCorrIntExtinc; /// Parameter type for correction to peak positions extern const RefParType *gpRefParTypeScattDataCorrPos; /// Parameter type for background intensity extern const RefParType *gpRefParTypeScattDataBackground; extern const RefParType *gpRefParTypeRadiation; extern const RefParType *gpRefParTypeRadiationWavelength; class NiftyStaticGlobalObjectsInitializer_ScatteringData { public: NiftyStaticGlobalObjectsInitializer_ScatteringData() { if (mCount++ == 0) { #ifndef HAVE_SSE_MATHFUN InitLibCrystTabulCosine(); InitLibCrystTabulExp(); #endif gpRefParTypeScattData= new RefParType(gpRefParTypeObjCryst,"Scattering Data"); gpRefParTypeScattDataScale= new RefParType(gpRefParTypeObjCryst,"Scale Factor"); gpRefParTypeScattDataProfile= new RefParType(gpRefParTypeScattData,"Profile"); gpRefParTypeScattDataProfileType= new RefParType(gpRefParTypeScattDataProfile,"Type"); gpRefParTypeScattDataProfileWidth= new RefParType(gpRefParTypeScattDataProfile,"Width"); gpRefParTypeScattDataProfileAsym= new RefParType(gpRefParTypeScattDataProfile,"Asymmetry"); gpRefParTypeScattDataCorr= new RefParType(gpRefParTypeScattData,"Correction"); gpRefParTypeScattDataCorrInt= new RefParType(gpRefParTypeScattDataCorr,"Intensities"); gpRefParTypeScattDataCorrIntPO_Direction= new RefParType(gpRefParTypeScattDataCorrIntPO_Direction,"Preferred orientation direction"); gpRefParTypeScattDataCorrIntPO_Fraction= new RefParType(gpRefParTypeScattDataCorrIntPO_Fraction,"Preferred orientation fraction"); gpRefParTypeScattDataCorrIntPO_Amplitude= new RefParType(gpRefParTypeScattDataCorrIntPO_Amplitude,"Preferred orientation amplitude"); gpRefParTypeScattDataCorrInt_Ellipsoid= new RefParType(gpRefParTypeScattDataCorrInt_Ellipsoid,"Preferred orientation ellipsoid"); gpRefParTypeScattDataCorrIntAbsorp= new RefParType(gpRefParTypeScattDataCorrInt,"Absorption"); gpRefParTypeScattDataCorrIntPolar= new RefParType(gpRefParTypeScattDataCorrInt,"Polarization"); gpRefParTypeScattDataCorrIntExtinc= new RefParType(gpRefParTypeScattDataCorrInt,"Extinction"); gpRefParTypeScattDataCorrPos= new RefParType(gpRefParTypeScattDataCorr,"Reflections Positions"); gpRefParTypeScattDataBackground= new RefParType(gpRefParTypeScattData,"Background"); gpRefParTypeRadiation= new RefParType(gpRefParTypeObjCryst,"Radiation"); gpRefParTypeRadiationWavelength= new RefParType(gpRefParTypeRadiation,"Wavelength"); } } ~NiftyStaticGlobalObjectsInitializer_ScatteringData() { if (--mCount == 0) { #ifndef HAVE_SSE_MATHFUN DeleteLibCrystTabulCosine(); DeleteLibCrystTabulExp(); #endif delete gpRefParTypeScattData; delete gpRefParTypeScattDataScale; delete gpRefParTypeScattDataProfile; delete gpRefParTypeScattDataProfileType; delete gpRefParTypeScattDataProfileWidth; delete gpRefParTypeScattDataProfileAsym; delete gpRefParTypeScattDataCorr; delete gpRefParTypeScattDataCorrInt; delete gpRefParTypeScattDataCorrIntAbsorp; delete gpRefParTypeScattDataCorrIntPolar; delete gpRefParTypeScattDataCorrIntExtinc; delete gpRefParTypeScattDataCorrPos; delete gpRefParTypeScattDataBackground; delete gpRefParTypeRadiation; delete gpRefParTypeRadiationWavelength; gpRefParTypeScattData=0; gpRefParTypeScattDataScale=0; gpRefParTypeScattDataProfile=0; gpRefParTypeScattDataProfileType=0; gpRefParTypeScattDataProfileWidth=0; gpRefParTypeScattDataProfileAsym=0; gpRefParTypeScattDataCorr=0; gpRefParTypeScattDataCorrInt=0; gpRefParTypeScattDataCorrIntAbsorp=0; gpRefParTypeScattDataCorrIntPolar=0; gpRefParTypeScattDataCorrIntExtinc=0; gpRefParTypeScattDataCorrPos=0; gpRefParTypeScattDataBackground=0; gpRefParTypeRadiation=0; gpRefParTypeRadiationWavelength=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_ScatteringData NiftyStaticGlobalObjectsInitializer_ScatteringData_counter; //###################################################################### /** \brief Class to define the radiation (type, monochromaticity, wavelength(s)) of an experiment * * This can be developped for more complex experiments, hence the \e vector of * wavelengths (so far it is not possible to use several wavelengths, though). * * X-Rays and Neutrons are available. Electrons are not available yet in * ScatteringData classes. * * \todo also add here information about the polarization of the beam. */ //###################################################################### class Radiation: public RefinableObj { public: /// Default constructor Radiation(); /** \ brief Constructor * * \param rad the RadiationType used (X-Rays, neutrons) * \param wavelength the wavelength (in Angstroems) of the monochromatic * radiation. */ Radiation(const RadiationType rad,const REAL wavelength); /** \ brief Constructor for X-Ray tube radiation * *\param XRayTubeElementName : name of the anticathode element name. Known *ones are Cr, Fe, Cu, Mo, Ag. *\param alpha2Alpha2ratio: Kalpha2/Kalpha1 ratio (0.5 by default) * *the average wavelength is calculated *using the alpha2/alpha1 weight. All structure factors computation are made *using the average wavelength, and for powder diffraction, profiles are output *at the alpha1 and alpha2 ratio for the calculated pattern. * *NOTE : if the name of the wavelength is generic (eg"Cu"), *then the program considers that *there are both Alpha1 and Alpha2, and thus automatically changes the WavelengthType *to WAVELENGTH_ALPHA12. If instead either alpha1 or alpha2 (eg "CuA1") is asked for, *the WavelengthType is set to WAVELENGTH_MONOCHROMATIC. In both cases, * the radiation type is set to X-Ray. */ Radiation(const string &XRayTubeElementName,const REAL alpha2Alpha2ratio=0.5); /// Copy constructor Radiation(const Radiation&); ~Radiation(); virtual const string& GetClassName() const; void operator=(const Radiation&); /// Get the radiation type (X-Rays, Neutron) RadiationType GetRadiationType()const; /// Set the radiation type (X-Rays, Neutron) void SetRadiationType(const RadiationType); /// Set the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...) void SetWavelengthType(const WavelengthType &type); /// Get the Wavelength type (monochromatic, Alpha1+Alpha2, Time Of Flight...) WavelengthType GetWavelengthType()const; /// Get the wavelength(s) in Angstroems. Currently only /// monochromatic is used, so the vector should only return /// only one wavelength. const CrystVector_REAL& GetWavelength()const; /// Set the (monochromatic) wavelength of the beam. void SetWavelength(const REAL ); /** \ brief Set X-Ray tube radiation. * *\param XRayTubeElementName : name of the anticathode element name. Known *ones are Cr, Fe, Cu, Mo, Ag. *\param alpha2Alpha2ratio: Kalpha2/Kalpha1 ratio (0.5 by default) * *the average wavelength is calculated *using the alpha2/alpha1 weight. All structure factors computation are made *using the average wavelength, and for powder diffraction, profiles are output *at the alpha1 and alpha2 ratio for the calculated pattern. * *NOTE : if the name of the wavelength is generic (eg"Cu"), *then the program considers that *there are both Alpha1 and Alpha2, and thus automatically changes the WavelengthType *to WAVELENGTH_ALPHA12. If instead either alpha1 or alpha2 (eg "CuA1") is asked for, *the WavelengthType is set to WAVELENGTH_MONOCHROMATIC. In both cases, * the radiation type is set to X-Ray. */ void SetWavelength(const string &XRayTubeElementName,const REAL alpha2Alpha2ratio=0.5); /// Get the wavelength difference for Alpha1 and Alpha2 REAL GetXRayTubeDeltaLambda()const; /// Get the Kalpha2/Kalpha1 ratio REAL GetXRayTubeAlpha2Alpha1Ratio()const; /// Last time the wavelength has been changed const RefinableObjClock& GetClockWavelength()const ; /// Last time the nature (X-Rays/Neutron, number of wavelengths)radiation has been changed const RefinableObjClock& GetClockRadiation()const ; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); /// Print to screen/console the charcteristics of the radiation. void Print()const; REAL GetLinearPolarRate()const; void SetLinearPolarRate(const REAL f); private: void InitOptions(); /// Neutron ? X-Ray ? (Electron: unimplemented) RefObjOpt mRadiationType; /// monochromatic ? Alpha1 & Alpha2 ? Multi-Wavelength ? RefObjOpt mWavelengthType; ///Wavelength of the Experiment, in Angstroems. CrystVector_REAL mWavelength; ///Name of the X-Ray tube used, if relevant. ie "Cu", "Fe",etc... /// "CuA1" for Cu-alpha1, etc... string mXRayTubeName; ///Absolute difference between alpha1 and alpha2, in angstroems REAL mXRayTubeDeltaLambda; ///Ratio alpha2/alpha1 (should be 0.5) REAL mXRayTubeAlpha2Alpha1Ratio; //Clocks RefinableObjClock mClockWavelength; RefinableObjClock mClockRadiation; /// Linear Polarization Rate (default:0, X-Ray tube unmonochromatized) REAL mLinearPolarRate; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXRadiation; #endif }; //###################################################################### /** \brief Class to compute structure factors for a set of reflections and a Crystal. * * This class only computes structure factor, but no intensity. i.e. it does * not include any correction such as absorption, Lorentz or Polarization. * * Does this really need to be a RefinableObj ? * \todo Optimize computation for Bijvoet/Friedel mates. To do this, generate * an internal list of 'true independent reflections', with two entries for each, * for both mates, and make the 'real' reflections only a reference to these reflections. * * \todo a \b lot of cleaning is necessary in the computing of structure * factors, for (1) the 'preparation' part (deciding what needs to be recomputed) * and (2) to allow anisotropic temperature factors (or other anisotropic parts) */ //###################################################################### class ScatteringData: virtual public RefinableObj { public: ScatteringData(); ScatteringData(const ScatteringData &old); ~ScatteringData(); /// So-called virtual copy constructor virtual ScatteringData* CreateCopy()const=0; /** \brief input H,K,L * * \param h,k,l: REAL arrays (vectors with NbRefl elements -same size), *with the h, k and l coordinates of all reflections. */ virtual void SetHKL( const CrystVector_REAL &h, const CrystVector_REAL &k, const CrystVector_REAL &l); /** \brief Generate a list of h,k,l to describe a full reciprocal space, * up to a given maximum theta value * * \param maxTheta:maximum theta value * \param unique: if set to true, only unique reflections will be listed. * Bijvoet (Friedel) pairs * are NOT merged, for 'anomalous' reasons, unless you have chosen to ignore the * imaginary part of the scattering factor. * * The multiplicity is always stored in ScatteringData::mMultiplicity. * * \warning The ScatteringData object must already have been assigned * a crystal object using SetCrystal(), and the experimental wavelength * must also have been set before calling this function. */ virtual void GenHKLFullSpace2(const REAL maxsithsl, const bool unique=false); /** \brief Generate a list of h,k,l to describe a full reciprocal space, * up to a given maximum theta value * * \param maxsithsl:maximum sin(theta)/lambda=1/2d value * \param unique: if set to true, only unique reflections will be listed. * Bijvoet (Friedel) pairs * are NOT merged, for 'anomalous' reasons, unless you have chosen to ignore the * imaginary part of the scattering factor. * * The multiplicity is always stored in ScatteringData::mMultiplicity. * * \warning The ScatteringData object must already have been assigned * a crystal object using SetCrystal(), and the experimental wavelength * must also have been set before calling this function. * * \deprecated Rather use PowderPattern::GenHKLFullSpace2, * with a maximum sin(theta)/lambda value, which also works for dispersive experiments. */ virtual void GenHKLFullSpace(const REAL maxTheta, const bool unique=false); ///Neutron or x-ray experiment ? Wavelength ? RadiationType GetRadiationType()const; /// Get the radiation object for this data virtual const Radiation& GetRadiation()const=0; /**Set the crystal for this experiment * */ virtual void SetCrystal(Crystal &crystal); /// Const access to the data's crystal const Crystal& GetCrystal()const ; /// Access to the data's crystal Crystal& GetCrystal() ; /// Has a Crystal structure associated yet ? bool HasCrystal()const; ///Return the number of reflections in this experiment. long GetNbRefl() const; ///Return the 1D array of H coordinates for all reflections const CrystVector_REAL& GetH() const; ///Return the 1D array of K coordinates for all reflections const CrystVector_REAL& GetK() const; ///Return the 1D array of L coordinates for all reflections const CrystVector_REAL& GetL() const; /// Return the 1D array of H coordinates for all reflections, multiplied by 2*pi /// \internal Should be private const CrystVector_REAL& GetH2Pi() const; ///Return the 1D array of K coordinates for all reflections, multiplied by 2*pi /// \internal Should be private const CrystVector_REAL& GetK2Pi() const; ///Return the 1D array of L coordinates for all reflections, multiplied by 2*pi /// \internal Should be private const CrystVector_REAL& GetL2Pi() const; ///Return the 1D array of orthonormal x coordinates for all reflections (recipr. space) const CrystVector_REAL& GetReflX() const; ///Return the 1D array of orthonormal y coordinates for all reflections (recipr. space) const CrystVector_REAL& GetReflY() const; ///Return the 1D array of orthonormal z coordinates for all reflections (recipr. space) const CrystVector_REAL& GetReflZ() const; /// Return an array with \f$ \frac{sin(\theta)}{\lambda} = \frac{1}{2d_{hkl}}\f$ ///for all reflections const CrystVector_REAL& GetSinThetaOverLambda()const; /// Return an array with theta values for all reflections const CrystVector_REAL& GetTheta()const; /// Clock the last time the sin(theta)/lambda and theta arrays were re-computed const RefinableObjClock& GetClockTheta()const; /// Returns the Array of calculated |F(hkl)|^2 for all reflections. const CrystVector_REAL& GetFhklCalcSq() const; std::map & GetFhklCalcSq_FullDeriv(std::set &vPar); /// Access to real part of F(hkl)calc const CrystVector_REAL& GetFhklCalcReal() const; /// Access to imaginary part of F(hkl)calc const CrystVector_REAL& GetFhklCalcImag() const; /// Returns the vector of observed |F(hkl)|^2 for all reflections. const CrystVector_REAL& GetFhklObsSq() const; /// Set the vector of observed |F(hkl)|^2 for all reflections. The supplied vector must have the same size /// as the mH, mK, mL vectors. void SetFhklObsSq(const CrystVector_REAL &obs); /// Scattering factors for each ScatteringPower, as vectors with NbRefl elements const map &GetScatteringFactor() const; ///wavelength of the experiment (in Angstroems) CrystVector_REAL GetWavelength()const; /// If true, then the imaginary part of the scattering factor is ignored during /// Structure factor computation. (default value=false) /// /// \todo this should become useless once we take fully advantage of coupled /// computation of Structure Factors for Fridel/Bijvoet mates using an internal /// list of 'fully unique' reflections. Then only one of the mates need to be computed.. void SetIsIgnoringImagScattFact(const bool b); /// If true, then the imaginary part of the scattering factor is ignored during /// Structure factor computation. bool IsIgnoringImagScattFact() const; // Set an option so that only low-amgle reflections (theta < angle) // are used. See DiffractionData::mUseOnlyLowAngleData //virtual void SetUseOnlyLowAngleData(const bool useOnlyLowAngle,const REAL angle)=0; /** \brief Print H, K, L F^2 Re(F) Im(F) theta sin(theta)/lambda for all reflections * */ virtual void PrintFhklCalc(ostream &os=cout)const; /** \brief Print H, K, L sin(theta)/lambda theta F^2 Re(F) Im(F) [Re(F) Im(F)]_i, * where [Re(F) Im(F)]_i are the real and imaginary contribution of the different * scattering powers to the overall structure factor */ virtual void PrintFhklCalcDetail(ostream &os=cout)const; virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); virtual void EndOptimization(); virtual void SetApproximationFlag(const bool allow); /// Set the maximum value for sin(theta)/lambda. All data (reflections,..) still /// exist but are ignored for all calculations. virtual void SetMaxSinThetaOvLambda(const REAL max); /// Get the maximum value for sin(theta)/lambda. REAL GetMaxSinThetaOvLambda()const; /// Recalc, and get the number of reflections which should be actually used, /// due to the maximuml sin(theta)/lambda value set. virtual long GetNbReflBelowMaxSinThetaOvLambda()const; /// Clock the last time the number of reflections used was changed const RefinableObjClock& GetClockNbReflBelowMaxSinThetaOvLambda()const; protected: /// \internal This function is called after H,K and L arrays have /// been initialized or modified. virtual void PrepareHKLarrays() ; /// \internal sort reflections by theta values (also get rid of [0,0,0] if present) /// If maxSTOL >0, then only reflections where sin(theta)/lambda &vPar); /** \brief Compute the 'Geometrical Structure Factor' for each ScatteringPower * of the Crystal * */ void CalcGeomStructFactor() const; void CalcGeomStructFactor_FullDeriv(std::set &vPar); /** Calculate the Luzzati factor associated to each ScatteringPower and * each reflection, for maximum likelihood optimization. * */ void CalcLuzzatiFactor()const; /** Calculate the variance associated to the calculated structure factor * */ void CalcStructFactVariance()const; /// Number of H,K,L reflections long mNbRefl; /// H,K,L coordinates CrystVector_REAL mH, mK, mL ; /// H,K,L integer coordinates mutable CrystVector_long mIntH, mIntK, mIntL ; /// H,K,L coordinates, multiplied by 2PI mutable CrystVector_REAL mH2Pi, mK2Pi, mL2Pi ; /// reflection coordinates in an orthonormal base mutable CrystVector_REAL mX, mY, mZ ; ///Multiplicity for each reflections (mostly for powder diffraction) CrystVector_int mMultiplicity ; /** Expected intensity factor for all reflections. * * See SpaceGroup::GetExpectedIntensityFactor() */ CrystVector_int mExpectedIntensityFactor; /// real &imaginary parts of F(HKL)calc mutable CrystVector_REAL mFhklCalcReal, mFhklCalcImag ; mutable std::map mFhklCalcReal_FullDeriv, mFhklCalcImag_FullDeriv ; /// F(HKL)^2 calc for each reflection mutable CrystVector_REAL mFhklCalcSq ; mutable std::map mFhklCalcSq_FullDeriv; /** Pointer to the crystal corresponding to this experiment. * * This gives an access to the UB matrix for the crystal, * as well as to the list of Scatterer. */ Crystal *mpCrystal; /** Global Biso, affecting the overall structure factor for all * reflections (but not the structure factors of individual atoms or * type of atomes). * */ REAL mGlobalBiso; /// Global Biso factor mutable CrystVector_REAL mGlobalTemperatureFactor; ///Use faster, but less precise, approximations for functions? (integer ///approximations to compute sin and cos in structure factors, and also ///to compute interatomic distances). /// This is activated by global optimization algortithms, only during the /// optimization. bool mUseFastLessPreciseFunc; //The Following members are only kept to avoid useless re-computation //during global refinements. They are used \b only by CalcStructFactor() /// \f$ \frac{sin(\theta)}{\lambda} = \frac{1}{2d_{hkl}}\f$ ///for the crystal and the reflections in ReciprSpace mutable CrystVector_REAL mSinThetaLambda; /// theta for the crystal and the HKL in ReciprSpace (in radians) mutable CrystVector_REAL mTheta; /// Anomalous X-Ray scattering term f' and f" are stored here for each ScatteringPower /// We store here only a value. For multi-wavelength support this should be changed /// to a vector... or to a matrix to take into account anisotropy of anomalous /// scattering... mutable map mvFprime,mvFsecond; /// Thermic factors for each ScatteringPower, as vectors with NbRefl elements mutable map mvTemperatureFactor; /// Scattering factors for each ScatteringPower, as vectors with NbRefl elements mutable map mvScatteringFactor; /// Geometrical Structure factor for each ScatteringPower, as vectors with NbRefl elements mutable map mvRealGeomSF,mvImagGeomSF; mutable map > mvRealGeomSF_FullDeriv,mvImagGeomSF_FullDeriv; //Public Clocks /// Clock for the list of hkl RefinableObjClock mClockHKL; /// Clock for the structure factor mutable RefinableObjClock mClockStructFactor; /// Clock for the square modulus of the structure factor mutable RefinableObjClock mClockStructFactorSq; //Internal Clocks /// Clock the last time theta was computed mutable RefinableObjClock mClockTheta; /// Clock the last time scattering factors were computed mutable RefinableObjClock mClockScattFactor; /// Clock the last time resonant scattering factors were computed mutable RefinableObjClock mClockScattFactorResonant; /// Clock the last time the geometrical structure factors were computed mutable RefinableObjClock mClockGeomStructFact; /// Clock the last time temperature factors were computed mutable RefinableObjClock mClockThermicFact; /// last time the global Biso factor was modified RefinableObjClock mClockGlobalBiso; /// last time the global temperature factor was computed mutable RefinableObjClock mClockGlobalTemperatureFact; /** \brief Ignore imaginary part of scattering factor. * * This can be used either to speed up computation, or when f" * has a small effect on calculated intensities, mostly for powder * diffraction (GenHKLFullSpace will not generate Friedel pairs, reducing * the number of reflections by a factor up to 2 for some structures). * * Practically this makes f"=0 during computation. The real resonant contribution (f') * is not affected. * * This may be removed later on... */ bool mIgnoreImagScattFact; // Maximum sin(theta)/lambda /** Maximum sin(theta)/lambda for all calculations (10 by default). * * This keeps all data in memory, but only the part which is below * the max is calculated. * * This affects the computing of structure factors, intensities (for single * crystal and powder patterns), R and Rw. * * The reflections \b must be sorted by increasing sin(theta)/lambda for * this to work correctly. */ REAL mMaxSinThetaOvLambda; /// Number of reflections which are below the max. This is updated automatically /// from ScatteringData::mMaxSinThetaOvLambda mutable long mNbReflUsed; /// Clock recording the last time the number of reflections used has increased. mutable RefinableObjClock mClockNbReflUsed; // Maximum Likelihood /// The Luzzati 'D' factor for each scattering power and each reflection mutable map mvLuzzatiFactor; /** The variance on all calculated structure factors, taking into account * the positionnal errors and the expected intensity factor. * * Actually this is the variance on both real and imaginary parts. */ mutable CrystVector_REAL mFhklCalcVariance; mutable RefinableObjClock mClockLuzzatiFactor; mutable RefinableObjClock mClockFhklCalcVariance; /// Observed squared structure factors (zero-sized if none) CrystVector_REAL mFhklObsSq; /// Last time observed squared structure factors were altered RefinableObjClock mClockFhklObsSq; #ifdef __WX__CRYST__ //to access mMaxSinThetaOvLambda friend class WXDiffractionSingleCrystal; friend class WXPowderPattern; #endif }; }//namespace ObjCryst #endif // _OBJCRYST_SCATTERINGDATA_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringPower.cpp000066400000000000000000001000231417150057700246640ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include //for sprintf() #include "cctbx/eltbx/xray_scattering.h" #include "cctbx/eltbx/tiny_pse.h" #include "cctbx/eltbx/icsd_radii.h" #include "cctbx/eltbx/covalent_radii.h" #include "cctbx/eltbx/henke.h" #include "cctbx/eltbx/neutron.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/ObjCryst/Colours.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxScatteringPower.h" #endif namespace ObjCryst { const RefParType *gpRefParTypeScattPow=0; const RefParType *gpRefParTypeScattPowResonant=0; const RefParType *gpRefParTypeScattPowTemperature=0; const RefParType *gpRefParTypeScattPowTemperatureIso=0; const RefParType *gpRefParTypeScattPowTemperatureAniso=0; long NiftyStaticGlobalObjectsInitializer_ScatteringPower::mCount=0; //###################################################################### // // Bij to Betaij conversion // //###################################################################### CrystMatrix_REAL Bij2Betaij(const CrystVector_REAL &Bij, const UnitCell &cell) { // Willis & Pryor,p 101: (betaij) = 2*pi^2 * transpose(cell.Bmatrix) * (Bij) * cell.Bmatrix // :TODO: this needs to be checked before being used const REAL B11=Bij(0); const REAL B22=Bij(1); const REAL B33=Bij(2); const REAL B12=Bij(3); const REAL B13=Bij(4); const REAL B23=Bij(5); CrystMatrix_REAL B(3,3); B(0,0)=B11; B(0,1)=B12; B(0,1)=B13; B(1,0)=B12; B(1,1)=B22; B(1,1)=B23; B(2,0)=B13; B(2,1)=B23; B(2,1)=B33; CrystMatrix_REAL b(3,3); b=cell.GetBMatrix().transpose().Mult(B.Mult(cell.GetBMatrix())); b*=2*M_PI*M_PI; return b; } //###################################################################### // // SCATTERING POWER // //###################################################################### ObjRegistry gScatteringPowerRegistry("Global ScatteringPower Registry"); ScatteringPower::ScatteringPower():mDynPopCorrIndex(0),mBiso(1.0),mIsIsotropic(true), mMaximumLikelihoodNbGhost(0),mFormalCharge(0.0) { VFN_DEBUG_MESSAGE("ScatteringPower::ScatteringPower():"<Init(); mClockMaster.AddChild(mClock); mClockMaster.AddChild(mMaximumLikelihoodParClock); } ScatteringPower::ScatteringPower(const ScatteringPower& old): mDynPopCorrIndex(old.mDynPopCorrIndex),mBiso(old.mBiso),mIsIsotropic(old.mIsIsotropic), mBeta(old.mBeta),mB(old.mB), mFormalCharge(old.mFormalCharge) { VFN_DEBUG_MESSAGE("ScatteringPower::ScatteringPower(&old):"<Init(); mMaximumLikelihoodPositionError=old.mMaximumLikelihoodPositionError; mMaximumLikelihoodNbGhost=old.mMaximumLikelihoodNbGhost; mClockMaster.AddChild(mClock); mClockMaster.AddChild(mMaximumLikelihoodParClock); } ScatteringPower::~ScatteringPower() { VFN_DEBUG_MESSAGE("ScatteringPower::~ScatteringPower():"<GetBij(i) != rhs.GetBij(i)) return false; if(this->GetClassName() != rhs.GetClassName()) return false; if(this->GetSymbol() != rhs.GetSymbol()) return false; return true; } bool ScatteringPower::operator!=(const ScatteringPower& rhs) const { return !(*this == rhs); } bool ScatteringPower::IsScatteringFactorAnisotropic()const{return false;} bool ScatteringPower::IsTemperatureFactorAnisotropic()const{return false;} bool ScatteringPower::IsResonantScatteringAnisotropic()const{return false;} const string& ScatteringPower::GetSymbol() const {return this->GetName();} REAL ScatteringPower::GetBiso() const {return mBiso;} REAL& ScatteringPower::GetBiso() {mClock.Click();return mBiso;} void ScatteringPower::SetBiso(const REAL newB) { mClock.Click();mBiso=newB;mIsIsotropic=true;} REAL ScatteringPower::GetBij(const size_t &i, const size_t &j) const { size_t idx = 0; if(i == j) { idx = i - 1; } else { idx = i + j; } return this->GetBij(idx); } REAL ScatteringPower::GetBij(const size_t &idx) const { return mB(idx); } void ScatteringPower::SetBij(const size_t &i, const size_t &j, const REAL newB) { size_t idx = 0; if(i == j) { idx = i - 1; } else { idx = i + j; } this->SetBij(idx, newB); } void ScatteringPower::SetBij(const size_t &idx, const REAL newB) { mClock.Click(); mIsIsotropic=false; mB(idx) = newB; } bool ScatteringPower::IsIsotropic() const {return mIsIsotropic;} long ScatteringPower::GetDynPopCorrIndex() const {return mDynPopCorrIndex;} long ScatteringPower::GetNbScatteringPower()const {return gScatteringPowerRegistry.GetNb();} const RefinableObjClock& ScatteringPower::GetLastChangeClock()const {return mClock;} const string& ScatteringPower::GetColourName()const{ return mColourName;} const float* ScatteringPower::GetColourRGB()const{ return mColourRGB;} void ScatteringPower::SetColour(const string& colourName) { mColourName=colourName; this->InitRGBColour(); } void ScatteringPower::SetColour(const float r,const float g,const float b) { mColourRGB[0]=r; mColourRGB[1]=g; mColourRGB[2]=b; } void ScatteringPower::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { // One group for all parameters unsigned int index=0; VFN_DEBUG_MESSAGE("ScatteringPower::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { if(index==0) index=first++; groupIndex(i)=index; } } REAL ScatteringPower::GetMaximumLikelihoodPositionError()const {return mMaximumLikelihoodPositionError;} const RefinableObjClock& ScatteringPower::GetMaximumLikelihoodParClock()const {return mMaximumLikelihoodParClock;} void ScatteringPower::SetMaximumLikelihoodPositionError(const REAL mle) { if(mle!=mMaximumLikelihoodPositionError) { mMaximumLikelihoodPositionError=mle; mMaximumLikelihoodParClock.Click(); } } REAL ScatteringPower::GetMaximumLikelihoodNbGhostAtom()const {return mMaximumLikelihoodNbGhost;} void ScatteringPower::SetMaximumLikelihoodNbGhostAtom(const REAL nb) { if(nb!=mMaximumLikelihoodNbGhost) { mMaximumLikelihoodNbGhost=nb; mMaximumLikelihoodParClock.Click(); } } REAL ScatteringPower::GetFormalCharge()const{return mFormalCharge;} void ScatteringPower::SetFormalCharge(const REAL charge) {mFormalCharge=charge;} void ScatteringPower::Init() { VFN_DEBUG_MESSAGE("ScatteringPower::Init():"<RGBColour:"< gScatteringPowerAtomRegistry("Global ScatteringPowerAtom Registry"); ScatteringPowerAtom::ScatteringPowerAtom(): ScatteringPower(),mSymbol(""),mAtomicNumber(0),mpGaussian(0) { VFN_DEBUG_MESSAGE("ScatteringPowerAtom::ScatteringPowerAtom():"<InitRefParList(); } ScatteringPowerAtom::ScatteringPowerAtom(const string &name, const string &symbol, const REAL bIso): mpGaussian(0) { VFN_DEBUG_MESSAGE("ScatteringPowerAtom::ScatteringPowerAtom(n,s,B):"<InitRefParList(); this->Init(name,symbol,bIso); } ScatteringPowerAtom::ScatteringPowerAtom(const ScatteringPowerAtom& old): mpGaussian(0) { VFN_DEBUG_MESSAGE("ScatteringPowerAtom::ScatteringPowerAtom(&old):"<Init(old.GetName(),old.mSymbol,old.mBiso); //this->InitRefParList(); //?? :TODO: Check } ScatteringPowerAtom::~ScatteringPowerAtom() { VFN_DEBUG_MESSAGE("ScatteringPowerAtom::~ScatteringPowerAtom():"<ScatteringPower::Init(); this->SetName(name); mSymbol=symbol; mBiso=bIso; mIsIsotropic=true; if(mpGaussian!=0) delete mpGaussian; try { cctbx::eltbx::xray_scattering::wk1995 wk95t(mSymbol); mpGaussian=new cctbx::eltbx::xray_scattering::gaussian(wk95t.fetch()); this->InitAtNeutronScattCoeffs(); cctbx::eltbx::tiny_pse::table tpse(mSymbol); mAtomicNumber=tpse.atomic_number(); mAtomicWeight=tpse.weight(); cctbx::eltbx::icsd_radii::table ticsd(mSymbol); mRadius= ticsd.radius(); cctbx::eltbx::covalent_radii::table tcov(mSymbol); mCovalentRadius=tcov.radius(); } catch(exception &err) { cout << "WARNING: could not interpret Symbol name !"<Init(name,"H",bIso); } VFN_DEBUG_MESSAGE("ScatteringPowerAtom::Init():/Name="<GetName() \ <<" /Symbol="<at_stol(*pstol++); } else sf=1.0;//:KLUDGE: Should never happen break; } case(RAD_ELECTRON): { VFN_DEBUG_MESSAGE("ScatteringPower::GetScatteringFactor():ELECTRON:"<GetAtomicNumber(); const long nb=data.GetSinThetaOverLambda().numElements(); const REAL *pstol=data.GetSinThetaOverLambda().data(); for(long i=0;iat_stol(*pstol))/(*pstol * *pstol); pstol++; } } else sf=1.0;//:KLUDGE: Should never happen break; } } VFN_DEBUG_MESSAGE("ScatteringPower::GetScatteringFactor(&data):End",3) return sf; } REAL ScatteringPowerAtom::GetForwardScatteringFactor(const RadiationType type) const { REAL sf = 0; switch(type) { case(RAD_NEUTRON): { sf=mNeutronScattLengthReal; break; } case(RAD_XRAY): { if(mpGaussian!=0) sf=mpGaussian->at_stol(0); else sf=1.0; break; } case(RAD_ELECTRON): { const REAL z=this->GetAtomicNumber(); sf=(z-mpGaussian->at_stol(0.0001))/(.0001 * .0001); } } VFN_DEBUG_MESSAGE("ScatteringPower::GetScatteringFactor(&data):End",3) return sf; } static bool warnADP=true; CrystVector_REAL ScatteringPowerAtom::GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex) const { VFN_DEBUG_MESSAGE("ScatteringPower::GetTemperatureFactor(&data):"<The Debye-Waller calculations will instead use only isotropic DPs"<Init(this->GetName(),symbol,this->GetBiso()); } const string& ScatteringPowerAtom::GetSymbol() const { VFN_DEBUG_MESSAGE("ScatteringPowerAtom::GetSymbol():"<GetName()<<"," << FormatString(this->GetSymbol(),4) << ") :" << FormatFloat(this->GetBiso()); VFN_DEBUG_MESSAGE_SHORT("at "<AddPar(tmp); } { REAL* bdata = (REAL*) mB.data(); RefinablePar B11("B11",&bdata[0],0.1,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B11.SetDerivStep(1e-3); B11.SetGlobalOptimStep(.5); B11.AssignClock(mClock); this->AddPar(B11); RefinablePar B22("B22",&bdata[1],0.1,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B22.SetDerivStep(1e-3); B22.SetGlobalOptimStep(.5); B22.AssignClock(mClock); this->AddPar(B22); RefinablePar B33("B33",&bdata[2],0.1,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B33.SetDerivStep(1e-3); B33.SetGlobalOptimStep(.5); B33.AssignClock(mClock); this->AddPar(B33); RefinablePar B12("B12",&bdata[3],-5,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B12.SetDerivStep(1e-3); B12.SetGlobalOptimStep(.5); B12.AssignClock(mClock); this->AddPar(B12); RefinablePar B13("B13",&bdata[4],-5,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B13.SetDerivStep(1e-3); B13.SetGlobalOptimStep(.5); B13.AssignClock(mClock); this->AddPar(B13); RefinablePar B23("B23",&bdata[5],-5,5., gpRefParTypeScattPowTemperatureAniso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,false,false); B23.SetDerivStep(1e-3); B23.SetGlobalOptimStep(.5); B23.AssignClock(mClock); this->AddPar(B23); } { RefinablePar tmp("ML Error",&mMaximumLikelihoodPositionError,0.,1., gpRefParTypeScattPow,REFPAR_DERIV_STEP_ABSOLUTE, false,true,true,false); tmp.SetDerivStep(1e-4); tmp.SetGlobalOptimStep(.001); tmp.AssignClock(mMaximumLikelihoodParClock); this->AddPar(tmp); } { RefinablePar tmp("ML-Nb Ghost Atoms",&mMaximumLikelihoodNbGhost,0.,10., gpRefParTypeScattPow,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false); tmp.SetDerivStep(1e-3); tmp.SetGlobalOptimStep(.05); tmp.AssignClock(mMaximumLikelihoodParClock); this->AddPar(tmp); } { RefinablePar tmp("Formal Charge",&mFormalCharge,-10.,10., gpRefParTypeScattPow,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false); tmp.SetDerivStep(1e-3); tmp.SetGlobalOptimStep(.05); tmp.AssignClock(mClock); this->AddPar(tmp); } } #ifdef __WX__CRYST__ WXCrystObjBasic* ScatteringPowerAtom::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXScatteringPowerAtom(parent,this); return mpWXCrystObj; } #endif //###################################################################### // // SCATTERING COMPONENT // //###################################################################### ScatteringComponent::ScatteringComponent(): mX(0),mY(0),mZ(0),mOccupancy(0),mpScattPow(0),mDynPopCorr(0) {} bool ScatteringComponent::operator==(const ScatteringComponent& rhs) const { return ((mX==rhs.mX) && (mY==rhs.mY) && (mZ==rhs.mZ) && (mOccupancy==rhs.mOccupancy) && (mpScattPow==rhs.mpScattPow)); } bool ScatteringComponent::operator!=(const ScatteringComponent& rhs) const { return ((mX!=rhs.mX) || (mY!=rhs.mY) || (mZ!=rhs.mZ) || (mOccupancy!=rhs.mOccupancy) || (mpScattPow!=rhs.mpScattPow)); } void ScatteringComponent::Print()const { cout <GetName(); cout<=this->GetNbComponent()) { this->Print(); throw ObjCrystException("ScatteringComponentList::operator()(i)::i>mNbComponent!!"); } if(i<0) throw ObjCrystException("ScatteringComponentList::operator()&(i)::i<0!!"); return mvScattComp[i]; } ScatteringComponent& ScatteringComponentList::operator()(const long i) { VFN_DEBUG_MESSAGE("ScatteringComponentList::operator()&("<=this->GetNbComponent()) { this->Print(); throw ObjCrystException("ScatteringComponentList::operator()&(i)::i>mNbComponent!!"); } if(i<0) throw ObjCrystException("ScatteringComponentList::operator()&(i):: i<0!!"); return mvScattComp[i]; } long ScatteringComponentList::GetNbComponent() const {return mvScattComp.size();} void ScatteringComponentList::operator=(const ScatteringComponentList &rhs) { VFN_DEBUG_MESSAGE("ScatteringComponentList::operator=()",1) mvScattComp=rhs.mvScattComp; VFN_DEBUG_MESSAGE("ScatteringComponentList::operator=():End",0) } bool ScatteringComponentList::operator==(const ScatteringComponentList &rhs)const { if(rhs.GetNbComponent() != this->GetNbComponent()) return false; for(long i=0;iGetNbComponent();i++) if( (*this)(i) != rhs(i) ) return false; return true; } void ScatteringComponentList::operator+=(const ScatteringComponentList &rhs) { for(long i=0;iGetNbComponent()+1); } void ScatteringComponentList::operator--() { VFN_DEBUG_MESSAGE("ScatteringComponentList::operator--()",1) if(this->GetNbComponent()>0) mvScattComp.resize(this->GetNbComponent()-1); } void ScatteringComponentList::Print()const { VFN_DEBUG_ENTRY("ScatteringComponentList::Print()",5) cout<<"Number of Scattering components:"<GetNbComponent()<GetNbComponent();i++) { cout << i<<":"; (*this)(i).Print(); } VFN_DEBUG_EXIT("ScatteringComponentList::Print()",5) } }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringPower.h000066400000000000000000000601451417150057700243430ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _OBJCRYST_SCATTPOWER_H_ #define _OBJCRYST_SCATTPOWER_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/RefinableObj/RefinableObj.h" //#include //#include //#include //#include //#include //#include //#include // forward declaration to avoid including boost headers namespace cctbx { namespace eltbx { namespace xray_scattering {class gaussian;}}} namespace ObjCryst { extern const RefParType *gpRefParTypeScattPow; extern const RefParType *gpRefParTypeScattPowResonant; extern const RefParType *gpRefParTypeScattPowTemperature; extern const RefParType *gpRefParTypeScattPowTemperatureIso; extern const RefParType *gpRefParTypeScattPowTemperatureAniso; class NiftyStaticGlobalObjectsInitializer_ScatteringPower { public: NiftyStaticGlobalObjectsInitializer_ScatteringPower() { if (mCount++ == 0) { gpRefParTypeScattPow=new RefParType(gpRefParTypeObjCryst,"Scattering Power"); gpRefParTypeScattPowResonant=new RefParType(gpRefParTypeScattPow,"Resonant Scatt."); gpRefParTypeScattPowTemperature=new RefParType(gpRefParTypeScattPow,"Temperature"); gpRefParTypeScattPowTemperatureIso=new RefParType(gpRefParTypeScattPowTemperature,"Isotropic"); gpRefParTypeScattPowTemperatureAniso=new RefParType(gpRefParTypeScattPowTemperatureIso,"Anisotropic"); } } ~NiftyStaticGlobalObjectsInitializer_ScatteringPower() { if (--mCount == 0) { delete gpRefParTypeScattPow; delete gpRefParTypeScattPowResonant; delete gpRefParTypeScattPowTemperature; delete gpRefParTypeScattPowTemperatureIso; delete gpRefParTypeScattPowTemperatureAniso; gpRefParTypeScattPow=0; gpRefParTypeScattPowResonant=0; gpRefParTypeScattPowTemperature=0; gpRefParTypeScattPowTemperatureIso=0; gpRefParTypeScattPowTemperatureAniso=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_ScatteringPower NiftyStaticGlobalObjectsInitializer_ScatteringPower_counter; class ScatteringData;//forward declaration :KLUDGE: ? //###################################################################### // // SCATTERING POWER /** \brief Abstract Base Class to describe the scattering power of any * Scatterer component in a crystal. * * This includes: * - the scattering factor, * - the temperature factor * - real and imaginary parts of the resonant * scattering factor. * * The interface is independent of the radiation type. * * This base class is designed to handle both isotropic and anisotropic * versions of scattering, temperature and anomalous factors. * * \todo Anisotropic scattering (temperature factor especially) code, using derived * classes * \todo Clarify organization by removing any 'real' data from the top, abstract * base class (eg remove Biso and Betaij), and by creating derived classes. * Optionnaly 3 classes (used as members of ScatteringPower) could be created, * TemperatureFactor, ScatteringFactor, and ResonantScatteringFactor. In any way * the design of this class should not evolve, so that code using the ScatteringPower * interface will remain compatible whatever modifications are made. * \warning: there is currently a storage for Anisotropic Displacement Parameters, * but Debye-Waller calculation is \e only isotropic. */ //###################################################################### class ScatteringPower:virtual public RefinableObj { public: ScatteringPower(); ScatteringPower(const ScatteringPower& old); virtual ~ScatteringPower(); virtual const string& GetClassName() const; virtual void operator=(const ScatteringPower& rhs); /** Comparison operator. Two scattering powers are equal if they have the same * displacement parameter, correspond to same element, and are of the same class. */ virtual bool operator==(const ScatteringPower& rhs) const; /** Comparison operator. Two scattering powers are equal if they have the same * displacement parameter, correspond to same element, and are of the same class. */ virtual bool operator!=(const ScatteringPower& rhs) const; /** \brief Get the Scattering factor for all reflections of a given * ScatteringData object. * * \return a vector with the scattering factor for all reflections, in the same * order as in the ScatteringData object. This format is independent of the radiation * type (X-Ray, neutron..). * \param data: the ScatteringData object, giving access to all the reflections. * \param spgSymPosIndex: if the ScatteringPower is anisotropic, then the * different symmetrics will not have the same scattering power for all reflections. * This parameter is the index of the symmetric position in the Spacegroup. * If spgSymPosIndex=-1, the isotropic values are returned. * \warning There is no anisotropic code yet, so spgSymPosIndex is simply ignored so far * , but the design of this function is general for any anisotropic scattering. */ virtual CrystVector_REAL GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex=-1) const=0; /// Get the scattering factor at (0,0,0). Used for scatterer (electron, nucleus) /// density generation. virtual REAL GetForwardScatteringFactor(const RadiationType) const=0; /** \brief Get the temperature factor for all reflections of a given * ScatteringData object. * * \return a vector with the temperature factor for all reflections, in the same * order as in the ScatteringData object. * \param data: the ScatteringData object, giving access to all the reflections. * \param spgSymPosIndex: if the ScatteringPower is anisotropic, then the * different symmetrics will not have the same scattering power for all reflections. * This parameter is the index of the symmetric position in the Spacegroup. * If spgSymPosIndex=-1, the isotropic values are returned. * \warning There is no anisotropic code yet, so spgSymPosIndex is simply ignored so far * , but the design of this function is general for any anisotropic scattering. */ virtual CrystVector_REAL GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex=-1) const=0; /** \brief Get the real part of the resonant scattering factor. * * \return a matrix where each row corresponds to each wavelength (currently only * monochromatic experiments are made so there is only one row), and each column * corresponds to each reflection \e only if the scattering term is anisotropic, which * is not the case so far... * \param data: the ScatteringData object, giving access to all the reflections and * a list of wavelengths). * \param spgSymPosIndex: if the ScatteringPower is anisotropic, then the * different symmetrics will not have the same scattering power for all reflections. * This parameter is the index of the symmetric position in the Spacegroup. * If spgSymPosIndex=-1, the isotropic values are returned. * \warning There is no anisotropic code yet, so spgSymPosIndex is simply ignored so far * , but the design of this function is general for any anisotropic scattering. */ virtual CrystMatrix_REAL GetResonantScattFactReal(const ScatteringData &data, const int spgSymPosIndex=-1) const=0; /** \brief Get the imaginary part of the resonant scattering factor. * * \return a matrix where each row corresponds to each wavelength (currently only * monochromatic experiments are made so there is only one row), and each column * corresponds to each reflection \e only if the scattering term is anisotropic, which * is not the case so far... * \param data: the ScatteringData object, giving access to all the reflections, * and a list of wavelengths. * \param spgSymPosIndex: if the ScatteringPower is anisotropic, then the * different symmetrics will not have the same scattering power for all reflections. * This parameter is the index of the symmetric position in the Spacegroup. * If spgSymPosIndex=-1, the isotropic values are returned. * \warning There is no anisotropic code yet, so spgSymPosIndex is simply ignored so far * , but the design of this function is general for any anisotropic scattering. */ virtual CrystMatrix_REAL GetResonantScattFactImag(const ScatteringData &data, const int spgSymPosIndex=-1) const=0; /// Is the scattering factor anisotropic ? virtual bool IsScatteringFactorAnisotropic()const; /// Is the thermic factor anisotropic ? virtual bool IsTemperatureFactorAnisotropic()const; /// Are the resonant scattering terms anisotropic ? virtual bool IsResonantScatteringAnisotropic()const; /** \brief Symbol for this Scattering power (the atom name for atoms) * */ virtual const string& GetSymbol() const; /** \brief Returns the isotropic temperature B factor * */ REAL GetBiso() const; /** \brief Returns the isotropic temperature B factor * */ REAL& GetBiso(); /** \brief Sets the isotropic temperature B factor * */ virtual void SetBiso(const REAL newB); /** \brief Returns the anisotropic temperature B factor for (i, j) pair. * * \warning: this is ambiguous, as it is Beta_ij which are stored, and not Bij... */ REAL GetBij(const size_t &i, const size_t &j) const; /** \brief Returns the anisotropic temperature B factor for given index. * * 0 -> (1, 1) * 1 -> (2, 2) * 2 -> (3, 3) * 3 -> (1, 2) * 4 -> (1, 3) * 5 -> (2, 3) * * \warning: this is ambiguous, as it is Beta_ij which are stored, and not Bij... */ REAL GetBij(const size_t &idx) const; /** \brief Sets the anisotropic temperature B factor for (i, j) pair. * * \warning: this is ambiguous, as it is Beta_ij which are stored, and not Bij... */ virtual void SetBij(const size_t &i, const size_t &j, const REAL newB); /** \brief Sets the anisotropic temperature B factor for given index. * * 0 -> (1, 1) * 1 -> (2, 2) * 2 -> (3, 3) * 3 -> (1, 2) * 4 -> (1, 3) * 5 -> (2, 3) * * \warning: this is ambiguous, as it is Beta_ij which are stored, and not Bij... */ virtual void SetBij(const size_t &idx, const REAL newB); /** \brief Returns true if the scattering power is isotropic, else false. * * */ bool IsIsotropic()const ; /// Get the number identifying this kind of scatterer, used to decide whether two /// scatterers are equivalent, for the dynamical occupancy correction. long GetDynPopCorrIndex()const; /// Total number of ScatteringPower object long GetNbScatteringPower()const; /// ObjCrystClock time when the last modification was made to the object const RefinableObjClock& GetLastChangeClock()const; ///Get the (POV-Ray) name associated to the color (if any) const string& GetColourName()const; /// Get the float[3] array of RGB components defining the colour of this scattering power const float* GetColourRGB()const; /// Set the colour from the associated POV-Ray name void SetColour(const string& colorName); /// Set the colour from RGB components (all between 0 and 1.) void SetColour(const float r,const float g,const float b); /// Return the physical radius of this type of scatterer (for 3D display purposes). /// \warning this may be removed later. virtual REAL GetRadius()const=0; virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; /// Maximum Likelihood: get the estimated error (sigma) on the positions /// for this kind of element. REAL GetMaximumLikelihoodPositionError()const; /// Maximum Likelihood: set the estimated error (sigma) on the positions /// for this kind of element. void SetMaximumLikelihoodPositionError(const REAL mle); /// Maximum Likelihood: get the number of ghost elements per asymmetric unit. REAL GetMaximumLikelihoodNbGhostAtom()const; /// Maximum Likelihood: set the number of ghost elements per asymmetric unit. void SetMaximumLikelihoodNbGhostAtom(const REAL nb); /// Get the clock value for the last change on the maximum likelihood parameters /// (positionnal error, number of ghost atoms). const RefinableObjClock& GetMaximumLikelihoodParClock()const; virtual REAL GetFormalCharge()const; virtual void SetFormalCharge(const REAL charge); protected: virtual void InitRefParList()=0; /// Initialization of the object, used by all constructors, and operator=. virtual void Init(); ///Get RGB Colour coordinates from Colour Name virtual void InitRGBColour(); /// number identifying this kind of scatterer, for the dynamical occupancy correction. /// Right now it is the atomic number. long mDynPopCorrIndex; /// Temperature isotropic B factor. REAL mBiso; /// Is the scattering isotropic ? bool mIsIsotropic; /** Anisotropic Beta(ij) * * \internal * These are stored temporarily, and derived from the Bij */ mutable CrystVector_REAL mBeta; /// Anisotropic B(ij) CrystVector_REAL mB; /// Clock. RefinableObjClock mClock; /// Colour for this ScatteringPower (from POVRay) string mColourName; /// Colour for this ScatteringPower using RGB float mColourRGB[3]; // Maximum Likelihood /// estimated error (sigma) on the positions for this type of element. REAL mMaximumLikelihoodPositionError; /// RefinableObjClock mMaximumLikelihoodParClock; /// Number of ghost atoms in the asymmetric unit. /// These contribute to the variance of the structure factor, but not to the structure /// factor as the uncertainty on their position is infinite. REAL mMaximumLikelihoodNbGhost; /** Formal Charge. This can be used for bond valence analysis, * or energy calculations. * * Default value is 0. */ REAL mFormalCharge; }; /// Global registry for all ScatteringPower objects extern ObjRegistry gScatteringPowerRegistry; //###################################################################### // // SCATTERING POWER ATOM /** \brief The Scattering Power for an Atom * */ //###################################################################### class ScatteringPowerAtom:virtual public ScatteringPower { public: ScatteringPowerAtom(); /** \brief Atom constructor * \param symbol : 'Ti' , 'Ti4+', 'Cl1-' *These symbols \e must correspond to one of the entries of the international tables *for crystallography (1995) giving the analytical approximation for scattering factors. * \param name : name of the atom ('Ta1','Sm2', 'Tungsten_1'...). *The name can have \e any format but spaces should be avoided, since it *will generate problems when reading the names from a file... * \param biso : Isotropic thermic coefficient */ ScatteringPowerAtom(const string &name,const string &symbol,const REAL bIso=1.0); ScatteringPowerAtom(const ScatteringPowerAtom& old); ~ScatteringPowerAtom(); virtual const string& GetClassName() const; /// Re-initialize parameters (after using the default constructor). void Init(const string &name,const string &symbol,const REAL bIso=1.0); virtual CrystVector_REAL GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual REAL GetForwardScatteringFactor(const RadiationType) const; virtual CrystVector_REAL GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactReal(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactImag(const ScatteringData &data, const int spgSymPosIndex=0) const; /// Set the symbol for this atom void SetSymbol(const string &symbol) ; /// Returns the symbol ('Ta', 'O2-',...) of the atom virtual const string& GetSymbol() const; /** \brief Returns the standard name of the element (ie "hydrogen", "tantalum",..). * * Names are extracted form Grosse-Kunstleve 'atominfo' package, *which uses data from the CRC Handbook of Chemistry & Physics, 63rd & 70th editions */ string GetElementName() const; /// Atomic number for this atom int GetAtomicNumber() const; /// Atomic weight (g/mol) for this atom REAL GetAtomicWeight() const; /// Atomic radius for this atom or ion, in Angstroems (ICSD table from cctbx) REAL GetRadius() const; /// Covalent Radius for this atom, in Angstroems (from cctbx) REAL GetCovalentRadius() const; /// Maximum number of covalent bonds (from openbabel element.txt) unsigned int GetMaxCovBonds() const; virtual void Print()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); protected: /** \internal * Fetch the coefficients for analytical approximation of the *atomic scattering factor. */ void InitAtScattCoeffsWK95(); /** \internal * Fetch the coefficients neutron scattering. */ void InitAtNeutronScattCoeffs(); virtual void InitRefParList(); /** \brief Symbol of this atom * *This symbol \e must correspond to one of the entries of the international tables *for crystallography (1995) giving the analytical approximation for scattering factors. */ string mSymbol; /// atomic number (Z) for the atom int mAtomicNumber; /// atomic weight (g/mol) for the atom REAL mAtomicWeight; /** Pointer to cctbx's gaussian describing the thomson x-ray * scattering factor. */ cctbx::eltbx::xray_scattering::gaussian *mpGaussian; /** \brief Neutron Bond Coherent Scattering lengths * *Real and imaginary (for atoms who have an imaginary part) * *Reference : Neutron News, Vol. 3, No. 3, 1992, pp. 29-37. */ REAL mNeutronScattLengthReal,mNeutronScattLengthImag; /// Radius of the atom or ion, in Angstroems (ICSD table from cctbx) REAL mRadius; /// Covalent Radius for this atom, in Angstroems (from cctbx) REAL mCovalentRadius; /// Maximum number of covalent bonds unsigned int mMaxCovBonds; /** \brief Neutron Absorption cross section (barn) * *For 2200 m/s neutrons. * *Reference : Neutron News, Vol. 3, No. 3, 1992, pp. 29-37. */ REAL mNeutronAbsCrossSection; private: // Avoid compiler warnings. Explicitly hide the base-class method. void Init(); #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXScatteringPowerAtom; #endif }; /// Global registry for all ScatteringPowerAtom objects extern ObjRegistry gScatteringPowerAtomRegistry; //###################################################################### // // SCATTERING COMPONENT /** \brief A scattering position in a crystal, associated with the corresponding * occupancy and a pointer to the ScatteringPower. Also given is the * */ //###################################################################### struct ScatteringComponent { // Default Constructor ScatteringComponent(); bool operator==(const ScatteringComponent& rhs)const; bool operator!=(const ScatteringComponent& rhs)const; ///Print one line oabout this component void Print() const; /// Coordinates of scattering positions i the crystal with the corresponding occupancy REAL mX,mY,mZ,mOccupancy; /// The ScatteringPower associated with this position const ScatteringPower *mpScattPow; /// Dynamical Population Correction. /// /// The population of any atom is given by mOccupancy*mDynPopCorr. /// mPopu is the \e real mOccupancy (0<.<1), and should be the only one /// used during a refinement. However during a \e model \e search for the structure, /// atoms may fall unexpectedly in a special position or with an overlap of /// two atoms (the shared oxygen between two polyhedras, for example). In these /// cases it is necessary to dynamically correct the population during the /// generation of structural models. /// See also Crystal::CalcDynPopCorr /// /// \note this parameter is mutable, and is computed by the Crystal object mutable REAL mDynPopCorr; // The scatterer to which this component is associated // Scatterer *mScatterer; }; //###################################################################### // // SCATTERING COMPONENT LIST /** \brief list of scattering positions in a crystal, associated with the corresponding * occupancy and a pointer to the ScatteringPower. * */ //###################################################################### class ScatteringComponentList { public: ScatteringComponentList(); ScatteringComponentList(const long nbComponent); ScatteringComponentList(const ScatteringComponentList &old); ~ScatteringComponentList(); /// Reset the list. This does \b not free the memory, but simply forgets /// that there already are some entries. void Reset(); /// Access to a component const ScatteringComponent& operator()(const long i) const; ScatteringComponent& operator()(const long i); /// Number of components long GetNbComponent() const; /// Assignement operator void operator=(const ScatteringComponentList &rhs); /// Compare two lists. bool operator==(const ScatteringComponentList &rhs)const; /// Add another list of components void operator+=(const ScatteringComponentList &rhs); /// Add component void operator+=(const ScatteringComponent &rhs); /// Add component (the whole list should be updated after that) void operator++(); /// Remove component (the whole list should be updated after that) void operator--(); /// Print the list of Scattering components. For debugging void Print() const; protected: /// The vector of components vector mvScattComp; }; }//namespace #include "ObjCryst/ObjCryst/ScatteringData.h" #endif //_OBJCRYST_SCATTPOWER_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringPowerSphere.cpp000066400000000000000000000215531417150057700260450ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* ScatteringPowerSphere.cpp * source file for the spherical scattering power * */ #include #include #include "ObjCryst/ObjCryst/ScatteringPowerSphere.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxScatteringPowerSphere.h" #endif namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // ScatteringPowerSphere // //////////////////////////////////////////////////////////////////////// ScatteringPowerSphere::ScatteringPowerSphere() { cout<<"Creating scattering power for fullerene"<Init("C60",3.56,1.0); } ScatteringPowerSphere::ScatteringPowerSphere(const string &name, const REAL radius, const REAL bIso) { this->Init(name,radius,bIso); } ScatteringPowerSphere::ScatteringPowerSphere(const ScatteringPowerSphere& old) {} ScatteringPowerSphere::~ScatteringPowerSphere() { } // Disable the base-class function. void ScatteringPowerSphere::Init() { // This should be never called. abort(); } void ScatteringPowerSphere::Init(const string &name, const REAL radius, const REAL bIso) { this->SetName(name); mRadius=radius; mColourRGB[0]=0.2; mColourRGB[1]=0.2; mColourRGB[2]=0.2; if(this->GetNbPar()==0) this->InitRefParList(); } const string& ScatteringPowerSphere::GetClassName() const { const static string className="ScatteringPowerSphere"; return className; } CrystVector_REAL ScatteringPowerSphere::GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex) const { CrystVector_REAL sf; #if 0 // :TODO: Support anisotropic form factor. For the moment use only mAxisLengthX REAL a,b,c; CrystMatrix_REAL phiMatrix(3,3),chiMatrix(3,3),psiMatrix(3,3); phiMatrix= cos(mPhi) , -sin(mPhi) , 0, sin(mPhi) , cos(mPhi) , 0, 0 ,0 ,1; chiMatrix= cos(mChi) ,0 ,-sin(mChi), 0 ,1 ,0, sin(mChi) ,0 ,cos(mChi); psiMatrix= 1 , 0 , 0, 0 ,cos(mPsi) ,-sin(mPsi), 0 ,sin(mPsi) ,cos(mPsi); CrystMatrix_REAL phiChiPsiMatrix=product(chiMatrix,product(phiMatrix,psiMatrix)); a=phiChiPsiMatrix(0,0)*mAxisLengthX+phiChiPsiMatrix(0,1)*mAxisLengthY+phiChiPsiMatrix(0,2)*mAxisLengthZ; b=phiChiPsiMatrix(1,0)*mAxisLengthX+phiChiPsiMatrix(1,1)*mAxisLengthY+phiChiPsiMatrix(1,2)*mAxisLengthZ; c=phiChiPsiMatrix(2,0)*mAxisLengthX+phiChiPsiMatrix(2,1)*mAxisLengthY+phiChiPsiMatrix(2,2)*mAxisLengthZ; const REAL *pX=data.GetReflX().data(); const REAL *pY=data.GetReflY().data(); const REAL *pZ=data.GetReflZ().data(); sf.resize(data.GetNbRefl()); REAL *pSF=sf.data(); for(long i=0;iGetName(),5) for(int i=0;iGetPar(&mRadius).XMLOutput(os,"Radius",0); os<GetPar(&mBiso).XMLOutput(os,"Biso",0); os<GetName(),5) } void ScatteringPowerSphere::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("ScatteringPowerSphere::XMLInput():"<GetName(),5) string symbol; for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("Symbol"==tagg.GetAttributeName(i)) symbol=tagg.GetAttributeValue(i); } this->Init(mName,3.56,1.0); while(true) { XMLCrystTag tag(is); if(("ScatteringPowerSphere"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("ScatteringPowerSphere::Exit():"<GetName(),5) return; } if("RGBColour"==tag.GetName()) { float r,g,b; is>>r>>g>>b; this->SetColour(r,g,b); XMLCrystTag junk(is); } if("Par"==tag.GetName()) { for(unsigned int i=0;iGetPar(&mRadius).XMLInput(is,tag); if("Biso"==tag.GetAttributeValue(i)) this->GetPar(&mBiso).XMLInput(is,tag); break; } } continue; } } } void ScatteringPowerSphere::InitRefParList() { { RefinablePar tmp("Radius",&mRadius,3.,5., gpRefParTypeScattPow,REFPAR_DERIV_STEP_RELATIVE, true,true,true,false); tmp.SetDerivStep(1e-3); tmp.SetGlobalOptimStep(.1); tmp.AssignClock(mClock); this->AddPar(tmp); } { RefinablePar tmp("Biso",&mBiso,0.1,5., gpRefParTypeScattPowTemperatureIso,REFPAR_DERIV_STEP_ABSOLUTE, true,true,true,false); tmp.SetDerivStep(1e-3); tmp.SetGlobalOptimStep(.5); tmp.AssignClock(mClock); this->AddPar(tmp); } } #ifdef __WX__CRYST__ WXCrystObjBasic* ScatteringPowerSphere::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXScatteringPowerSphere(parent,this); return mpWXCrystObj; } #endif }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ScatteringPowerSphere.h000066400000000000000000000073711417150057700255140ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* ScatteringPowerSphere.h * header file for the Spherical scattering power (fullerenes, etc..) * */ #ifndef _OBJCRYST_SCATTPOWERSPHERE_H_ #define _OBJCRYST_SCATTPOWERSPHERE_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" namespace ObjCryst { /** \ brief ScatteringPower for a spherical particule * * This can be used to modelize the form factor of disordered (or low-resolution) * of fullerene-type compounds, where all atoms are located on a * sphere. * * This actually modelizes a spherical distribution of a \e single electron, so to modelize * C60 the occupancy must be set to 60*6. */ class ScatteringPowerSphere: public ScatteringPower { public: /// Default constructor ScatteringPowerSphere(); /** \brief constructor * \param name : name of the ScatteringPower ('C60','France 98'...). *The name can have \e any format * \param nbAtom: the number of atoms * \param biso : Isotropic thermic coefficient * \param AxisLengthX,AxisLengthY,AxisLengthZ: length of the different * main axis of the ellipsoid * \param symbol: the symbol of the element associated to this fullerene. By * default it is assumed to be carbon */ ScatteringPowerSphere(const string &name,const REAL radius,const REAL bIso=1.0); ScatteringPowerSphere(const ScatteringPowerSphere& old); ~ScatteringPowerSphere(); void Init(const string &name,const REAL radius,const REAL bIso=1.0); virtual const string& GetClassName() const; virtual CrystVector_REAL GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual REAL GetForwardScatteringFactor(const RadiationType) const; virtual CrystVector_REAL GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactReal(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactImag(const ScatteringData &data, const int spgSymPosIndex=0) const; REAL GetRadius()const; virtual void Print()const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); private: virtual void InitRefParList(); // Avoid compiler warnings. Explicitly hide the base-class method. void Init(); /// Isotropic temperature B-factor. REAL mBiso; /** Radius of the sphere. */ REAL mRadius; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXScatteringPowerSphere; #endif }; }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/SpaceGroup.cpp000066400000000000000000000614611417150057700236300ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file LibCryst++ AsymmetricUnit and SpaceGroup classes * */ #include #include #include #include "cctbx/sgtbx/space_group.h" #include "cctbx/sgtbx/brick.h" #include "cctbx/miller/sym_equiv.h" #include #include "ObjCryst/ObjCryst/SpaceGroup.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs.. #include "ObjCryst/ObjCryst/GeomStructFactor.h" //Geometrical Struct Factor definitions #include "ObjCryst/Quirks/VFNDebug.h" #include #define POSSIBLY_UNUSED(expr) (void)(expr) namespace ObjCryst { #include "ObjCryst/Quirks/VFNDebug.h" // We need to force the C locale when using cctbx (when interpreting xyz strings) tmp_C_Numeric_locale::tmp_C_Numeric_locale() { char *old; old=setlocale(LC_NUMERIC,NULL); mLocale=old; setlocale(LC_NUMERIC,"C"); } tmp_C_Numeric_locale::~tmp_C_Numeric_locale() { setlocale(LC_NUMERIC,mLocale.c_str()); } //////////////////////////////////////////////////////////////////////// // // AsymmetricUnit // //////////////////////////////////////////////////////////////////////// AsymmetricUnit::AsymmetricUnit() { VFN_DEBUG_MESSAGE("AsymmetricUnit::AsymmetricUnit()",5) mXmin=0; mYmin=0; mZmin=0; mXmax=1; mYmax=1; mZmax=1; } AsymmetricUnit::AsymmetricUnit(const SpaceGroup &spg) { VFN_DEBUG_MESSAGE("AsymmetricUnit::AsymmetricUnit(SpGroup)",5) this->SetSpaceGroup(spg); } AsymmetricUnit::~AsymmetricUnit() { VFN_DEBUG_MESSAGE("AsymmetricUnit::~AsymmetricUnit(SpGroup)",5) } void AsymmetricUnit::SetSpaceGroup(const SpaceGroup &spg) { VFN_DEBUG_MESSAGE("AsymmetricUnit::SetSpaceGroup(SpGroup)",5) tmp_C_Numeric_locale tmploc; # if 0 TAU_PROFILE("(AsymmetricUnit::SetSpaceGroup)","void (SpaceGroup)",TAU_DEFAULT); mXmin=0.; mYmin=0.; mZmin=0.; mXmax=1.; mYmax=1.; mZmax=1.; if(1==spg.GetSpaceGroupNumber()) return;//no need to search an asymmetric unit // Test points=reular grid of points inside the unit cell // All points must be or have at least a symmetric in the asymmetric unit const long nbPoints=13; CrystMatrix_REAL testPoints(nbPoints*nbPoints*nbPoints,3); { long l=0; for(long i=0;iACCEPTED:" << mXmax <<" "<< mYmax <<" "<< mZmax <ACCEPTED:" << mXmax <<" "<< mYmax <<" "<< mZmax <Finished Generating (pseudo) Asymmetric Unit, with:"<>Parallelepipedic Asymmetric Unit, from cctbx::sgtbx::brick:"<(b(0,0).value()); mYmin=boost::rational_cast(b(1,0).value()); mZmin=boost::rational_cast(b(2,0).value()); mXmax=boost::rational_cast(b(0,1).value()); mYmax=boost::rational_cast(b(1,1).value()); mZmax=boost::rational_cast(b(2,1).value()); #endif } bool AsymmetricUnit::IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z)const { return ( ( x <= mXmin) && ( x >= mXmax) &&( y <= mYmin) && ( y >= mYmax) &&( z <= mZmin) && ( z >= mZmax)); } REAL AsymmetricUnit::Xmin() const {return mXmin;} REAL AsymmetricUnit::Xmax() const {return mXmax;} REAL AsymmetricUnit::Ymin() const {return mYmin;} REAL AsymmetricUnit::Ymax() const {return mYmax;} REAL AsymmetricUnit::Zmin() const {return mZmin;} REAL AsymmetricUnit::Zmax() const {return mZmax;} //////////////////////////////////////////////////////////////////////// // // SpaceGroup // //////////////////////////////////////////////////////////////////////// SpaceGroup::SpaceGroup():mId("P1"),mpCCTbxSpaceGroup(0) { InitSpaceGroup(mId); } SpaceGroup::SpaceGroup(const string &spgId):mId(spgId),mpCCTbxSpaceGroup(0) { InitSpaceGroup(spgId); } SpaceGroup::~SpaceGroup() { if(mpCCTbxSpaceGroup!=0) delete mpCCTbxSpaceGroup; } void SpaceGroup::ChangeSpaceGroup(const string &spgId) { VFN_DEBUG_MESSAGE("SpaceGroup::ChangeSpaceGroup():"<InitSpaceGroup(spgId); } const string& SpaceGroup::GetName()const{return mId;} bool SpaceGroup::IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z) const { return mAsymmetricUnit.IsInAsymmetricUnit(x,y,z); } void SpaceGroup::ChangeToAsymmetricUnit(REAL x, REAL y, REAL z) const { //:TODO: } const AsymmetricUnit& SpaceGroup::GetAsymUnit() const {return mAsymmetricUnit;} /// Id number of the spacegroup int SpaceGroup::GetSpaceGroupNumber()const { return mSpgNumber; } bool SpaceGroup::IsCentrosymmetric()const { return mHasInversionCenter; } int SpaceGroup::GetNbTranslationVectors()const { return mNbTrans; } const std::vector& SpaceGroup::GetTranslationVectors()const { return mvTrans; } const std::vector& SpaceGroup::GetSymmetryOperations()const { return mvSym; } CrystMatrix_REAL SpaceGroup::GetAllSymmetrics(const REAL x, const REAL y, const REAL z, const bool noCenter,const bool noTransl, const bool noIdentical)const { //TAU_PROFILE("SpaceGroup::GetAllSymmetrics()","Matrix (x,y,z)",TAU_DEFAULT); VFN_DEBUG_MESSAGE("SpaceGroup::GetAllSymmetrics()",0) int nbMatrix, nbTrans,coeffInvert,i,j,k; nbMatrix=this->GetCCTbxSpg().n_smx(); nbTrans=this->GetNbTranslationVectors(); if(this->IsCentrosymmetric()) coeffInvert=2 ; else coeffInvert=1; if(noCenter==true) coeffInvert=1; //skip center of symmetry if(noTransl==true) nbTrans=1; //skip translation operations CrystMatrix_REAL coords(nbMatrix*nbTrans*coeffInvert,3); k=0; for(i=0;iGetCCTbxSpg().ltr(i).den()); const REAL tx=this->GetCCTbxSpg().ltr(i)[0]*ltr_den; const REAL ty=this->GetCCTbxSpg().ltr(i)[1]*ltr_den; const REAL tz=this->GetCCTbxSpg().ltr(i)[2]*ltr_den; //if(noTransl==false) cout << nbTrans <GetCCTbxSpg().smx(j)); const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r()); const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t()); const REAL r_den=1/(REAL)(pMatrix->r().den()); const REAL t_den=1/(REAL)(pMatrix->t().den()); coords(k,0)= ((*pRot)[0]*x+(*pRot)[1]*y+(*pRot)[2]*z)*r_den+(*pTrans)[0]*t_den+tx; coords(k,1)= ((*pRot)[3]*x+(*pRot)[4]*y+(*pRot)[5]*z)*r_den+(*pTrans)[1]*t_den+ty; coords(k,2)= ((*pRot)[6]*x+(*pRot)[7]*y+(*pRot)[8]*z)*r_den+(*pTrans)[2]*t_den+tz; k++; } } if(coeffInvert==2) //inversion center not in ListSeitzMx, but to be applied { int shift=nbMatrix*nbTrans; const REAL dx=((REAL)this->GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den();//inversion not at the origin const REAL dy=((REAL)this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den(); const REAL dz=((REAL)this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den(); for(i=0;iGetCCTbxSpg().n_smx(); int nbTrans=this->GetNbTranslationVectors(); POSSIBLY_UNUSED(nbTrans); if(this->IsCentrosymmetric()) coeffInvert=2 ; else coeffInvert=1; if(noCenter==true) coeffInvert=1; //skip center of symmetry if(noTransl==true) nbTrans=1; //skip translation operations const int i=idx/nbMatrix;//translation index const int j=idx%nbMatrix; const REAL ltr_den=1/(REAL)(this->GetCCTbxSpg().ltr(i).den()); const REAL tx=this->GetCCTbxSpg().ltr(i)[0]*ltr_den; const REAL ty=this->GetCCTbxSpg().ltr(i)[1]*ltr_den; const REAL tz=this->GetCCTbxSpg().ltr(i)[2]*ltr_den; const cctbx::sgtbx::rt_mx *pMatrix=&(this->GetCCTbxSpg().smx(j)); const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r()); const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t()); const REAL r_den=1/(REAL)(pMatrix->r().den()); const REAL t_den=1/(REAL)(pMatrix->t().den()); const REAL x1= ((*pRot)[0]*x+(*pRot)[1]*y+(*pRot)[2]*z)*r_den; const REAL y1= ((*pRot)[3]*x+(*pRot)[4]*y+(*pRot)[5]*z)*r_den; const REAL z1= ((*pRot)[6]*x+(*pRot)[7]*y+(*pRot)[8]*z)*r_den; if(derivative==false) { x=x1+(*pTrans)[0]*t_den+tx; y=y1+(*pTrans)[1]*t_den+ty; z=z1+(*pTrans)[2]*t_den+tz; } else { x=x1; y=y1; z=z1; } if(coeffInvert==2) //inversion center not in ListSeitzMx, but to be applied { const REAL dx=((REAL)this->GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den();//inversion not at the origin const REAL dy=((REAL)this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den(); const REAL dz=((REAL)this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den(); x=dx-x; y=dy-y; z=dz-z; } } int SpaceGroup::GetNbSymmetrics(const bool noCenter,const bool noTransl)const { if(noCenter || (!mHasInversionCenter)) { if(noTransl) return mNbSym; else return mNbSym*mNbTrans; } else { if(noTransl) return 2*mNbSym; else return 2*mNbSym*mNbTrans; } return 2*mNbSym*mNbTrans; } void SpaceGroup::Print() const { cout << "SpaceGroup:" <GetCCTbxSpg().n_smx();i++) cout << " " << this->GetCCTbxSpg().smx(i).as_xyz() <GetCCTbxSpg().inv_t()[0])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << " " << (this->GetCCTbxSpg().inv_t()[1])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << " " << (this->GetCCTbxSpg().inv_t()[2])/(REAL)this->GetCCTbxSpg().inv_t().den()/2. << endl; } if(this->GetCCTbxSpg().n_ltr()>0) { cout <<" List of Translation vectors :"<GetCCTbxSpg().n_ltr();i++) cout << " "<< this->GetCCTbxSpg().ltr(i)[0]/(REAL)this->GetCCTbxSpg().ltr(i).den()<<"," << this->GetCCTbxSpg().ltr(i)[1]/(REAL)this->GetCCTbxSpg().ltr(i).den()<<"," << this->GetCCTbxSpg().ltr(i)[2]/(REAL)this->GetCCTbxSpg().ltr(i).den()<GetCCTbxSpg().inv_t()[0]; center(1) = this->GetCCTbxSpg().inv_t()[1]; center(2) = this->GetCCTbxSpg().inv_t()[2]; // inv_t is the overall translation associated with inversion, // the actual inversion center is therefore at midpoint. center /= 2 * this->GetCCTbxSpg().inv_t().den(); return center; } unsigned int SpaceGroup::AreReflEquiv(const REAL h1, const REAL k1, const REAL l1, const REAL h2, const REAL k2, const REAL l2)const { const int ih1=scitbx::math::iround(h1); const int ik1=scitbx::math::iround(k1); const int il1=scitbx::math::iround(l1); cctbx::miller::index h0(scitbx::vec3(ih1,ik1,il1)); const int ih2=scitbx::math::iround(h2); const int ik2=scitbx::math::iround(k2); const int il2=scitbx::math::iround(l2); cctbx::miller::index k0(scitbx::vec3(ih2,ik2,il2)); cctbx::miller::sym_equiv_indices sei(this->GetCCTbxSpg(),k0); int equiv=0; //cout< k = sei(i_mate, i_indices).h(); //cout<<" ->("< h(scitbx::vec3(ih0,ik0,il0)); cctbx::miller::sym_equiv_indices sei(this->GetCCTbxSpg(),h); int nbEquiv; if(forceFriedelLaw) nbEquiv=sei.multiplicity(false); else nbEquiv=sei.multiplicity(true); if( ((this->IsCentrosymmetric())||forceFriedelLaw) && excludeFriedelMate) nbEquiv/=2; CrystMatrix_REAL equivReflList(nbEquiv,5); complex sf0((double)(sf_re),(double)(sf_im)); for(int i=0;i k = sei(i).h(); equivReflList(i,0)=(REAL)k[0]; equivReflList(i,1)=(REAL)k[1]; equivReflList(i,2)=(REAL)k[2]; equivReflList(i,3)=(REAL)sei(i).complex_eq(sf0).real(); equivReflList(i,4)=(REAL)sei(i).complex_eq(sf0).imag(); } VFN_DEBUG_EXIT("SpaceGroup::GetAllEquivRefl():",5) return equivReflList; } bool SpaceGroup::IsReflSystematicAbsent(const REAL h0, const REAL k0, const REAL l0)const { const int ih0=scitbx::math::iround(h0); const int ik0=scitbx::math::iround(k0); const int il0=scitbx::math::iround(l0); cctbx::miller::index h(scitbx::vec3(ih0,ik0,il0)); return this->GetCCTbxSpg().is_sys_absent(h); } bool SpaceGroup::IsReflCentric(const REAL h0, const REAL k0, const REAL l0)const { const int ih0=scitbx::math::iround(h0); const int ik0=scitbx::math::iround(k0); const int il0=scitbx::math::iround(l0); cctbx::miller::index h(scitbx::vec3(ih0,ik0,il0)); return this->GetCCTbxSpg().is_centric(h); } unsigned int SpaceGroup::GetExpectedIntensityFactor(const REAL h0, const REAL k0, const REAL l0)const { const int ih0=scitbx::math::iround(h0); const int ik0=scitbx::math::iround(k0); const int il0=scitbx::math::iround(l0); cctbx::miller::index h(scitbx::vec3(ih0,ik0,il0)); return this->GetCCTbxSpg().epsilon(h); } void SpaceGroup::InitSpaceGroup(const string &spgId) { if((mId==spgId)&&(mpCCTbxSpaceGroup!=0)) return; VFN_DEBUG_ENTRY("SpaceGroup::InitSpaceGroup():"<GetCCTbxSpg().f_inv() == 2) { mHasInversionCenter=true ; if( (this->GetCCTbxSpg().inv_t()[0] !=0) || (this->GetCCTbxSpg().inv_t()[1] !=0) || (this->GetCCTbxSpg().inv_t()[2] !=0) ) mIsInversionCenterAtOrigin=false; else mIsInversionCenterAtOrigin=true; } else { mHasInversionCenter=false ; mIsInversionCenterAtOrigin=true; } //initialize asymmetric unit mAsymmetricUnit.SetSpaceGroup(*this); mUniqueAxisId=0; if( (this->GetCCTbxSpg().type().number() >2) &&(this->GetCCTbxSpg().type().number() <16)) { string ch=this->GetCCTbxSpg().match_tabulated_settings().hall(); if(ch.find("x")!=std::string::npos) {mUniqueAxisId=0;} else if(ch.find("y")!=std::string::npos) {mUniqueAxisId=1;} else mUniqueAxisId=2; } mNbSym =this->GetCCTbxSpg().n_smx(); mNbTrans =this->GetCCTbxSpg().n_ltr(); mSpgNumber=this->GetCCTbxSpg().type().number(); mExtension='\0'; //this->GetCCTbxSpg().type().extension(); } catch(exception ex) { (*fpObjCrystInformUser)("Error initializing spacegroup (Incorrect Hall symbol ?):"+spgId); if (mId != spgId) { (*fpObjCrystInformUser)("Reverting to spacegroup symbol:"+mId); this->InitSpaceGroup(mId); } VFN_DEBUG_EXIT("SpaceGroup::InitSpaceGroup() could not interpret spacegroup:"<GetCCTbxSpg().match_tabulated_settings().extension(); // Force using the H-M symbol if(mExtension=='\0') mId=this->GetCCTbxSpg().match_tabulated_settings().hermann_mauguin(); else mId=this->GetCCTbxSpg().match_tabulated_settings().hermann_mauguin()+":"+mExtension; // Store rotation matrices & translation vectors mvTrans.resize(mNbTrans); for(unsigned int i=0;iGetCCTbxSpg().ltr(i)[j]/(REAL)(this->GetCCTbxSpg().ltr(i).den()); } mvSym.resize(mNbSym); for(unsigned int j=0;jGetCCTbxSpg().smx(j)); const cctbx::sgtbx::rot_mx *pRot=&(pMatrix->r()); const cctbx::sgtbx::tr_vec *pTrans=&(pMatrix->t()); const REAL r_den=1/(REAL)(pMatrix->r().den()); const REAL t_den=1/(REAL)(pMatrix->t().den()); for(unsigned int i=0;i<9;++i) mvSym[j].mx[i]=(*pRot)[i]*r_den; for(unsigned int i=0;i<3;++i) mvSym[j].tr[i]=(*pTrans)[i]*t_den; } #ifdef __DEBUG__ this->Print(); #endif mClock.Click(); string extension(""); if(mExtension=='1') extension=" (Using origin choice #1)"; if(mExtension=='2') extension=" (Using origin choice #2)"; if(mExtension=='R') extension=" (Using Rhombohedral cell)"; if(mExtension=='H') extension=" (Using Hexagonal cell)"; #ifdef __DEBUG__ (*fpObjCrystInformUser)("Initialized spacegroup, HM: "+spgId+extension+" , Hall:"+this->GetCCTbxSpg().type().hall_symbol()); #endif VFN_DEBUG_EXIT("SpaceGroup::InitSpaceGroup():"< //#include "cctbx/sgtbx/space_group.h" namespace cctbx{namespace sgtbx{class space_group;}} namespace ObjCryst { class SpaceGroup; //###################################################################### // AsymmetricUnit. /** * * \brief The basic description of spacegroup asymmetric unit. * * Only xmin,xmax,ymin,ymax and zmin,zmax are recorded, thus resulting * in a parallelepipedic unit with one (0,0,0) corner. * It is not really 'asymmetric' since more than the crystallographic asymmetric * unit can be included in it. * * \todo Currently the initialization of the asymmetric unit is done * numerically, slowly. A faster algorithm should be used (using * dichotomy), or we could switch to using a table of asymmetric units. */ //###################################################################### class AsymmetricUnit { public: /// Default Constructor. AsymmetricUnit(); /// Constructor, for a given spacegroup. AsymmetricUnit(const SpaceGroup &spg); ~AsymmetricUnit(); /// Assign a SpaceGroup and generate the corrsponding Xmax, Ymax, ZMax. void SetSpaceGroup(const SpaceGroup &spg); /// Test if (x,y,z) is in the asymmetric unit bool IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z)const; REAL Xmin() const; REAL Xmax() const; REAL Ymin() const; REAL Ymax() const; REAL Zmin() const; REAL Zmax() const; protected: private: REAL mXmin,mXmax,mYmin,mYmax,mZmin,mZmax; }; //###################################################################### // SpaceGroup /** * \brief The crystallographic space group, and the cell choice. * * This class includes functions to get basic information about * the symmetries, as well as getting all symmetrics for a given * position in a unit cell. * * This class included a pointer to a function calculating the "geometrical * structure factor" (ie the sum of sin() and cos() for all symetrics, as * could be found in the old version of the (red) International Tables), * which was used to speed up computation of structure factors * by using pre-factorised formulas. * This is not used anymore, since methods can be used to speed up computations. * * This class uses R. Grosse-Kunstleve 'SgLite' package, * which is part of the Pymol package : http://pymol.sourceforge.net/ * *\warning: the interface of the class will somewhat change when switching * from sgLite to cctbx (http://cctbx.sourceforge.net). Particularly * functions Spacegroup::GetSgOps() and Spacegroup::GetHM_as_Hall() will * be removed. */ //###################################################################### class SpaceGroup { public: /// Default Constructor (initializes in P1) /// /// You can use later SpaceGroup::ChangeSpaceGroup() to set the spacegroup. SpaceGroup(); /** \brief Constructor with a specified spacegroup symbol or number * * \param spgId The space group identifier, either an Hermann-Maugin, * or Hall, or Schonflies symbol. */ SpaceGroup(const string &spgId); /// Destructor ~SpaceGroup(); /// Change the Spacegroup void ChangeSpaceGroup(const string &spgId); /// Get the name of this spacegroup (its name, as supplied initially by /// the calling program or user) const string& GetName()const; /// Test if a given scatterer at (x,y,z) is in the asymmetric unit. bool IsInAsymmetricUnit(const REAL x, const REAL y, const REAL z) const; /// Move (x,y,z) coordinates to their equivalent in the asym unit /// \warning Not implemented yet. /// \todo SpaceGroup::IsInAsymmetricUnit() void ChangeToAsymmetricUnit(REAL x, REAL y, REAL z) const;//:TODO: /// Get the AsymmetricUnit for this spacegroup const AsymmetricUnit& GetAsymUnit() const; /// Id number of the spacegroup int GetSpaceGroupNumber()const; /// Is the crystal centrosymmetric ? bool IsCentrosymmetric()const; /** \brief Number of translation vectors * (1 for 'P' cells, 2 for 'I', 4 for 'F',etc..) * */ int GetNbTranslationVectors()const; /// Struct to store trans matrix struct TRx { REAL tr[3]; }; /// Struct to store rot+trans matrix struct SMx { REAL mx[9]; REAL tr[3]; }; /** Return all Translation Vectors, as a 3 columns-array * * The first vector is always [0,0,0] * \return * \f$ \left[ \begin {array}{ccc} 0 & 0 & 0 \end{array} \right] \f$ * for a 'P' Cell, * \f$ \left[ \begin {array}{ccc} 0 & 0 & 0 \\ * \frac{1}{2} & \frac{1}{2} & \frac{1}{2} \\ \end{array} \right] \f$ * for a 'I' cell, and * \f$ \left[ \begin {array}{ccc} 0 & 0 & 0 \\ * \frac{1}{2} & \frac{1}{2} & 0 \\ * \frac{1}{2} & 0 & \frac{1}{2} \\ * 0 & \frac{1}{2} & \frac{1}{2} \\ \end{array} \right] \f$ *for a 'F' cell,etc... */ const std::vector& GetTranslationVectors()const; /** Get all symmetry operations stored in vector of struct SMx. */ const std::vector& GetSymmetryOperations()const; /** \brief Get all equivalent positions of a (xyz) position * * \param x,y,z fractional coordinates of the position * \param noCenter if set to 'false' (the default), then the center of * symmetry (if any) is used to generate ALL positions. If 'true', then * only one half of equivalent positions are generated. This has * no influence if the group is not centrosymmetric. (\b note Not generating * symmetrical positions from center of symmetry is useful to speed up computation * of structure factor, but is a bit tricky if the inversion is not at the origin. * This is taken into account) * \param noTransl if set to 'false' (the default), then translation are * taken into account to generate all atom positions. This affect * only body or face(s)-centered spacegroups. * \param noIdentical if set to true, then atom in special positions * will only return the distinct atomic positions. Currently two atoms are considered * distinct if the difference for all of their fractionnal coordinates is less than 1e-5 * \return a 3-column (x,y,z) matrix with as many rows as symmetric atoms * \warning 'special' positions are not taken into account. (ie an * atom in special position will return duplicate entries. This may be * corrected automatically later.) You can use the 'noIdentical' option for that, */ CrystMatrix_REAL GetAllSymmetrics(const REAL x, const REAL y, const REAL z, const bool noCenter=false,const bool noTransl=false, const bool noIdentical=false) const; /** \brief Get all equivalent positions of a (xyz) position * * \param x,y,z: fractional coordinates of the position. On return, * these will contain the new values. * \param noCenter if set to 'false' (the default), then the center of * symmetry (if any) is used to generate ALL positions. If 'true', then * only one half of equivalent positions are generated. This has * no influence if the group is not centrosymmetric. (\b note Not generating * symmetrical positions from center of symmetry is useful to speed up computation * of structure factor, but is a bit tricky if the inversion is not at the origin. * This is taken into account) * \param noTransl if set to 'false' (the default), then translation are * taken into account to generate all atom positions. This affect * only body or face(s)-centered spacegroups. * \param derivative: if true, then this is used to calculate the displacement * vector of s symmetric, given the orginal (dx,dy,dz)=> the translation * components of gliding axis/plane are then ignored. */ void GetSymmetric(unsigned int i, REAL &x, REAL &y, REAL &z, const bool noCenter=false,const bool noTransl=false, const bool derivative=false) const; /** \brief Return the number of equivalent positions in the spacegroup, *ie the multilicity of the general position. * * \param noCenter if 'true', do not take into account the center of symmetry * \param noTransl if 'true', do not take into account translations */ int GetNbSymmetrics(const bool noCenter=false,const bool noTransl=false)const; /// Prints a description of the spacegroup (symbol, properties). /// /// \todo void Print()const; /// Is centrosymmetric ? bool HasInversionCenter()const; /// Is the center of symmetry at the origin ? bool IsInversionCenterAtOrigin()const; /// Get the underlying cctbx Spacegroup object const cctbx::sgtbx::space_group& GetCCTbxSpg()const; /// Get the SpaceGroup Clock (corresponding to the time of the /// initialization of the SpaceGroup) const RefinableObjClock& GetClockSpaceGroup() const; /// Which is the unique axis (for monoclinic space groups ) unsigned int GetUniqueAxis()const; /// Extension to space group symbol ('1','2':origin choice ; 'R','H'=rhomboedral/hexagonal) char GetExtension()const; /// Get the inversion center CrystVector_REAL GetInversionCenter()const; /** Are these reflections equivalent ? * * \return 1 if they are equivalent, 2 if they are Friedel/Bijvoet mates, and else 0. */ unsigned int AreReflEquiv(const REAL h1, const REAL k1, const REAL l1, const REAL h2, const REAL k2, const REAL l2)const; /** Get the list of all equivalent reflections. * * \return a matrix with 5 columns for h,k,l,Re(F),Im(F) and as many rows as there are * reflections (the input reflection is included), with the associated structure factor, * from the structure factor of the input reflection. * \param excludeFriedelMate if true, then Friedel mates of reflections will not * be listed, even if there is a center of symmetry. * \param forceFriedelLaw if true, a center of symmetry will be added (to force * considering Friedel mates as equivalent). This as no effect if * excludeFriedelMate=true * * \param sf_re, sf_im: the real & imaginary part of the structure factor of the original reflection */ CrystMatrix_REAL GetAllEquivRefl(const REAL h, const REAL k, const REAL l, const bool excludeFriedelMate=false, const bool forceFriedelLaw=false, const REAL sf_re=0,const REAL sf_im=0) const; /// Is the reflection systematically absent ? bool IsReflSystematicAbsent(const REAL h, const REAL k, const REAL l)const; /// Is the reflection centric ? bool IsReflCentric(const REAL h, const REAL k, const REAL l)const; /** Get the "expected intensity factor" for a given reflection. * This is the * number of times the reflection is identical to the reflections deduced by * the symmetry operators, under all distinct pure rotationnal symmetry operations * of the space group. * * This is used for the probability distribution of reflection intensities. * * See: * - Stewart & Karle, Acta. Cryst 132 (1976), 1005 * - Wilson, Acta Cryst 3 (1950), 258 */ unsigned int GetExpectedIntensityFactor(const REAL h, const REAL k, const REAL l)const; protected: private: /** \brief Init the spaceGroup object from its name * *Initialize the SgOps & HM_as_Hall structures (SgLite), *and set the function pointers to the functions used to *compute the geometrical structure factors. */ void InitSpaceGroup(const string &spgId); /// Spacegroup's name ( 'I422', 'D2^8','230') /// Maybe we should only store the Hermann-Mauguin symbol, rather than storing /// the string which was initially given by the user/program for the initialization. string mId; /** \brief SgOps structure for this spacegroup. (Symmetry operations) * * See sglite subdirectory for more information. * This is (c) R. Gross-Kunstleve, part of PyMol software * http://pymol.sourceforge.net/ */ cctbx::sgtbx::space_group *mpCCTbxSpaceGroup; /** \brief Is spacegroup centrosymmetric ? * */ bool mHasInversionCenter; /** \brief Is center of symmetry at the origin ? * */ bool mIsInversionCenterAtOrigin; /// The spacegroup asymmetric unit AsymmetricUnit mAsymmetricUnit; /// The Spacegroup clock RefinableObjClock mClock; /// Unique axis number (0=a,1=b,2=c) unsigned int mUniqueAxisId; /// Number of symmetry operations (excluding center, and translations). unsigned long mNbSym; /// Number of lattice translations, including (0,0,0). unsigned long mNbTrans; /// SpaceGroup Number unsigned long mSpgNumber; /// Extension to space group symbol (1,2:origin choice ; R,H=rhomboedral/hexagonal) char mExtension; /// Store floating-point matrices for faster use std::vector mvSym; /// Store floating-point translation vectors for faster use std::vector mvTrans; }; }//namespace #endif //_OBJCRYST_SPACEGROUP_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/UnitCell.cpp000066400000000000000000000505641417150057700233010ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file ObjCryst++ Crystal class * */ #include "ObjCryst/ObjCryst/UnitCell.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" namespace ObjCryst { const RefParType *gpRefParTypeUnitCell=0; const RefParType *gpRefParTypeUnitCellLength=0; const RefParType *gpRefParTypeUnitCellAngle=0; long NiftyStaticGlobalObjectsInitializer_UnitCell::mCount=0; UnitCell::UnitCell(): mCellDim(6), mBMatrix(3,3),mOrthMatrix(3,3),mOrthMatrixInvert(3,3) { VFN_DEBUG_MESSAGE("UnitCell::UnitCell()",10) this->InitOptions(); this->Init(10,11,12,M_PI/2+.1,M_PI/2+.2,M_PI/2+.3,"P 1",""); mClockMaster.AddChild(mClockLatticePar); mClockMaster.AddChild(this->GetSpaceGroup().GetClockSpaceGroup()); } UnitCell::UnitCell(const REAL a, const REAL b, const REAL c, const string &SpaceGroupId): mCellDim(6), mBMatrix(3,3),mOrthMatrix(3,3),mOrthMatrixInvert(3,3) { VFN_DEBUG_MESSAGE("UnitCell::UnitCell(a,b,c,Sg)",10) this->Init(a,b,c,M_PI/2,M_PI/2,M_PI/2,SpaceGroupId,""); this->InitOptions(); mClockMaster.AddChild(mClockLatticePar); mClockMaster.AddChild(this->GetSpaceGroup().GetClockSpaceGroup()); } UnitCell::UnitCell(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId): mCellDim(6), mBMatrix(3,3),mOrthMatrix(3,3),mOrthMatrixInvert(3,3) { VFN_DEBUG_MESSAGE("UnitCell::UnitCell(a,b,c,alpha,beta,gamma,Sg)",10) this->Init(a,b,c,alpha,beta,gamma,SpaceGroupId,""); this->InitOptions(); mClockMaster.AddChild(mClockLatticePar); mClockMaster.AddChild(this->GetSpaceGroup().GetClockSpaceGroup()); } UnitCell::UnitCell(const UnitCell &old): mCellDim(old.mCellDim),mSpaceGroup(old.GetSpaceGroup()), mBMatrix(3,3),mOrthMatrix(3,3),mOrthMatrixInvert(3,3) { VFN_DEBUG_MESSAGE("UnitCell::UnitCell(&oldUnitCell)",10) this ->InitRefParList(); mConstrainLatticeToSpaceGroup.SetChoice(old.mConstrainLatticeToSpaceGroup.GetChoice()); this->InitMatrices(); this->UpdateLatticePar(); mClockMaster.AddChild(mClockLatticePar); mClockMaster.AddChild(this->GetSpaceGroup().GetClockSpaceGroup()); } UnitCell::~UnitCell() { VFN_DEBUG_ENTRY("UnitCell::~UnitCell()",5) VFN_DEBUG_EXIT("UnitCell::~UnitCell()",5) } const string& UnitCell::GetClassName() const { const static string className="UnitCell"; return className; } CrystVector_REAL UnitCell::GetLatticePar() const { VFN_DEBUG_MESSAGE("UnitCell::GetLatticePar()",0) if(mClockLatticeParUpdate>mClockLatticePar) return mCellDim; else { //:NOTE: cannot use this->UpdateLatticePar() because it is not a const member function int num = mSpaceGroup.GetSpaceGroupNumber(); CrystVector_REAL cellDim=mCellDim; if((num <=2)||(mConstrainLatticeToSpaceGroup.GetChoice()!=0)) return cellDim; if((num <=15) && (0==mSpaceGroup.GetUniqueAxis())) { cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim; } if((num <=15) && (1==mSpaceGroup.GetUniqueAxis())) { cellDim(3)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim; } if((num <=15) && (2==mSpaceGroup.GetUniqueAxis())) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; return cellDim; } if(num <=74) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim; } if(num <= 142) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; cellDim(1) = mCellDim(0) ; return cellDim; } if(mSpaceGroup.GetExtension()=='R') { cellDim(4) = mCellDim(3); cellDim(5) = mCellDim(3); cellDim(1) = mCellDim(0); cellDim(2) = mCellDim(0); return cellDim; } if(num <= 194) // || (mSpaceGroup.GetExtension()=='H') //Hexagonal {//Hexagonal axes, for hexagonal and non-rhomboedral trigonal cells cellDim(3) = M_PI/2.; cellDim(4) = M_PI/2.; cellDim(5) = M_PI*2./3.; cellDim(1) = mCellDim(0) ; return cellDim; } cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; cellDim(1) = mCellDim(0) ; cellDim(2) = mCellDim(0) ; return cellDim; } } REAL UnitCell::GetLatticePar(int whichPar)const { VFN_DEBUG_MESSAGE("UnitCell::LatticePar(i)",0) if( (whichPar<0) || (whichPar>5)) throw ObjCrystException("UnitCell::LatticePar(int) :trying to access parameter>5!"); if(mClockLatticeParUpdate>mClockLatticePar) return mCellDim(whichPar); else { const int num = mSpaceGroup.GetSpaceGroupNumber(); static CrystVector_REAL cellDim; cellDim=mCellDim; if((num <=2)||(mConstrainLatticeToSpaceGroup.GetChoice()!=0)) return cellDim(whichPar); if((num <=15) && (0==mSpaceGroup.GetUniqueAxis())) { cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim(whichPar); } if((num <=15) && (1==mSpaceGroup.GetUniqueAxis())) { cellDim(3)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim(whichPar); } if((num <=15) && (2==mSpaceGroup.GetUniqueAxis())) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; return cellDim(whichPar); } if(num <=74) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; return cellDim(whichPar); } if(num <= 142) { cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; cellDim(1) = mCellDim(0) ; return cellDim(whichPar); } if(mSpaceGroup.GetExtension()=='R') { cellDim(4) = mCellDim(3); cellDim(5) = mCellDim(3); cellDim(1) = mCellDim(0); cellDim(2) = mCellDim(0); return cellDim(whichPar); } if(num <= 194) // ||(mSpaceGroup.GetExtension()=='H') {//Hexagonal axes, for hexagonal and non-rhomboedral trigonal cells cellDim(3) = M_PI/2.; cellDim(4) = M_PI/2.; cellDim(5) = M_PI*2./3.; cellDim(1) = mCellDim(0) ; return cellDim(whichPar); } cellDim(3)=M_PI/2.; cellDim(4)=M_PI/2.; cellDim(5)=M_PI/2.; cellDim(1) = mCellDim(0) ; cellDim(2) = mCellDim(0) ; return cellDim(whichPar); } } const CrystMatrix_REAL& UnitCell::GetBMatrix()const { VFN_DEBUG_MESSAGE("UnitCell::GetBMatrix()",0) this->InitMatrices(); return mBMatrix; } const CrystMatrix_REAL& UnitCell::GetOrthMatrix() const { VFN_DEBUG_MESSAGE("UnitCell::GetOrthMatrix()",0) this->InitMatrices(); return mOrthMatrix; } CrystVector_REAL UnitCell::GetOrthonormalCoords(const REAL x, const REAL y, const REAL z) const { this->InitMatrices(); CrystVector_REAL coords(3); coords(0)=mOrthMatrix(0,0)*x+mOrthMatrix(0,1)*y+mOrthMatrix(0,2)*z; coords(1)=mOrthMatrix(1,0)*x+mOrthMatrix(1,1)*y+mOrthMatrix(1,2)*z; coords(2)=mOrthMatrix(2,0)*x+mOrthMatrix(2,1)*y+mOrthMatrix(2,2)*z; return coords; } void UnitCell::FractionalToOrthonormalCoords(REAL &x,REAL &y,REAL &z) const { this->InitMatrices(); const REAL oldx=x; const REAL oldy=y; x=mOrthMatrix(0,0)*oldx+mOrthMatrix(0,1)*oldy+mOrthMatrix(0,2)*z; y=mOrthMatrix(1,0)*oldx+mOrthMatrix(1,1)*oldy+mOrthMatrix(1,2)*z; z=mOrthMatrix(2,0)*oldx+mOrthMatrix(2,1)*oldy+mOrthMatrix(2,2)*z; } void UnitCell::OrthonormalToFractionalCoords(REAL &x,REAL &y,REAL &z) const { //cout << x << " " << y << " " << z <InitMatrices(); const REAL oldx=x; const REAL oldy=y; x=mOrthMatrixInvert(0,0)*oldx+mOrthMatrixInvert(0,1)*oldy+mOrthMatrixInvert(0,2)*z; y=mOrthMatrixInvert(1,0)*oldx+mOrthMatrixInvert(1,1)*oldy+mOrthMatrixInvert(1,2)*z; z=mOrthMatrixInvert(2,0)*oldx+mOrthMatrixInvert(2,1)*oldy+mOrthMatrixInvert(2,2)*z; //cout << x << " " << y << " " << z <InitMatrices(); const REAL oldx=x; const REAL oldy=y; x=mBMatrix(0,0)*oldx+mBMatrix(0,1)*oldy+mBMatrix(0,2)*z; y=mBMatrix(1,0)*oldx+mBMatrix(1,1)*oldy+mBMatrix(1,2)*z; z=mBMatrix(2,0)*oldx+mBMatrix(2,1)*oldy+mBMatrix(2,2)*z; } void UnitCell::OrthonormalToMillerCoords(REAL &x,REAL &y,REAL &z) const { this->InitMatrices(); const REAL oldx=x; const REAL oldy=y; x=mBMatrixInvert(0,0)*oldx+mBMatrixInvert(0,1)*oldy+mBMatrixInvert(0,2)*z; y=mBMatrixInvert(1,0)*oldx+mBMatrixInvert(1,1)*oldy+mBMatrixInvert(1,2)*z; z=mBMatrixInvert(2,0)*oldx+mBMatrixInvert(2,1)*oldy+mBMatrixInvert(2,2)*z; } void UnitCell::Print(ostream &os)const { VFN_DEBUG_MESSAGE("UnitCell::Print()",5) this->InitMatrices(); int width =8 ; os << "UnitCell : " << mName <<"("<GetSpaceGroup().GetName()<<")"<< endl; os.width(width); os << " Cell dimensions : " << FormatFloat(this->GetLatticePar(0),8,5) << " " << FormatFloat(this->GetLatticePar(1),8,5) << " " << FormatFloat(this->GetLatticePar(2),8,5) << " " << FormatFloat(this->GetLatticePar(3)*RAD2DEG,8,5) << " " << FormatFloat(this->GetLatticePar(4)*RAD2DEG,8,5) << " " << FormatFloat(this->GetLatticePar(5)*RAD2DEG,8,5) << endl ; } const SpaceGroup & UnitCell::GetSpaceGroup() const {return mSpaceGroup;} SpaceGroup & UnitCell::GetSpaceGroup() {return mSpaceGroup;} const RefinableObjClock& UnitCell::GetClockLatticePar()const {return mClockLatticePar;} const RefinableObjClock& UnitCell::GetClockMetricMatrix()const {return mClockMetricMatrix;} REAL UnitCell::GetVolume()const { const REAL a=this->GetLatticePar(0); const REAL b=this->GetLatticePar(1); const REAL c=this->GetLatticePar(2); const REAL alpha=this->GetLatticePar(3); const REAL beta=this->GetLatticePar(4); const REAL gamma=this->GetLatticePar(5); return a*b*c*sqrt(1-cos(alpha)*cos(alpha)-cos(beta)*cos(beta)-cos(gamma)*cos(gamma) +2*cos(alpha)*cos(beta)*cos(gamma)); } void UnitCell::Init(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId, const string& name) { VFN_DEBUG_ENTRY("UnitCell::Init(a,b,c,alpha,beta,gamma,Sg,name)",10) //mSpaceGroup.Print(); mSpaceGroup.ChangeSpaceGroup(SpaceGroupId); //mSpaceGroup.Print(); mCellDim(0)=a; mCellDim(1)=b; mCellDim(2)=c; mCellDim(3)=alpha; mCellDim(4)=beta; mCellDim(5)=gamma; mClockLatticePar.Click(); mClockMetricMatrix.Reset(); mClockLatticeParUpdate.Reset(); this->InitRefParList(); this->InitMatrices(); this->UpdateLatticePar(); this->SetName(name); VFN_DEBUG_EXIT("UnitCell::Init(a,b,c,alpha,beta,gamma,Sg,name):End",10) } void UnitCell::InitOptions() { VFN_DEBUG_ENTRY("UnitCell::InitOptions",10) static string ConstrainLatticeToSpaceGroupName; static string ConstrainLatticeToSpaceGroupChoices[2]; static bool needInitNames=true; if(true==needInitNames) { ConstrainLatticeToSpaceGroupName="Constrain Lattice to SpaceGroup Symmetry"; ConstrainLatticeToSpaceGroupChoices[0]="Yes (Default)"; ConstrainLatticeToSpaceGroupChoices[1]="No (Allow Crystallographic Pseudo-Symmetry)"; needInitNames=false;//Only once for the class } VFN_DEBUG_MESSAGE("UnitCell::Init(a,b,c,alpha,beta,gamma,Sg,name):Init options",5) mConstrainLatticeToSpaceGroup.Init(2,&ConstrainLatticeToSpaceGroupName, ConstrainLatticeToSpaceGroupChoices); mConstrainLatticeToSpaceGroup.SetChoice(0); this->AddOption(&mConstrainLatticeToSpaceGroup); VFN_DEBUG_EXIT("UnitCell::InitOptions",10) } void UnitCell::InitMatrices() const { //:NOTE: The Matrices must remain upper triangular, since this is assumed for //optimization purposes in some procedures. if(mClockMetricMatrix>mClockLatticePar) return;//no need to update //this->UpdateLatticePar(); we should be able to do this... VFN_DEBUG_MESSAGE("UnitCell::InitMatrices() for crystal : "+this->GetName(),5) //mClockMetricMatrix.Print(); //mClockLatticePar.Print(); REAL a,b,c,alpha,beta,gamma;//direct space parameters REAL aa,bb,cc,alphaa,betaa,gammaa;//reciprocal space parameters REAL v;//volume of the unit cell a=this->GetLatticePar(0); b=this->GetLatticePar(1); c=this->GetLatticePar(2); alpha=this->GetLatticePar(3); beta=this->GetLatticePar(4); gamma=this->GetLatticePar(5); //cout <mSpaceGroup.GetClockSpaceGroup()) &&(mClockLatticeParUpdate>mClockLatticePar)) return; VFN_DEBUG_ENTRY("UnitCell::UpdateLatticePar().",3) int num = mSpaceGroup.GetSpaceGroupNumber(); if((num <=2)||(mConstrainLatticeToSpaceGroup.GetChoice()!=0)) { mClockLatticeParUpdate.Click(); return; } if((num <=15) && (0==mSpaceGroup.GetUniqueAxis())) { mCellDim(4)=M_PI/2.; mCellDim(5)=M_PI/2.; mClockLatticeParUpdate.Click(); return; } if((num <=15) && (1==mSpaceGroup.GetUniqueAxis())) { mCellDim(3)=M_PI/2.; mCellDim(5)=M_PI/2.; mClockLatticeParUpdate.Click(); return; } if((num <=15) && (2==mSpaceGroup.GetUniqueAxis())) { mCellDim(3)=M_PI/2.; mCellDim(4)=M_PI/2.; mClockLatticeParUpdate.Click(); return; } if(num <=74) { mCellDim(3)=M_PI/2.; mCellDim(4)=M_PI/2.; mCellDim(5)=M_PI/2.; mClockLatticeParUpdate.Click(); return; } if(num <= 142) { mCellDim(3)=M_PI/2.; mCellDim(4)=M_PI/2.; mCellDim(5)=M_PI/2.; mCellDim(1) = mCellDim(0) ; mClockLatticeParUpdate.Click(); return; } if(mSpaceGroup.GetExtension()=='R') { mCellDim(4) = mCellDim(3); mCellDim(5) = mCellDim(3); mCellDim(1) = mCellDim(0); mCellDim(2) = mCellDim(0); mClockLatticeParUpdate.Click(); return; } if(num <= 194) //||(mSpaceGroup.GetExtension()=='H') {//Hexagonal axes, for hexagonal and non-rhomboedral trigonal cells mCellDim(3) = M_PI/2.; mCellDim(4) = M_PI/2.; mCellDim(5) = M_PI*2./3.; mCellDim(1) = mCellDim(0) ; mClockLatticeParUpdate.Click(); return; } mCellDim(3)=M_PI/2.; mCellDim(4)=M_PI/2.; mCellDim(5)=M_PI/2.; mCellDim(1) = mCellDim(0) ; mCellDim(2) = mCellDim(0) ; mClockLatticeParUpdate.Click(); VFN_DEBUG_EXIT("UnitCell::UpdateLatticePar().",3) return; } void UnitCell::InitRefParList() { VFN_DEBUG_ENTRY("UnitCell::InitRefParList()",5) //this->ResetParList(); int num = mSpaceGroup.GetSpaceGroupNumber(); bool a=true; bool b=true; bool c=true; bool alpha=true; bool beta=true; bool gamma=true; if(mConstrainLatticeToSpaceGroup.GetChoice()==0) { if(num <=2) { } else if((num <=15) && (0==mSpaceGroup.GetUniqueAxis())) { beta=false; gamma=false; } else if((num <=15) && (1==mSpaceGroup.GetUniqueAxis())) { alpha=false; gamma=false; } else if((num <=15) && (2==mSpaceGroup.GetUniqueAxis())) { alpha=false; beta=false; } else if(num <=74) { alpha=false; beta=false; gamma=false; } else if(num <= 142) { b=false; alpha=false; beta=false; gamma=false; } else if(mSpaceGroup.GetExtension()=='R') {//Rhombohedral b=false; c=false; alpha=true; beta=false; gamma=false; } else if(num <= 194) {//Hexagonal axes, for hexagonal and non-rhomboedral trigonal cells b=false; alpha=false; beta=false; gamma=false; } else { b=false; c=false; alpha=false; beta=false; gamma=false; } } REAL *pLatPar=mCellDim.data(); if(this->GetNbPar()==0) {//:KLUDGE: { RefinablePar tmp("a",pLatPar,1.,100., gpRefParTypeUnitCellLength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,a,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } { RefinablePar tmp("b",pLatPar+1,1.,100., gpRefParTypeUnitCellLength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,b,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } { RefinablePar tmp("c",pLatPar+2,1.,100., gpRefParTypeUnitCellLength,REFPAR_DERIV_STEP_ABSOLUTE, true,true,c,false,1.0); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } { RefinablePar tmp("alpha",pLatPar+3,.5,3., gpRefParTypeUnitCellAngle,REFPAR_DERIV_STEP_ABSOLUTE, true,true,alpha,false,RAD2DEG); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } { RefinablePar tmp("beta",pLatPar+4,.5,3., gpRefParTypeUnitCellAngle,REFPAR_DERIV_STEP_ABSOLUTE, true,true,beta,false,RAD2DEG); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } { RefinablePar tmp("gamma",pLatPar+5,.5,3., gpRefParTypeUnitCellAngle,REFPAR_DERIV_STEP_ABSOLUTE, true,true,gamma,false,RAD2DEG); tmp.SetDerivStep(1e-4); tmp.AssignClock(mClockLatticePar); this->AddPar(tmp); } } else {//Just Fix the 'used' status this->GetPar(pLatPar+0).SetIsUsed(a); this->GetPar(pLatPar+1).SetIsUsed(b); this->GetPar(pLatPar+2).SetIsUsed(c); this->GetPar(pLatPar+3).SetIsUsed(alpha); this->GetPar(pLatPar+4).SetIsUsed(beta); this->GetPar(pLatPar+5).SetIsUsed(gamma); } VFN_DEBUG_EXIT("UnitCell::InitRefParList():Finished",5) } } libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/UnitCell.h000066400000000000000000000263211417150057700227400ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* UnitCell.h header file for the UnitCell object * */ #ifndef _OBJCRYST_UNITCELL_H_ #define _OBJCRYST_UNITCELL_H_ #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/ObjCryst/SpaceGroup.h" namespace ObjCryst { extern const RefParType *gpRefParTypeUnitCell; extern const RefParType *gpRefParTypeUnitCellLength; extern const RefParType *gpRefParTypeUnitCellAngle; class NiftyStaticGlobalObjectsInitializer_UnitCell { public: NiftyStaticGlobalObjectsInitializer_UnitCell() { if (mCount++ == 0) { gpRefParTypeUnitCell=new RefParType (gpRefParTypeObjCryst,"Unit Cell"); gpRefParTypeUnitCellLength=new RefParType (gpRefParTypeUnitCell,"Unit Cell Length"); gpRefParTypeUnitCellAngle=new RefParType (gpRefParTypeUnitCell,"Unit Cell Angle"); } } ~NiftyStaticGlobalObjectsInitializer_UnitCell() { if (--mCount == 0) { delete gpRefParTypeUnitCell; delete gpRefParTypeUnitCellLength; delete gpRefParTypeUnitCellAngle; gpRefParTypeUnitCell=0; gpRefParTypeUnitCellLength=0; gpRefParTypeUnitCellAngle=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_UnitCell NiftyStaticGlobalObjectsInitializer_UnitCell_counter; //###################################################################### /** \brief Unit Cell class: Unit cell with spacegroup information. * */ //###################################################################### class UnitCell:public RefinableObj { public: /// Default Constructor UnitCell(); /** \brief UnitCell Constructor (orthorombic) * \param a,b,c : unit cell dimension, in angstroems * \param SpaceGroupId: space group symbol or number */ UnitCell(const REAL a, const REAL b, const REAL c, const string &SpaceGroupId); /** \brief UnitCell Constructor (triclinic) * \param a,b,c : unit cell dimension, in angstroems * \param alpha,beta,gamma : unit cell angles, in radians. * \param SpaceGroupId: space group symbol or number */ UnitCell(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId); /// UnitCell copy constructor UnitCell(const UnitCell &oldCryst); /// Destructor ~UnitCell(); virtual const string& GetClassName() const; /// Lattice parameters (a,b,c,alpha,beta,gamma) as a 6-element vector in Angstroems /// and radians. CrystVector_REAL GetLatticePar() const; /// Return one of the 6 Lattice parameters, 0<= whichPar <6 (a,b,c,alpha,beta,gamma), /// returned in Angstroems and radians. REAL GetLatticePar(const int whichPar)const; /// last time the Lattice parameters were changed const RefinableObjClock& GetClockLatticePar()const; /** \brief Get the 'B' matrix (UnitCell::mBMatrix)for the UnitCell (orthogonalization * matrix for the given lattice, in the reciprocal space) * * The convention is taken following Giacovazzo, "Fundamentals of Crystallography", p.69 * "e1 is chosen along a*, e2 in the (a*,b*) plane, then e3 is along c". */ const CrystMatrix_REAL& GetBMatrix() const; /** \brief Get the orthogonalization matrix (UnitCell::mOrthMatrix)for the UnitCell * in real space * */ const CrystMatrix_REAL& GetOrthMatrix() const; /// last time the metric matrices were changed const RefinableObjClock& GetClockMetricMatrix()const; /** \brief Get orthonormal cartesian coordinates for a set of (x,y,z) * fractional coordinates. * * Results are given in Angstroems. * The convention is taken following : * e1 is chosen along a, e2 in the (a,b) plane, then e3 is along c* */ CrystVector_REAL GetOrthonormalCoords(const REAL x,const REAL y,const REAL z) const; /** \brief Get orthonormal cartesian coordinates for a set of (x,y,z) * fractional coordinates. * * X,y and z input are changed to Amgstroems values * The convention is taken following : * e1 is chosen along a, e2 in the (a,b) plane, then e3 is along c* */ void FractionalToOrthonormalCoords(REAL &x,REAL &y,REAL &z) const; /** \brief Get fractional cartesian coordinates for a set of (x,y,z) * orthonormal coordinates. * * Result is stored into x,y and z * The convention is taken following : * e1 is chosen along a, e2 in the (a,b) plane, then e3 is along c* */ void OrthonormalToFractionalCoords(REAL &x,REAL &y,REAL &z) const; /** \brief Get Miller H,K, L indices from orthonormal coordinates * in reciprocal space. * * Result is stored into x,y and z */ void MillerToOrthonormalCoords(REAL &x,REAL &y,REAL &z) const; /** \brief Get orthonormal coordinates given a set of H,K, L indices * in reciprocal space. * * Result is stored into x,y and z */ void OrthonormalToMillerCoords(REAL &x,REAL &y,REAL &z) const; /** Prints some info about the UnitCell * * \param os the stream to which the information is outputed (default=cout) */ virtual void Print(ostream &os) const; // Avoid compiler warnings about hidden base class method. virtual void Print() const { this->Print(cout); } /// Access to the SpaceGroup object const SpaceGroup & GetSpaceGroup()const; /// Access to the SpaceGroup object. SpaceGroup & GetSpaceGroup(); // :TODO: ? //virtual void XMLOutput(ostream &os,int indent=0)const; //virtual void XMLInput(istream &is,const XMLCrystTag &tag); /// Volume of Unit Cell (in Angstroems) REAL GetVolume()const; protected: /** \brief Init all UnitCell parameters * \param a,b,c : unit cell dimension, in angstroems * \param alpha,beta,gamma : unit cell angles * \param SpcGroup: space group number (1..230) * \param name: name for the UnitCell, : '(TaSe4)2I' */ virtual void Init(const REAL a, const REAL b, const REAL c, const REAL alpha, const REAL beta, const REAL gamma,const string &SpaceGroupId, const string& name); /** \brief Prepare the refinable parameters list * * This is called once when creating the UnitCell. */ void InitRefParList(); private: /** Init options. * * Need only be done once per UnitCell. */ virtual void InitOptions(); /// \internal.Init the (de)orthogonalization matrices. /// They are re-computed only if parameters have changed since last call. void InitMatrices() const; /// \internal /// Update cell parameters for tetragonal, trigonal, hexagonal, cubic lattices. /// Also set angular parameters for those group which need it. This is needed during /// Refinement, since for example in a quadratic spg, only a is refined and /// we need to have b=a... void UpdateLatticePar(); /// a,b and c in Angstroems, angles (stored) in radians /// For cubic, rhomboedric UnitCells, only the 'a' parameter is relevant. /// For quadratic and hexagonal UnitCells, only a and c parameters are relevant. /// The MUTABLE is temporary ! It should not be ! CrystVector_REAL mCellDim; /// The space group of the UnitCell SpaceGroup mSpaceGroup ; /** \brief B Matrix (Orthogonalization matrix for reciprocal space) * \f[ B= \left[ \begin {array}{ccc} a^* & b^*\cos(\gamma^*) & c^*\cos(\beta^*) \\ * 0 & b^*\sin(\gamma^*) & -c^*\sin(\beta^*)\cos(\alpha) \\ * 0 & 0 & \frac{1}{c}\end{array} \right]\f] *\f[ \left[ \begin{array}{c} k_x \\ k_y \\ k_z \end{array} \right]_{orthonormal} * = B \times \left[ \begin{array}{c} h \\ k \\ l \end{array}\right]_{integer} \f] * \note this matrix is and must remain upper triangular. this is assumed for * some optimizations. */ mutable CrystMatrix_REAL mBMatrix; /// inverse of B Matrix (i.e. inverse of orthogonalization matrix for direct space) mutable CrystMatrix_REAL mBMatrixInvert; /** \brief Eucl Matrix (Orthogonalization matrix for direct space) * \f[ M_{orth}= \left[ \begin {array}{ccc} a & b\cos(\gamma) & c\cos(\beta) \\ * 0 & b\sin(\gamma) & -c\sin(\beta)\cos(\alpha^*) \\ * 0 & 0 & \frac{1}{c^*}\end{array} \right]\f] * \f[ \left[ \begin{array}{c} x \\ y \\ z \end{array} \right]_{orthonormal} * = M_{orth} \times \left[ \begin{array}{c} x \\ y \\ z \end{array} * \right]_{fractional coords}\f] * \note this matrix is and must remain upper triangular. this is assumed for * some optimizations. */ mutable CrystMatrix_REAL mOrthMatrix; /// inverse of Eucl Matrix (i.e. inverse of de-orthogonalization matrix for direct space) mutable CrystMatrix_REAL mOrthMatrixInvert; /// Last time lattice parameters were changed RefinableObjClock mClockLatticePar; /// \internal Last time metric matrices were computed mutable RefinableObjClock mClockMetricMatrix; /// \internal Last time the lattice parameters whre updated mutable RefinableObjClock mClockLatticeParUpdate; /** Option to override lattice parameters constraints from spacegroup choice. * * \warning EXPERIMENTAL * * Normally lattice parameters are constrained by the space group choice * (e.g. a=b=c and angles =90° for cubic spacegroups). Using this option * allows you to override this, and choose any lattice parameter. THis works * as long as symmetry operations are applied to fractionnal coordinates. * * This is useful duting global optimization when searching the structure in a UnitCell * which has (or is expected to have) a known pseudo-crystallographic * symmetry, to reduce dramatically the number of parameters. Of course * for final refinement the 'real' symmetry should be imposed. */ RefObjOpt mConstrainLatticeToSpaceGroup; }; }// namespace #endif //_OBJCRYST_UNITCELL_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/ZScatterer.cpp000066400000000000000000003374271417150057700236560ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Atom.h * header file for the Atom scatterer * */ #include #include #include #include //for sprintf() //#include "ObjCryst/ObjCryst/ScatteringPower.h" //#include "ObjCryst/ObjCryst/Scatterer.h" //#include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/ObjCryst/ZScatterer.h" #include "ObjCryst/ObjCryst/ScatteringData.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" //simple formatting of integers, REALs.. #include "ObjCryst/Quirks/VFNDebug.h" #include #include #ifdef OBJCRYST_GL #ifdef __DARWIN__ #include #else #include #endif #endif #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxZScatterer.h" #undef GetClassName // Conflict from wxMSW headers ? (cygwin) #endif #ifdef _MSC_VER // MS VC++ predefined macros.... #undef min #undef max #endif namespace ObjCryst { //###################################################################### // // ZAtom // // //###################################################################### ZAtom::ZAtom(ZScatterer &scatt,const ScatteringPower *pow, const long atomBond, const REAL bondLength, const long atomAngle, const REAL bondAngle, const long atomDihedral, const REAL dihedralAngle, const REAL popu, const string &name): mpScattPow(pow), mAtomBond(atomBond),mAtomAngle(atomAngle),mAtomDihed(atomDihedral), mBondLength(bondLength),mAngle(bondAngle),mDihed(dihedralAngle), mOccupancy(popu),mName(name),mpScatt(&scatt) { VFN_DEBUG_MESSAGE("ZAtom::ZAtom():("<GetClockScatterer().Click();} void ZAtom::SetZAngle(const REAL angle) {mAngle=angle;mpScatt->GetClockScatterer().Click();} void ZAtom::SetZDihedralAngle(const REAL dihed) {mDihed=dihed;mpScatt->GetClockScatterer().Click();} void ZAtom::SetOccupancy(const REAL pop) {mOccupancy=pop;mpScatt->GetClockScatterer().Click();} void ZAtom::SetScatteringPower(const ScatteringPower* scatt) {mpScattPow=scatt;mpScatt->GetClockScatterer().Click();} #ifdef __WX__CRYST__ WXCrystObjBasic* ZAtom::WXCreate(wxWindow *parent) { VFN_DEBUG_ENTRY("ZAtom::WXCreate()",7) mpWXCrystObj=new WXZAtom (parent,this); VFN_DEBUG_EXIT("ZAtom::WXCreate()",7) return mpWXCrystObj; } WXCrystObjBasic* ZAtom::WXGet() { return mpWXCrystObj; } void ZAtom::WXDelete() { if(0!=mpWXCrystObj) { VFN_DEBUG_MESSAGE("ZAtom::WXDelete()",5) delete mpWXCrystObj; } mpWXCrystObj=0; } void ZAtom::WXNotifyDelete() { VFN_DEBUG_MESSAGE("ZAtom::WXNotifyDelete():"<GetXCoord().data(); const REAL *pY1=mpZScatt->GetYCoord().data(); const REAL *pZ1=mpZScatt->GetZCoord().data(); const REAL *pX0=mXCoord0.data(); const REAL *pY0=mYCoord0.data(); const REAL *pZ0=mZCoord0.data(); const REAL *pW=mAtomWeight.data(); REAL dist=0; //for(int i=mXCoord0.numElements()-1;i>=0;i--) // dist+= abs(*pX1++ - *pX0++) + abs(*pY1++ - *pY0++) + abs(*pZ1++ - *pZ0++); for(int i=mXCoord0.numElements()-1;i>=0;i--) { dist+= *pW++* ( (*pX1 - *pX0)*(*pX1 - *pX0) +(*pY1 - *pY0)*(*pY1 - *pY0) +(*pZ1 - *pZ0)*(*pZ1 - *pZ0)); pX1++;pY1++;pZ1++; pX0++;pY0++;pZ0++; } #if 0 const CrystVector_REAL *pXcoord=&(mpZScatt->GetXCoord()); const CrystVector_REAL *pYcoord=&(mpZScatt->GetYCoord()); const CrystVector_REAL *pZcoord=&(mpZScatt->GetZCoord()); REAL dist=0; for(int i=pXcoord->numElements()-1;i>=0;i--) { dist+=mAtomWeight(i)*( ((*pXcoord)(i)-mXCoord0(i))*((*pXcoord)(i)-mXCoord0(i)) +((*pYcoord)(i)-mYCoord0(i))*((*pYcoord)(i)-mYCoord0(i)) +((*pZcoord)(i)-mZCoord0(i))*((*pZcoord)(i)-mZCoord0(i))); } #endif return dist/mAtomWeight.sum(); } void ZMoveMinimizer::RecordConformation() { mXCoord0=mpZScatt->GetXCoord(); mYCoord0=mpZScatt->GetYCoord(); mZCoord0=mpZScatt->GetZCoord(); if(mAtomWeight.numElements() != mXCoord0.numElements()) { mAtomWeight.resize(mXCoord0.numElements()); mAtomWeight=1; } } void ZMoveMinimizer::SetZAtomWeight(const CrystVector_REAL weight) {mAtomWeight=weight;} void ZMoveMinimizer::MinimizeChange(long nbTrial) { if(mAtomWeight.max()<1e-3) return; mOptimObj.Optimize(nbTrial,true); } //###################################################################### // // ZScatterer // // //###################################################################### ZScatterer::ZScatterer(const string &name,Crystal &cryst, const REAL x,const REAL y,const REAL z, const REAL phi,const REAL chi, const REAL psi): mScattCompList(0),mNbAtom(0),mNbDummyAtom(0), mPhi(0),mChi(0),mPsi(0), mZAtomRegistry("List of ZAtoms"), mCenterAtomIndex(0), mPhiChiPsiMatrix(3,3), mUseGlobalScattPow(false),mpGlobalScattPow(0), mpZMoveMinimizer(0) { VFN_DEBUG_MESSAGE("ZScatterer::ZScatterer():("<SetCrystal(cryst); this->InitRefParList(); VFN_DEBUG_MESSAGE("ZScatterer::ZScatterer():("<SetCrystal(*(old.mpCryst)); this->InitRefParList(); VFN_DEBUG_MESSAGE("ZScatterer::ZScatterer(&old):Copying atoms",10) for(long i=0; iAddAtom(old.GetZAtomRegistry().GetObj(i).GetName(), old.GetZAtomRegistry().GetObj(i).GetScatteringPower(), old.GetZAtomRegistry().GetObj(i).GetZBondAtom(), old.GetZAtomRegistry().GetObj(i).GetZBondLength(), old.GetZAtomRegistry().GetObj(i).GetZAngleAtom(), old.GetZAtomRegistry().GetObj(i).GetZAngle(), old.GetZAtomRegistry().GetObj(i).GetZDihedralAngleAtom(), old.GetZAtomRegistry().GetObj(i).GetZDihedralAngle(), old.GetZAtomRegistry().GetObj(i).GetOccupancy()); this->SetUseGlobalScatteringPower(old.mUseGlobalScattPow); // Copy parameters attributes (limits, etc...) VFN_DEBUG_MESSAGE("ZScatterer::ZScatterer(&old):Copying param attributes",10) this->GetPar(mXYZ.data()). CopyAttributes(old.GetPar(old.mXYZ.data())); this->GetPar(mXYZ.data()+1).CopyAttributes(old.GetPar(old.mXYZ.data()+1)); this->GetPar(mXYZ.data()+2).CopyAttributes(old.GetPar(old.mXYZ.data()+2)); this->GetPar(&mOccupancy). CopyAttributes(old.GetPar(&(old.mOccupancy))); this->GetPar(&mPhi). CopyAttributes(old.GetPar(&(old.mPhi))); this->GetPar(&mChi). CopyAttributes(old.GetPar(&(old.mChi))); this->GetPar(&mPsi). CopyAttributes(old.GetPar(&(old.mPsi))); VFN_DEBUG_MESSAGE("ZScatterer::ZScatterer(&old):Copying atoms param attributes",10) for(long i=0; iGetPar(&(this->GetZAtomRegistry().GetObj(i).mBondLength)). CopyAttributes(old.GetPar(&(old.GetZAtomRegistry().GetObj(i).mBondLength))); this->GetPar(&(this->GetZAtomRegistry().GetObj(i).mAngle)). CopyAttributes(old.GetPar(&(old.GetZAtomRegistry().GetObj(i).mAngle))); this->GetPar(&(this->GetZAtomRegistry().GetObj(i).mDihed)). CopyAttributes(old.GetPar(&(old.GetZAtomRegistry().GetObj(i).mDihed))); this->GetPar(&(this->GetZAtomRegistry().GetObj(i).mOccupancy)). CopyAttributes(old.GetPar(&(old.GetZAtomRegistry().GetObj(i).mOccupancy))); } VFN_DEBUG_EXIT("ZScatterer::ZScatterer(&old):("<mBondLength), 1.,5., // bondLength*.9,bondLength*1.1, gpRefParTypeScattConformBondLength, REFPAR_DERIV_STEP_ABSOLUTE,true,false,usedBond,false,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { sprintf(buf,"%d-%d-%d",(int)mNbAtom,(int)atomBond,(int)atomAngle); RefinablePar tmp("Angle"+(string)buf,&(zatom->mAngle), 0,2*M_PI, // zatom->mAngle-.2,zatom->mAngle+.2, gpRefParTypeScattConformBondAngle, REFPAR_DERIV_STEP_ABSOLUTE,false,false,usedAngle,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { sprintf(buf,"%d-%d-%d-%d",(int)mNbAtom,(int)atomBond,(int)atomAngle,(int)atomDihedral); RefinablePar tmp("Dihed"+(string)buf,&(zatom->mDihed), 0,2*M_PI, // zatom->mDihed-.2,zatom->mDihed+.2, gpRefParTypeScattConformDihedAngle, REFPAR_DERIV_STEP_ABSOLUTE,false,false,usedDihed,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } {//fixed by default sprintf(buf,"%d",(int)mNbAtom); RefinablePar tmp("Occupancy"+(string)buf, &(zatom->mOccupancy),0,1, gpRefParTypeScattOccup, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } //:NOTE: we *must* add it in the registry after declaring the parameters, // since it triggers the creation of the WXZAtom, which requires the parameters... VFN_DEBUG_MESSAGE("ZScatterer::AddAtom():Registering...",2) mZAtomRegistry.Register(*zatom); // Add an entry for this atom in the list of all components. The actual values are // written in Update().No entry for a dummy atom VFN_DEBUG_MESSAGE("ZScatterer::AddAtom():Adding to the ScattCompList...",2) if(0!=pow) { ++mScattCompList; mScattCompList(mNbAtom-mNbDummyAtom).mpScattPow=pow; mComponentIndex.resizeAndPreserve(mNbAtom-mNbDummyAtom+1); mComponentIndex(mNbAtom-mNbDummyAtom)=mNbAtom; } else mNbDummyAtom++; //Finish mNbAtom++; mClockScatterer.Click(); VFN_DEBUG_MESSAGE("ZScatterer::AddAtom():End",3) } int ZScatterer::GetNbComponent() const { if(true==mUseGlobalScattPow) return 1; return mNbAtom-mNbDummyAtom; } const ScatteringComponentList& ZScatterer::GetScatteringComponentList() const { this->UpdateScattCompList(); return mScattCompList; } string ZScatterer::GetComponentName(const int i) const { return mZAtomRegistry.GetObj(mComponentIndex(i)).GetName(); } void ZScatterer::Print() const { VFN_DEBUG_MESSAGE("ZScatterer::Print()",5) //:TODO: //this->UpdateScattCompList(); //for(int i=0;imNbAtom;i++) ??; } REAL ZScatterer::GetPhi() const {return mPhi;} REAL ZScatterer::GetChi() const {return mChi;} REAL ZScatterer::GetPsi() const {return mPsi;} void ZScatterer::SetPhi(const REAL x) { mClockScatterer.Click();mPhi=x;} void ZScatterer::SetChi(const REAL y) { mClockScatterer.Click();mChi=y;} void ZScatterer::SetPsi(const REAL z) { mClockScatterer.Click();mPsi=z;} REAL ZScatterer::GetZAtomX(const int i)const{this->UpdateCoordinates(); return mXCoord(i);} REAL ZScatterer::GetZAtomY(const int i)const{this->UpdateCoordinates(); return mYCoord(i);} REAL ZScatterer::GetZAtomZ(const int i)const{this->UpdateCoordinates(); return mZCoord(i);} long ZScatterer::GetZBondAtom(const int i)const {return mZAtomRegistry.GetObj(i).GetZBondAtom();} long ZScatterer::GetZAngleAtom(const int i)const {return mZAtomRegistry.GetObj(i).GetZAngleAtom();} long ZScatterer::GetZDihedralAngleAtom(const int i)const {return mZAtomRegistry.GetObj(i).GetZDihedralAngleAtom();} REAL ZScatterer::GetZBondLength(const int i)const {return mZAtomRegistry.GetObj(i).GetZBondLength();} REAL ZScatterer::GetZAngle(const int i)const {return mZAtomRegistry.GetObj(i).GetZAngle();} REAL ZScatterer::GetZDihedralAngle(const int i)const {return mZAtomRegistry.GetObj(i).GetZDihedralAngle();} void ZScatterer::SetZBondLength(const int i,const REAL a) {mClockScatterer.Click();mZAtomRegistry.GetObj(i).SetZBondLength(a);} void ZScatterer::SetZAngle(const int i,const REAL a) {mClockScatterer.Click();mZAtomRegistry.GetObj(i).SetZAngle(a);} void ZScatterer::SetZDihedralAngle(const int i,const REAL a) {mClockScatterer.Click();mZAtomRegistry.GetObj(i).SetZDihedralAngle(a);} const ObjRegistry& ZScatterer::GetZAtomRegistry()const {return mZAtomRegistry;} ostream& ZScatterer::POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const { VFN_DEBUG_MESSAGE("ZScatterer::POVRayDescription()",5) //throw ObjCrystException("ZScatterer::POVRayDescription() not implemented! "+this->GetName()); //:TODO: this->UpdateScattCompList(); //for(long i=0;iPOVRayDescription(os,onlyIndependentAtoms); os << "// Description of ZScatterer :" << this->GetName() <POVRayDescription(os,onlyIndependentAtoms); return os; } //Declare colours for(int i=0;iIsDummy()) continue; os <<" #declare colour_"<GetName()<<"="<Colour()<<";"<GetX(); y(i)=mpAtom[i]->GetY(); z(i)=mpAtom[i]->GetZ(); this->GetCrystal().FractionalToOrthonormalCoords(x(i),y(i),z(i)); } for(int i=0;iIsDummy()) { os << " // Skipping Dummy Atom :" << mpAtom[i]->GetName() <GetName() <," << mpAtom[i]->GetRadius()/3<GetName() <<" }" << endl; os << " }" <IsDummy()) || (i==0)) continue; os << " cylinder"<,"<,"< xyzCoords; for(int i=0;iGetCrystal().GetSpaceGroup().GetAllSymmetrics(mpAtom[i]->GetX(), mpAtom[i]->GetY(), mpAtom[i]->GetZ(), false,false,false)); const int nbSymmetrics=(vXYZCoords[0])->rows(); int symNum=0; CrystMatrix_int translate(27,3); translate= -1,-1,-1, -1,-1, 0, -1,-1, 1, -1, 0,-1, -1, 0, 0, -1, 0, 1, -1, 1,-1, -1, 1, 0, -1, 1, 1, 0,-1,-1, 0,-1, 0, 0,-1, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1, 0, 1,-1, 0, 1, 0, 0, 1, 1, 1,-1,-1, 1,-1, 0, 1,-1, 1, 1, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1,-1, 1, 1, 0, 1, 1, 1; REAL dx,dy,dz; CrystVector_REAL x(mNbAtom),y(mNbAtom),z(mNbAtom); CrystVector_REAL xSave,ySave,zSave; for(int i=0;i(-limit)) && (x(0)<(1+limit)) &&(y(0)>(-limit)) && (y(0)<(1+limit)) &&(z(0)>(-limit)) && (z(0)<(1+limit))) { for(int k=0;kGetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k)); os << " // Symmetric&Translated #" << symNum++ <IsDummy()) { os << " // Skipping Dummy Atom :" << mpAtom[i]->GetName() <GetName() <," << mpAtom[i]->GetRadius()/3<GetName() <<" }" << endl; os << " }" <IsDummy()) || (i==0)) continue; os << " cylinder"<,"<,"<UpdateScattCompList(); if(true==mUseGlobalScattPow) { //mpAtom[mCenterAtomIndex]->GLInitDisplayList(onlyIndependentAtoms); return; } GLfloat colour_bond[]= { 0.5, .5, .5, 1.0 }; GLfloat colour_side[]= { 0.0, .0, .0, 1.0 }; const GLfloat colour0[] = {0.0f, 0.0f, 0.0f, 0.0f}; GLUquadricObj* pQuadric = gluNewQuadric(); if(true==onlyIndependentAtoms) { //cout << m3DDisplayIndex <0) { for(long k=0;kGetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mZAtomRegistry.GetObj(n1).GetScatteringPower()->GetColourRGB()); glPushMatrix(); glTranslatef(x(n1)*en, y(n1), z(n1)); gluSphere(pQuadric,mZAtomRegistry.GetObj(n1).GetScatteringPower() ->GetRadius()/3.,10,10); glPopMatrix(); } case 2: // Draw a bond { long n1,n2; n1=m3DDisplayIndex(k,1); n2=m3DDisplayIndex(k,2); if(hideHydrogens && (mZAtomRegistry.GetObj(n1).GetScatteringPower()->GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; if(hideHydrogens && (mZAtomRegistry.GetObj(n2).GetScatteringPower()->GetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; glPushMatrix(); glTranslatef(x(n1)*en, y(n1), z(n1)); glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colour_bond); GLUquadricObj *quadobj = gluNewQuadric(); glColor3f(1.0f,1.0f,1.0f); const REAL height= sqrt( (x(n2)-x(n1))*(x(n2)-x(n1)) +(y(n2)-y(n1))*(y(n2)-y(n1)) +(z(n2)-z(n1))*(z(n2)-z(n1))); glRotatef(180,(x(n2)-x(n1))*en,y(n2)-y(n1),z(n2)-z(n1)+height);// ?!?!?! gluCylinder(quadobj,.1,.1,height,10,1 ); gluDeleteQuadric(quadobj); glPopMatrix(); } case 3: // Draw a triangular face { long n1,n2,n3; REAL x1,y1,z1,x2,y2,z2,xn,yn,zn,xc,yc,zc; n1=m3DDisplayIndex(k,1); n2=m3DDisplayIndex(k,2); n3=m3DDisplayIndex(k,3); x1=x(n1)-x(n2); y1=y(n1)-y(n2); z1=z(n1)-z(n2); x2=x(n1)-x(n3); y2=y(n1)-y(n3); z2=z(n1)-z(n3); xn=y1*z2-z1*y2; yn=z1*x2-x1*z2; zn=x1*y2-y1*x2; xc=(x(n1)+x(n2)+x(n3))/3.-x(mCenterAtomIndex); yc=(y(n1)+y(n2)+y(n3))/3.-y(mCenterAtomIndex); zc=(z(n1)+z(n2)+z(n3))/3.-z(mCenterAtomIndex); glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mZAtomRegistry.GetObj(0).GetScatteringPower()->GetColourRGB()); //glColor3f(1.0f,1.0f,1.0f); // White glBegin(GL_TRIANGLES); // Bottom if((xn*xc+yn*yc+zn*zc)>0) glNormal3f(xn*en, yn, zn); else glNormal3f(-xn*en, -yn, -zn); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glEnd(); glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colour_side); glBegin(GL_LINE_LOOP); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glEnd(); } case 4: // Draw a quadric face { long n1,n2,n3,n4; REAL x1,y1,z1,x2,y2,z2,xn,yn,zn,xc,yc,zc; n1=m3DDisplayIndex(k,1); n2=m3DDisplayIndex(k,2); n3=m3DDisplayIndex(k,3); n4=m3DDisplayIndex(k,3); x1=x(n1)-x(n2); y1=y(n1)-y(n2); z1=z(n1)-z(n2); x2=x(n1)-x(n3); y2=y(n1)-y(n3); z2=z(n1)-z(n3); xn=y1*z2-z1*y2; yn=z1*x2-x1*z2; zn=x1*y2-y1*x2; xc=(x(n1)+x(n2)+x(n3)+x(n4))/4.-x(mCenterAtomIndex); yc=(y(n1)+y(n2)+y(n3)+y(n4))/4.-y(mCenterAtomIndex); zc=(z(n1)+z(n2)+z(n3)+z(n4))/4.-z(mCenterAtomIndex); glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mZAtomRegistry.GetObj(0).GetScatteringPower()->GetColourRGB()); //glColor3f(1.0f,1.0f,1.0f); // White glBegin(GL_TRIANGLES); // Bottom if((xn*xc+yn*yc+zn*zc)>0) glNormal3f(xn*en, yn, zn); else glNormal3f(-xn*en, -yn, -zn); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glVertex3f(x(n4)*en,y(n4),z(n4)); glEnd(); glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colour_side); glBegin(GL_LINE_LOOP); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glVertex3f(x(n4)*en,y(n4),z(n4)); glEnd(); } } } } else { for(int k=0;kGetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; const float r=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[0]; const float g=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[1]; const float b=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[2]; glPushMatrix(); glTranslatef(x(k)*en, y(k), z(k)); if(displayNames) { GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } glMaterialfv(GL_FRONT, GL_AMBIENT, colour0); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS,colour0); glRasterPos3f(0.0f, 0.0f, 0.0f); crystGLPrint(mZAtomRegistry.GetObj(k).GetName()); } else { const GLfloat colourAtom [] = {r, g, b, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colourAtom); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glPolygonMode(GL_FRONT, GL_FILL); gluSphere(pQuadric, mZAtomRegistry.GetObj(k).GetScatteringPower()->GetRadius()/3.,10,10); //Draw the bond for this Atom,if it's not linked to a dummy int bond=this->GetZBondAtom(k); if((0!=mZAtomRegistry.GetObj(bond).GetScatteringPower()) && (k>0)) { glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,colour_bond); GLUquadricObj *quadobj = gluNewQuadric(); glColor3f(1.0f,1.0f,1.0f); const REAL height= sqrt( (x(bond)-x(k))*(x(bond)-x(k)) +(y(bond)-y(k))*(y(bond)-y(k)) +(z(bond)-z(k))*(z(bond)-z(k))); glRotatef(180,(x(bond)-x(k))*en,y(bond)-y(k),z(bond)-z(k)+height);// !!! gluCylinder(quadobj,.1,.1,height,10,1 ); gluDeleteQuadric(quadobj); } } glPopMatrix(); } }//Use triangle faces ? }//Only independent atoms ? else { VFN_DEBUG_ENTRY("ZScatterer::GLInitDisplayList():Show all symmetrics",3) vector vXYZCoords; { REAL x0,y0,z0; for(int i=0;iGetCrystal().OrthonormalToFractionalCoords(x0,y0,z0); vXYZCoords.push_back(this->GetCrystal().GetSpaceGroup(). GetAllSymmetrics(x0,y0,z0,false,false,false)); } } CrystMatrix_int translate(27,3); translate= -1,-1,-1, -1,-1, 0, -1,-1, 1, -1, 0,-1, -1, 0, 0, -1, 0, 1, -1, 1,-1, -1, 1, 0, -1, 1, 1, 0,-1,-1, 0,-1, 0, 0,-1, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1, 0, 1,-1, 0, 1, 0, 0, 1, 1, 1,-1,-1, 1,-1, 0, 1,-1, 1, 1, 0,-1, 1, 0, 0, 1, 0, 1, 1, 1,-1, 1, 1, 0, 1, 1, 1; REAL dx,dy,dz; CrystVector_REAL x(mNbAtom),y(mNbAtom),z(mNbAtom); CrystVector_REAL xSave,ySave,zSave; const int nbSymmetrics=vXYZCoords[0].rows(); for(int i=0;ixMin) && (x(0)yMin) && (y(0)zMin) && (z(0)GetCrystal().FractionalToOrthonormalCoords(x(k),y(k),z(k)); //:NOTE: The code below is the same as without symmetrics if(m3DDisplayIndex.numElements()>0) { long n1,n2,n3; REAL x1,y1,z1,x2,y2,z2,xn,yn,zn,xc,yc,zc; for(long k=0;kGetColourRGB()); glBegin(GL_TRIANGLES); if((xn*xc+yn*yc+zn*zc)>0) glNormal3f( xn*en, yn, zn); else glNormal3f(-xn*en, -yn, -zn); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glEnd(); glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colour_side); glBegin(GL_LINE_LOOP); glVertex3f(x(n1)*en,y(n1),z(n1)); glVertex3f(x(n2)*en,y(n2),z(n2)); glVertex3f(x(n3)*en,y(n3),z(n3)); glEnd(); } } else { for(int k=0;kGetForwardScatteringFactor(RAD_XRAY)<1.5)) continue; const float r=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[0]; const float g=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[1]; const float b=mZAtomRegistry.GetObj(k).GetScatteringPower()->GetColourRGB()[2]; glPushMatrix(); glTranslatef(x(k)*en, y(k), z(k)); if(displayNames) { GLfloat colourChar [] = {1.0, 1.0, 1.0, 1.0}; if((r>0.8)&&(g>0.8)&&(b>0.8)) { colourChar[0] = 0.5; colourChar[1] = 0.5; colourChar[2] = 0.5; } glMaterialfv(GL_FRONT, GL_AMBIENT, colour0); glMaterialfv(GL_FRONT, GL_DIFFUSE, colour0); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colourChar); glMaterialfv(GL_FRONT, GL_SHININESS,colour0); glRasterPos3f(0.0f, 0.0f, 0.0f); crystGLPrint(mZAtomRegistry.GetObj(k).GetName()); } else { const GLfloat colourAtom [] = {r, g, b, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,colourAtom); glMaterialfv(GL_FRONT, GL_SPECULAR, colour0); glMaterialfv(GL_FRONT, GL_EMISSION, colour0); glMaterialfv(GL_FRONT, GL_SHININESS, colour0); glPolygonMode(GL_FRONT, GL_FILL); gluSphere(pQuadric, mZAtomRegistry.GetObj(k).GetScatteringPower()->GetRadius()/3.,10,10); glRasterPos3f(0,0,0); //Draw the bond for this Atom,if it's not linked to a dummy int bond=this->GetZBondAtom(k); if((0!=mZAtomRegistry.GetObj(bond).GetScatteringPower()) && (k>0)) { glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,colour_bond); GLUquadricObj *quadobj = gluNewQuadric(); glColor3f(1.0f,1.0f,1.0f); const REAL height= sqrt( (x(bond)-x(k))*(x(bond)-x(k)) +(y(bond)-y(k))*(y(bond)-y(k)) +(z(bond)-z(k))*(z(bond)-z(k))); glRotatef(180,(x(bond)-x(k))*en,y(bond)-y(k),z(bond)-z(k)+height);// !!! gluCylinder(quadobj,.1,.1,height,10,1 ); gluDeleteQuadric(quadobj); } } glPopMatrix(); } }//Use triangle faces ? }//if in limits x=xSave; y=ySave; z=zSave; }//for translation VFN_DEBUG_EXIT("ZScatterer::GLInitDisplayList():Symmetric#"<GetName()<<":"<InitRefParList(); mClockScatterer.Click(); } //Just change the functions which return the component list } else { if(true==mUseGlobalScattPow) { delete mpGlobalScattPow; mpGlobalScattPow=0; mUseGlobalScattPow=false; mScattCompList.Reset(); for(long i=0;i<(mNbAtom-mNbDummyAtom);i++) ++mScattCompList; this->InitRefParList(); mClockScatterer.Click(); } } } void ZScatterer::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { // One group for all translation parameters, another for orientation. // All conformation parameters (bond, angle,torsion) are in individual groups. unsigned int posIndex=0; unsigned int orientIndex=0; VFN_DEBUG_MESSAGE("ZScatterer::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) { if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattTransl)) { if(posIndex==0) posIndex=first++; groupIndex(i)=posIndex; } else if(this->GetPar(j).GetType()->IsDescendantFromOrSameAs(gpRefParTypeScattOrient)) { if(orientIndex==0) orientIndex=first++; groupIndex(i)=orientIndex; } else groupIndex(i)= first++; } } const CrystVector_REAL& ZScatterer::GetXCoord() const { this->UpdateCoordinates(); return mXCoord; } const CrystVector_REAL& ZScatterer::GetYCoord() const { this->UpdateCoordinates(); return mYCoord; } const CrystVector_REAL& ZScatterer::GetZCoord() const { this->UpdateCoordinates(); return mZCoord; } void ZScatterer::EndOptimization() { if(mOptimizationDepth==1) { if(0!=mpZMoveMinimizer) delete mpZMoveMinimizer; mpZMoveMinimizer=0; } this->RefinableObj::EndOptimization(); } std::vector SplitString(const std::string &s) { const string delim(" "); std::vector v; string str=s; unsigned int ct=0; int n=str.find_first_of(delim); while( n != (int) str.npos) { ct++; if(n>0) { v.push_back(str.substr(0,n)); } str= str.substr(n+1); n=str.find_first_of(delim); } if(str.length() > 0) v.push_back(str); //cout<<"SplitString: "< "; //for(std::vector::const_iterator pos=v.begin();pos!=v.end();++pos) cout << *pos <<" / "; //cout< v=SplitString(sbuf); if(nb==1) {//First atom "C 1" if(v.size()>0) symbol=v[0]; else symbol=string(buf).substr(0,2); return; } if(nb==2) {//Second atom "C 1 1.450" if(v.size()==3) { symbol=v[0]; n1=(unsigned int) atoi(v[1].c_str()); v1=string2floatC(v[2]); } else { symbol=string(buf).substr(0,2); n1=(int) atoi(string(buf).substr(2,3).c_str()); v1=string2floatC(string(buf).substr(5,6)); } cout<<"ReadFHLine():"< '9') ) { cout<<"ZScatterer::ImportFenskeHallZMatrix()" <<":getting rid of first line..."<> nbAtoms; char c; while(!isgraph(is.peek())) is.get(c); // go to end of line // 17 //C 1 //N 1 1.465 //C 2 1.366 1 119.987 //N 3 1.321 2 120.030 1 6.0 //C 4 1.355 3 119.982 2 6.8 //N 5 1.136 4 180.000 3 46.3 //N 3 1.366 2 120.022 1 186.0 //C 7 1.466 3 119.988 2 354.9 // ... string symbol, atomName,bondAtomName,angleAtomName,dihedAtomName,junk; int bondAtom=0,angleAtom=0,dihedAtom=0; float bond=0,angle=0,dihed=0; int scattPow; //first if(named) { is >> atomName >> symbol >> junk; VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<<2<<",name:"<GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom",true); if(scattPow==-1) { cout<<"Scattering power"<AddScatteringPower(new ScatteringPowerAtom(symbol,symbol)); } scattPow=mpCryst->GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom"); if(named) this->AddAtom(atomName, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), 0,0, 0,0, 0,0); else { sprintf(buf,"%d",1); this->AddAtom(symbol+(string)buf, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), 0,0, 0,0, 0,0); } } //second if(named) { is >> atomName >> symbol >> bondAtomName >> bond; VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<<2<<",name:"<GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom",true); if(scattPow==-1) { cout<<"Scattering power"<AddScatteringPower(new ScatteringPowerAtom(symbol,symbol)); } scattPow=mpCryst->GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom"); if(named) { bondAtom=mZAtomRegistry.Find(bondAtomName); if(bondAtom<0) throw ObjCrystException(string("ZScatterer::ImportFenskeHallZMatrix:") +string("when adding atom ")+atomName+string(": could not find atom: ") +bondAtomName); this->AddAtom(atomName, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom,bond, 0,0, 0,0); } else { sprintf(buf,"%d",2); this->AddAtom(symbol+(string)buf, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom-1,bond, 0,0, 0,0); } } //third if(named) { is >> atomName >> symbol >> bondAtomName >> bond >> angleAtomName >> angle; VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<<2<<",name:"<GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom",true); if(scattPow==-1) { cout<<"Scattering power"<AddScatteringPower(new ScatteringPowerAtom(symbol,symbol)); } scattPow=mpCryst->GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom"); if(named) { VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<<3<<",name:"<AddAtom(atomName, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom,bond, angleAtom,angle*DEG2RAD, 0,0); } else { sprintf(buf,"%d",3); this->AddAtom(symbol+(string)buf, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom-1,bond, angleAtom-1,angle*DEG2RAD, 0,0); } } for(int i=3;i> atomName >> symbol >> bondAtomName >> bond >> angleAtomName >> angle >> dihedAtomName >> dihed; VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom",true); if(scattPow==-1) { cout<<"Scattering power"<AddScatteringPower(new ScatteringPowerAtom(symbol,symbol)); } scattPow=mpCryst->GetScatteringPowerRegistry().Find (symbol,"ScatteringPowerAtom"); if(named) { bondAtom=mZAtomRegistry.Find(bondAtomName); angleAtom=mZAtomRegistry.Find(angleAtomName); dihedAtom=mZAtomRegistry.Find(dihedAtomName); VFN_DEBUG_MESSAGE("ZScatterer::ImportFenskeHallZMatrix():#"<AddAtom(atomName, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom,bond, angleAtom,angle*DEG2RAD, dihedAtom,dihed*DEG2RAD); } else { sprintf(buf,"%d",i+1); this->AddAtom(symbol+(string)buf, &(mpCryst->GetScatteringPowerRegistry().GetObj(scattPow)), bondAtom-1,bond, angleAtom-1,angle*DEG2RAD, dihedAtom-1,dihed*DEG2RAD); } } } this->SetLimitsRelative(gpRefParTypeScattConformBondLength,-.03,.03); this->SetLimitsRelative(gpRefParTypeScattConformBondAngle,-.01,.01); this->SetLimitsRelative(gpRefParTypeScattConformDihedAngle,-.01,.01); } void ZScatterer::ExportFenskeHallZMatrix(ostream &os) { if(mNbAtom<1) return; os << mNbAtom<GetZAtomRegistry().GetObj(0).mpScattPow->GetName() << " 1"<GetZAtomRegistry().GetObj(1).mpScattPow->GetName() << " "<GetZBondAtom(1)+1<< " "<GetZBondLength(1) <GetZAtomRegistry().GetObj(2).mpScattPow->GetName() << " "<GetZBondAtom(2)+1 << " "<GetZBondLength(2) << " "<GetZAngleAtom(2)+1<< " "<GetZAngle(2)*RAD2DEG <GetZAtomRegistry().GetObj(i).mpScattPow->GetName() << " "<GetZBondAtom(i)+1 << " "<GetZBondLength(i) << " "<GetZAngleAtom(i)+1<< " "<GetZAngle(i)*RAD2DEG << " "<GetZDihedralAngleAtom(i)+1<< " "<GetZDihedralAngle(i)*RAD2DEG <::const_iterator ZScatterer::begin() const { return mZAtomRegistry.begin(); } vector::const_iterator ZScatterer::end() const { return mZAtomRegistry.end(); } void ZScatterer::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; VFN_DEBUG_ENTRY("ZScatterer::GlobalOptRandomMove()",3) TAU_PROFILE("ZScatterer::GlobalOptRandomMove()","void ()",TAU_DEFAULT); // give a 2% chance of either moving a single atom, or move // all atoms before a given torsion angle. // Only try this if there are more than 10 atoms (else it's not worth the speed cost) if((mNbAtom>=10) && ((rand()/(REAL)RAND_MAX)<.02) && (gpRefParTypeScattConform->IsDescendantFromOrSameAs(type)))//.01 { TAU_PROFILE_TIMER(timer1,\ "ZScatterer::GlobalOptRandomMoveSmart1(prepare ref par & mutate)"\ ,"", TAU_FIELD); TAU_PROFILE_TIMER(timer2,\ "ZScatterer::GlobalOptRandomMoveSmart2(optimize if necessary)"\ ,"", TAU_FIELD); TAU_PROFILE_START(timer1); // Do we have *any* dihedral angle to really move ? CrystVector_long dihed(mNbAtom); dihed=0; int nbDihed=0; RefinablePar *par; dihed(nbDihed++)=2;//This is the Psi angle, in fact. Should Chi be added, too ? for(int i=3;iGetPar(&(mZAtomRegistry.GetObj(i).mDihed))); if( !(par->IsFixed()) ) //&& !(par->IsLimited()) dihed(nbDihed++)=i; } if(nbDihed<2) //Can't play :-( { mRandomMoveIsDone=false; this->RefinableObj::GlobalOptRandomMove(mutationAmplitude); TAU_PROFILE_STOP(timer1); VFN_DEBUG_EXIT("ZScatterer::GlobalOptRandomMove():End",3) return; } // Build mpZMoveMinimizer object if(0==mpZMoveMinimizer) { mpZMoveMinimizer=new ZMoveMinimizer(*this); // copy all parameters (and not reference them, we will change the fix status.. // we could remove all popu parameters... for(int i=0; iGetNbPar();i++) mpZMoveMinimizer->AddPar(this->GetPar(i)); } // Pick one to move and get the relevant parameter // (maybe we should random-move also the associated bond lengths an angles, // but for now we'll concentrate on dihedral (torsion) angles. const int atom=dihed((int) (rand()/((REAL)RAND_MAX+1)*nbDihed)); //cout<GetPar(&mPsi)); else par=&(this->GetPar(&(mZAtomRegistry.GetObj(atom).mDihed))); VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove(): initial value:"<GetHumanValue() ,3) // Record the current conformation mpZMoveMinimizer->RecordConformation(); // Set up const int moveType= rand()%3; mpZMoveMinimizer->FixAllPar(); REAL x0,y0,z0; //cout << " Move Type:"<GetZBondAtom(atom)) ||(i==this->GetZAngleAtom(atom)) ||(i==this->GetZDihedralAngleAtom(atom)) ||(atom==this->GetZBondAtom(i)) ||(atom==this->GetZAngleAtom(i)) ||(atom==this->GetZDihedralAngleAtom(i))) { if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mBondLength)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mBondLength)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mAngle)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mAngle)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mDihed)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mDihed)).SetIsFixed(false); } if(!(this->GetPar(&mPhi).IsFixed())) mpZMoveMinimizer->GetPar(&mPhi).SetIsFixed(false); if(!(this->GetPar(&mChi).IsFixed())) mpZMoveMinimizer->GetPar(&mChi).SetIsFixed(false); if( !(this->GetPar(&mPsi).IsFixed()) && (atom!=2)) mpZMoveMinimizer->GetPar(&mPsi).SetIsFixed(false); if(!(this->GetPar(&mXYZ(0)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(0)).SetIsFixed(false); if(!(this->GetPar(&mXYZ(1)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(1)).SetIsFixed(false); if(!(this->GetPar(&mXYZ(2)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(2)).SetIsFixed(false); break; } case 1:// (1) Try to move the atoms *before* the rotated bond { VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove():Move before the rotated bond",3) const int atom1=this->GetZBondAtom(atom); const int atom2=this->GetZAngleAtom(atom); weight=0; weight(atom1)=1; for(int i=0;iGetZBondAtom(i))>.1) weight(i)=1; weight(atom2)=1; for(int i=0;iGetZAngleAtom(i)) &&(atom1 !=this->GetZBondAtom(i)) &&(i != atom) ) { if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mBondLength)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mBondLength)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mAngle)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mAngle)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(i).mDihed)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(i).mDihed)).SetIsFixed(false); } if(!(this->GetPar(&mPhi).IsFixed())) mpZMoveMinimizer->GetPar(&mPhi).SetIsFixed(false); if(!(this->GetPar(&mChi).IsFixed())) mpZMoveMinimizer->GetPar(&mChi).SetIsFixed(false); if( !(this->GetPar(&mPsi).IsFixed()) && (atom!=2)) mpZMoveMinimizer->GetPar(&mPsi).SetIsFixed(false); if(!(this->GetPar(&mXYZ(0)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(0)).SetIsFixed(false); if(!(this->GetPar(&mXYZ(1)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(1)).SetIsFixed(false); if(!(this->GetPar(&mXYZ(2)).IsFixed())) mpZMoveMinimizer->GetPar(&mXYZ(2)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(atom).mBondLength)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(atom).mBondLength)).SetIsFixed(false); if(!(this->GetPar(&(mZAtomRegistry.GetObj(atom).mAngle)).IsFixed())) mpZMoveMinimizer->GetPar(&(mZAtomRegistry.GetObj(atom).mAngle)).SetIsFixed(false); break; } case 2:// (2) Try to move the atoms *after* the rotated bond { if(mCenterAtomIndex>=atom) { VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove():Move after the bond (translate)",3) x0=this->GetXCoord()(0); y0=this->GetYCoord()(0); z0=this->GetZCoord()(0); } else { VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove():Move after the bond(nothing to do)",3) } break; } } // Move it, and with some probability use flipping to some // not-so-random angles., and then minimize the conformation change mpZMoveMinimizer->SetZAtomWeight(weight); REAL change; if( (rand()%5)==0) { switch(rand()%5) { case 0: change=-120*DEG2RAD;break; case 1: change= -90*DEG2RAD;break; case 2: change= 90*DEG2RAD;break; case 3: change= 120*DEG2RAD;break; default:change= 180*DEG2RAD;break; } } else { change= par->GetGlobalOptimStep() *2*(rand()/(REAL)RAND_MAX-0.5)*mutationAmplitude*16; } TAU_PROFILE_STOP(timer1); VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove(): mutation:"<Mutate(change); if(2==moveType) { if(mCenterAtomIndex>=atom) { this->UpdateCoordinates(); x0 -= this->GetXCoord()(0); y0 -= this->GetYCoord()(0); z0 -= this->GetZCoord()(0); mpCryst->OrthonormalToFractionalCoords(x0,y0,z0); this->GetPar(mXYZ.data()).Mutate(x0); this->GetPar(mXYZ.data()+1).Mutate(y0); this->GetPar(mXYZ.data()+2).Mutate(z0); } } else { const REAL tmp=mpZMoveMinimizer->GetLogLikelihood(); if(tmp>.05) { TAU_PROFILE_START(timer2); if(tmp<1) mpZMoveMinimizer->MinimizeChange(100); else if(tmp<5) mpZMoveMinimizer->MinimizeChange(200); else mpZMoveMinimizer->MinimizeChange(500); TAU_PROFILE_STOP(timer2); } } VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove(): final value:"<GetHumanValue(),3) // } #if 0 { // find unfixed, dihedral angles to play with //unlimited? CrystVector_long dihed(mNbAtom); dihed=0; int nbDihed=0; RefinablePar *par; dihed(nbDihed++)=2; for(int i=3;iGetPar(&(mZAtomRegistry.GetObj(i).mDihed))); if( !(par->IsFixed()) ) //&& !(par->IsLimited()) dihed(nbDihed++)=i; } if(nbDihed<2) //Can't play :-( this->RefinableObj::GlobalOptRandomMove(mutationAmplitude); // Pick one const int atom=dihed((int) (rand()/((REAL)RAND_MAX+1)*nbDihed)); VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove(): "<(dihed) ,10) VFN_DEBUG_MESSAGE("ZScatterer::GlobalOptRandomMove(): Changing atom #"<GetPar(&mPsi)); else par=&(this->GetPar(&(mZAtomRegistry.GetObj(atom).mDihed))); // Get the old value const REAL old=par->GetValue(); // Move it, with a max amplitude 8x greater than usual if( (rand()/(REAL)RAND_MAX)<.1) {// give some probability to use certain angles: -120,-90,90,120,180 switch(rand()%5) { case 0: par->Mutate(-120*!DEG2RAD);break; case 1: par->Mutate( -90*!DEG2RAD);break; case 2: par->Mutate( 90*!DEG2RAD);break; case 3: par->Mutate( 120*!DEG2RAD);break; default:par->Mutate( 180*!DEG2RAD);break; } } else par->Mutate( par->GetGlobalOptimStep() *2*(rand()/(REAL)RAND_MAX-0.5)*mutationAmplitude*8); const REAL change=mZAtomRegistry.GetObj(atom).GetZDihedralAngle()-old; // Now move all atoms using this changed bond as a reference //const int atom2= mZAtomRegistry.GetObj(atom).GetZAngleAtom(); for(int i=atom;iGetPar(&(mZAtomRegistry.GetObj(i).mDihed)).Mutate(-change); if(mZAtomRegistry.GetObj(i).GetZAngleAtom()==atom) this->GetPar(&(mZAtomRegistry.GetObj(i).mDihed)).Mutate(-change); //cout <<"ZScatterer::GlobalOptRandomMove:"<(dihed,4) // <RefinableObj::GlobalOptRandomMove(mutationAmplitude,type); } mRandomMoveIsDone=true; VFN_DEBUG_EXIT("ZScatterer::GlobalOptRandomMove():End",3) } void ZScatterer::UpdateCoordinates() const { if(mClockCoord>mClockScatterer) return; VFN_DEBUG_ENTRY("ZScatterer::UpdateCoordinates():"<GetName(),3) TAU_PROFILE("ZScatterer::UpdateCoordinates()","void ()",TAU_DEFAULT); //if(0==mNbAtom) throw ObjCrystException("ZScatterer::Update() No Atoms in Scatterer !"); if(0==mNbAtom) return; { CrystMatrix_REAL phiMatrix(3,3),chiMatrix(3,3),psiMatrix(3,3); phiMatrix= cos(mPhi) , -sin(mPhi) , 0, sin(mPhi) , cos(mPhi) , 0, 0 ,0 ,1; chiMatrix= cos(mChi) ,0 ,-sin(mChi), 0 ,1 ,0, sin(mChi) ,0 ,cos(mChi); psiMatrix= 1 , 0 , 0, 0 ,cos(mPsi) ,-sin(mPsi), 0 ,sin(mPsi) ,cos(mPsi); mPhiChiPsiMatrix=product(chiMatrix,product(phiMatrix,psiMatrix)); //cout << phiMatrix <Atom #0:"<1) {// Atom 1 mXCoord(1)=GetZBondLength(1); mYCoord(1)=0.; mZCoord(1)=0.; VFN_DEBUG_MESSAGE("->Atom #1:"<2) {// Atom 2 if(0==GetZBondAtom(2)) //Linked with Atom 1 mXCoord(2)=GetZBondLength(2)*cos(GetZAngle(2)); else //Linked with Atom 1 mXCoord(2)=mXCoord(1)-GetZBondLength(2)*cos(GetZAngle(2)); mYCoord(2)=GetZBondLength(2)*sin(GetZAngle(2)); mZCoord(2)=0.; VFN_DEBUG_MESSAGE("->Atom #2:"<3) { REAL xa,ya,za,xb,yb,zb,xd,yd,zd,cosph,sinph,costh,sinth,coskh,sinkh,cosa,sina; REAL xpd,ypd,zpd,xqd,yqd,zqd; REAL rbc,xyb,yza,tmp,xpa,ypa,zqa; int na,nb,nc; bool flag; REAL dist,angle,dihed; for(int i=3;i= 0.999999 ) { // Colinear mXCoord(i)=mXCoord(na)+cosa*dist*rbc*xb; mYCoord(i)=mYCoord(na)+cosa*dist*rbc*yb; mZCoord(i)=mZCoord(na)+cosa*dist*rbc*zb; VFN_DEBUG_MESSAGE("->Atom #"< 1e-5 ) { coskh = ypa/yza; sinkh = zqa/yza; ypd = coskh*yd - sinkh*zd; zpd = coskh*zd + sinkh*yd; } else { ypd = yd; zpd = zd; } xpd = cosph*xd - sinph*zpd; zqd = cosph*zpd + sinph*xd; xqd = costh*xpd - sinth*ypd; yqd = costh*ypd + sinth*xpd; if( true==flag ) { // Rotate about y-axis ? mXCoord(i)=mXCoord(na) - zqd; mYCoord(i)=mYCoord(na) + yqd; mZCoord(i)=mZCoord(na) + xqd; } else { mXCoord(i)=mXCoord(na) + xqd; mYCoord(i)=mYCoord(na) + yqd; mZCoord(i)=mZCoord(na) + zqd; } VFN_DEBUG_MESSAGE("->Atom #"<GetX(); y=this->GetY(); z=this->GetZ(); mpCryst->FractionalToOrthonormalCoords(x,y,z); const REAL x0=x-mXCoord(mCenterAtomIndex); const REAL y0=y-mYCoord(mCenterAtomIndex); const REAL z0=z-mZCoord(mCenterAtomIndex); for(int i=0;iGetName(),3) } void ZScatterer::UpdateScattCompList() const { VFN_DEBUG_ENTRY("ZScatterer::UpdateScattCompList()"<GetName(),3) this->UpdateCoordinates(); if( (mClockScattCompList>mClockCoord) &&(mClockScattCompList>mpCryst->GetClockLatticePar())) return; if(true==mUseGlobalScattPow) { mScattCompList(0).mX=mXYZ(0); mScattCompList(0).mY=mXYZ(1); mScattCompList(0).mZ=mXYZ(2); mScattCompList(0).mOccupancy=mOccupancy; mScattCompList(0).mpScattPow=mpGlobalScattPow; // Update central atom for Display. //mXCoord(mCenterAtomIndex)=this->GetX(); //mYCoord(mCenterAtomIndex)=this->GetY(); //mZCoord(mCenterAtomIndex)=this->GetZ(); //mpCryst->FractionalToOrthonormalCoords(mXCoord(mCenterAtomIndex), // mXCoord(mCenterAtomIndex), // mXCoord(mCenterAtomIndex)); mClockScattCompList.Click(); VFN_DEBUG_MESSAGE("ZScatterer::UpdateScattCompList()->Global Scatterer:End",3) return; } long j=0; REAL x,y,z; VFN_DEBUG_MESSAGE("ZScatterer::UpdateScattCompList(bool):Finishing"<OrthonormalToFractionalCoords(x,y,z); mScattCompList(j ).mX=x; mScattCompList(j ).mY=y; mScattCompList(j ).mZ=z; mScattCompList(j ).mpScattPow=mZAtomRegistry.GetObj(i).GetScatteringPower(); mScattCompList(j++).mOccupancy=mZAtomRegistry.GetObj(i).GetOccupancy()*mOccupancy; } } #ifdef __DEBUG__ if(gVFNDebugMessageLevel<3) mScattCompList.Print(); #endif mClockScattCompList.Click(); VFN_DEBUG_EXIT("ZScatterer::UpdateScattCompList()"<GetName(),3) } void ZScatterer::InitRefParList() { VFN_DEBUG_MESSAGE("ZScatterer::InitRefParList():"<GetName(),5) //throw ObjCrystException("ZScatterer::InitRefParList() not implemented! "+this->GetName()); //:TODO: this->ResetParList(); { RefinablePar tmp("x",&mXYZ(0),0.,1., gpRefParTypeScattTranslX, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("y",&mXYZ(1),0,1, gpRefParTypeScattTranslY, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("z",&mXYZ(2),0,1, gpRefParTypeScattTranslZ, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("Occupancy",&mOccupancy,0,1, gpRefParTypeScattOccup, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } if(false==mUseGlobalScattPow) { { RefinablePar tmp("Phi",&mPhi,0,2*M_PI, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("Chi",&mChi,0,2*M_PI, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { RefinablePar tmp("Psi",&mPsi,0,2*M_PI, gpRefParTypeScattOrient, REFPAR_DERIV_STEP_ABSOLUTE,false,false,true,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } char buf [20]; for(long i=0;iAddPar(tmp); } { sprintf(buf,"%d-%d-%d",(int)i,(int)(mZAtomRegistry.GetObj(i).GetZBondAtom()), (int)(mZAtomRegistry.GetObj(i).GetZAngleAtom())); RefinablePar tmp("Angle"+(string)buf, &(mZAtomRegistry.GetObj(i).mAngle),0,2*M_PI, gpRefParTypeScattConformBondAngle, REFPAR_DERIV_STEP_ABSOLUTE,false,false,usedAngle,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } { sprintf(buf,"%d-%d-%d-%d",(int)i,(int)(mZAtomRegistry.GetObj(i).GetZBondAtom()), (int)(mZAtomRegistry.GetObj(i).GetZAngleAtom()), (int)(mZAtomRegistry.GetObj(i).GetZDihedralAngleAtom())); RefinablePar tmp("Dihed"+(string)buf, &(mZAtomRegistry.GetObj(i).mDihed),0,2*M_PI, gpRefParTypeScattConformDihedAngle, REFPAR_DERIV_STEP_ABSOLUTE,false,false,usedDihed,true,RAD2DEG,2*M_PI); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } if(0!=mZAtomRegistry.GetObj(i).GetScatteringPower()) {//fixed by default sprintf(buf,"%d",(int)i); RefinablePar tmp("Occupancy"+(string)buf, &(mZAtomRegistry.GetObj(i).mOccupancy),0,1, gpRefParTypeScattOccup, REFPAR_DERIV_STEP_ABSOLUTE,true,true,true,false,1.,1.); tmp.AssignClock(mClockScatterer); this->AddPar(tmp); } } }//if(false==mUseGlobalScatteringPower) } #ifdef __WX__CRYST__ WXCrystObjBasic* ZScatterer::WXCreate(wxWindow* parent) { //:TODO: Check mpWXCrystObj==0 mpWXCrystObj=new WXZScatterer(parent,this); return mpWXCrystObj; } #endif //###################################################################### // // ZPolyhedron // // //###################################################################### ZPolyhedron::ZPolyhedron( const RegularPolyhedraType type,Crystal &cryst, const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *centralAtomSymbol, const ScatteringPower *periphAtomSymbol,const REAL centralPeriphDist, const REAL ligandPopu, const REAL phi, const REAL chi, const REAL psi): ZScatterer(name,cryst,x,y,z,phi,chi,psi),mPolyhedraType(type) { VFN_DEBUG_MESSAGE("ZPolyhedron::ZPolyhedron(..)",5) // Additioning string and char arrays takes a huge lot of mem (gcc 2.95.2) const string name_=name+"_"; const string name_central=name_+centralAtomSymbol->GetName(); const string name_periph=name_+periphAtomSymbol->GetName(); switch(mPolyhedraType) { case TETRAHEDRON : { REAL ang=2*asin(sqrt(2./3.)); this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 0,0., 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 0,0., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2, M_PI*2./3., 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,-M_PI*2./3., 1.); m3DDisplayIndex.resize(4,3); m3DDisplayIndex= 1,2,3, 1,2,4, 1,3,4, 2,3,4; break; } case OCTAHEDRON: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 0,0., 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 0,0., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,M_PI/2, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,-M_PI/2, 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,M_PI, 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI, 2,0., 1.); m3DDisplayIndex.resize(8,3); m3DDisplayIndex= 1,2,3, 1,2,4, 1,5,3, 1,5,4, 6,2,3, 6,2,4, 6,5,3, 6,5,4; break; } case SQUARE_PLANE: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom on top 0,1., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,M_PI/2, 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,M_PI, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,-M_PI/2, 1.); //:TODO: GL Display with squares //m3DDisplayIndex.resize(2,3); //m3DDisplayIndex= 2,4,2, // 2,4,5; break; } case CUBE: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom in middle of face 0,1., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,M_PI/2., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,M_PI, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,-M_PI/2., 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 0,0., 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI/2., 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI, 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI*3./2., 1.); break; } case ANTIPRISM_TETRAGONAL: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom in middle of face 0,1., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,M_PI/2., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,M_PI, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/4., 2,-M_PI/2., 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 0,M_PI/4., 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI*3./4., 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI*5./4., 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI*3./4., 2,M_PI*7./4., 1.); break; } case PRISM_TETRAGONAL_MONOCAP: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"0",periphAtomSymbol, 0,centralPeriphDist, 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,70*DEG2RAD, 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,70*DEG2RAD, 2,M_PI/2., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,70*DEG2RAD, 2,M_PI, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,70*DEG2RAD, 2,-M_PI/2., 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,145*DEG2RAD, 0,0., 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,145*DEG2RAD, 2,M_PI/2., 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 1,145*DEG2RAD, 2,M_PI, 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,145*DEG2RAD, 2,M_PI*3./2., 1.); break; } case PRISM_TETRAGONAL_DICAP: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"0",periphAtomSymbol, 0,centralPeriphDist, 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,60*DEG2RAD, 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,60*DEG2RAD, 2,M_PI/2., 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,60*DEG2RAD, 2,M_PI, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,60*DEG2RAD, 2,-M_PI/2., 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,120*DEG2RAD, 0,0., 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,120*DEG2RAD, 2,M_PI/2., 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 1,120*DEG2RAD, 2,M_PI, 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,120*DEG2RAD, 2,M_PI*3./2., 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI, 2,0., 1.); break; } case PRISM_TRIGONAL: { const REAL ang=55.*DEG2RAD; const REAL ang2=120.*DEG2RAD; this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom in middle of top face 0,1., 0,0., 0,0., 0.); this ->AddAtom (name_periph+"0",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,ang2, 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,-ang2, 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 0,0., 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 2,ang2, 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 2,-ang2, 1.); break; } case PRISM_TRIGONAL_TRICAPPED: { const REAL ang=55.*DEG2RAD; const REAL ang2=120.*DEG2RAD; this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom in middle of top face 0,1., 0,0., 0,0., 0.); this ->AddAtom (name_periph+"0",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,ang2, 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,-ang2, 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 0,0., 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 2,ang2, 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI-ang, 2,-ang2, 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2., 2,M_PI, 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2., 2,M_PI/3., 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2., 2,-M_PI/3., 1.); break; } case ICOSAHEDRON: { const REAL ang=acos(sqrt(.2)); const REAL ang2=M_PI*2./5.; this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"0",periphAtomSymbol, 0,centralPeriphDist, 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 1,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,ang2, 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,2*ang2, 1.); this ->AddAtom (name_periph+"4",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,-2*ang2, 1.); this ->AddAtom (name_periph+"5",periphAtomSymbol, 0,centralPeriphDist, 1,ang, 2,-ang2, 1.); this ->AddAtom (name_periph+"6",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI, 0,0., 1.); this ->AddAtom (name_periph+"7",periphAtomSymbol, 0,centralPeriphDist, 7,ang, 3,M_PI, 1.); this ->AddAtom (name_periph+"8",periphAtomSymbol, 0,centralPeriphDist, 7,ang, 8,ang2, 1.); this ->AddAtom (name_periph+"9",periphAtomSymbol, 0,centralPeriphDist, 7,ang, 8,2*ang2, 1.); this ->AddAtom (name_periph+"10",periphAtomSymbol, 0,centralPeriphDist, 7,ang, 8,-2*ang2, 1.); this ->AddAtom (name_periph+"11",periphAtomSymbol, 0,centralPeriphDist, 7,ang, 8,-ang2, 1.); break; } case TRIANGLE_PLANE: { this ->AddAtom (name_central, centralAtomSymbol, 0,0., 0,0., 0,0., 1.); this ->AddAtom (name+"_X",0, //Dummy atom on top 0,1., 0,0., 0,0., 1.); this ->AddAtom (name_periph+"1",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 0,0., 1.); this ->AddAtom (name_periph+"2",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,2*M_PI/3, 1.); this ->AddAtom (name_periph+"3",periphAtomSymbol, 0,centralPeriphDist, 1,M_PI/2, 2,-2*M_PI/3, 1.); //:TODO: GL Display with squares //m3DDisplayIndex.resize(2,3); //m3DDisplayIndex= 2,4,2, // 2,4,5; break; } default : throw ObjCrystException("ZPolyhedron::ZPolyhedron():Unknown Polyhedra type !"); } //We want to keep an approximate geometry //this->RefinableObj::Print(); this->SetLimitsRelative(gpRefParTypeScattConformBondLength,-.2,.2); this->SetLimitsRelative(gpRefParTypeScattConformBondAngle ,-.2,.2); this->SetLimitsRelative(gpRefParTypeScattConformDihedAngle,-.2,.2); //this->RefinableObj::Print(); VFN_DEBUG_MESSAGE("ZPolyhedron::ZPolyhedron():End:"<Init(scatt); } GlobalScatteringPower::GlobalScatteringPower(const GlobalScatteringPower& old):mpZScatterer(0) { VFN_DEBUG_MESSAGE("GlobalScatteringPower::GlobalScatteringPower(&old):"<Init(*(old.mpZScatterer)); } GlobalScatteringPower::~GlobalScatteringPower() { VFN_DEBUG_MESSAGE("GlobalScatteringPower::~GlobalScatteringPower():"<SetName(scatt.GetName()+(string)"_Global"); VFN_DEBUG_MESSAGE("GlobalScatteringPower::Init(&Scatt):"<SetUseGlobalScatteringPower(false); mpZScatterer->SetName(scatt.GetName()+"_GlobalCopy"); //Set the DynPopCorrIndex to the sum of the DynPopCorrIndexs (eg the sum of atomic numbers) mDynPopCorrIndex=0; const ScatteringComponentList* tmp=&(mpZScatterer->GetScatteringComponentList()); for(long i=0;iGetNbComponent();i++) mDynPopCorrIndex += (*tmp)(i).mpScattPow->GetDynPopCorrIndex(); } CrystVector_REAL GlobalScatteringPower:: GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex) const { // Here comes the hard work VFN_DEBUG_MESSAGE("GlobalScatteringPower::GetScatteringFactor():"<SetCrystal(cryst); pData->SetName("GlobalScatteringPowerData!"); VFN_DEBUG_MESSAGE("GlobalScatteringPower::GetScatteringFactor():No DEBUG Messages",5) VFN_DEBUG_LOCAL_LEVEL(10) const long nbStep=4;//number of steps over 90 degrees for phi,chi psi REAL norm=0; for(int i=-nbStep;i<=nbStep;i++) { mpZScatterer->SetChi(i*M_PI/2/nbStep); for(int j=-nbStep;j<=nbStep;j++) { mpZScatterer->SetPhi(j*M_PI/2/nbStep); for(int k=-nbStep;k<=nbStep;k++) { //cout <SetPsi(k*M_PI/2/nbStep); rsf=pData->GetFhklCalcReal(); rsf*=rsf; isf=pData->GetFhklCalcImag(); isf*=isf; rsf+=isf; rsf=sqrt(rsf); //correct for the solid angle (dChi*dPhi) corresponding to this orientation rsf*= cos(mpZScatterer->GetPhi());//:TODO: needs checking !!! norm += cos(mpZScatterer->GetPhi()); sf += rsf; } } //cout << FormatHorizVector(sf) <GetScatteringComponentList()); for(int i=0;iGetNbComponent();i++) sf += (*pList)(i).mpScattPow->GetForwardScatteringFactor(type); return sf; } CrystVector_REAL GlobalScatteringPower:: GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex) const { VFN_DEBUG_MESSAGE("GlobalScatteringPower::GetTemperatureFactor(data):"< namespace ObjCryst { class ZScatterer; //###################################################################### // // GLOBAL SCATTERING POWER /** * \brief Global Scattering Power. Used to approximate the scattering * power of a multi-atom ZScatterer (polyhedron,...) to an isotropic * scattering power. * * The scattering power will be (\b slowly) approximated to the average * scattering power of this ZScatterer take in all orientations. * The approximated scattering factor will include the temperature factor * and resonant scattering factors contributions. * * This is only used in ZScatterer, and maybe obsolete (?). */ //###################################################################### class GlobalScatteringPower:virtual public ScatteringPower { public: GlobalScatteringPower(); GlobalScatteringPower(const ZScatterer &scatt); GlobalScatteringPower(const GlobalScatteringPower& old); ~GlobalScatteringPower(); /// Re-initialize parameters (after using the default constructor). void Init(const ZScatterer &scatt); virtual CrystVector_REAL GetScatteringFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual REAL GetForwardScatteringFactor(const RadiationType) const; virtual CrystVector_REAL GetTemperatureFactor(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactReal(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual CrystMatrix_REAL GetResonantScattFactImag(const ScatteringData &data, const int spgSymPosIndex=0) const; virtual REAL GetRadius()const; protected: virtual void InitRefParList(); /// a copy of the ZScatterer associated to this object ZScatterer *mpZScatterer; private: // Avoid compiler warnings. Explicitly hide the base-class method. void Init(); }; //###################################################################### /// Class for individual atoms in a ZScatterer Object. This class /// is \e purely \e internal to ZScatterer, so should not be used /// for any other purpose... //###################################################################### class ZAtom { public: ZAtom(ZScatterer &scatt,const ScatteringPower *pow, const long atomBond=0, const REAL bondLength=1, const long atomAngle=0, const REAL bondAngle=M_PI, const long atomDihedral=0, const REAL dihedralAngle=M_PI, const REAL popu=1., const string &name=""); ~ZAtom(); const string& GetClassName()const; const string& GetName()const; void SetName(const string&); /// Get the ZScatterer associated to this ZAtom const ZScatterer& GetZScatterer()const; /// Get the ZScatterer associated to this ZAtom ZScatterer& GetZScatterer(); /// Index of the 1st atom used to define the atom in the Z-Matrix (the one from /// which the bondlength is calculated) long GetZBondAtom()const; /// Index of the 2nd atom used to define the atom in the Z-Matrix (the one from /// which the angle is calculated) long GetZAngleAtom()const; /// Index of the 3rd atom used to define the atom in the Z-Matrix (the one from /// which the dihedral angle is calculated) long GetZDihedralAngleAtom()const; ///Const access to bondlength parameter. const REAL& GetZBondLength()const; ///Const access to the angle parameter. const REAL& GetZAngle()const; ///Const access to the dihedral angle parameter. const REAL& GetZDihedralAngle()const; ///Const access to the ocupancy parameter. const REAL& GetOccupancy()const; ///ScatteringPower for this atom. const ScatteringPower* GetScatteringPower()const; ///Access to bondlength parameter. void SetZBondLength(const REAL); ///Access to the angle parameter. void SetZAngle(const REAL); ///Access to the dihedral angle parameter. void SetZDihedralAngle(const REAL); ///Access to the dihedral angle parameter. void SetOccupancy(const REAL); ///Set the ScatteringPower. void SetScatteringPower(const ScatteringPower*); void XMLOutput(ostream &os,int indent=0)const; void XMLInput(istream &is,const XMLCrystTag &tag); private: /// The ScatteringPower corresponding to this atom. const ScatteringPower *mpScattPow; /// The index (in the ZScatterer) of the atoms which are used to define the /// position of this atom. long mAtomBond,mAtomAngle,mAtomDihed; /// Bond length, angle and dihedral angle. REAL mBondLength,mAngle,mDihed,mOccupancy; /// Name for this atom string mName; /// the ZScatterer in which this atom is included. ZScatterer *mpScatt; friend class ZScatterer; //So that RefinablePar can be declared in ZScatterer #ifdef __WX__CRYST__ public: WXCrystObjBasic* WXCreate(wxWindow *parent); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); private: WXCrystObjBasic *mpWXCrystObj; friend class WXZAtom; #endif }; //###################################################################### /** \brief Class to minimize conformation changes for random moves. Very * experimental !!! * \internal Only used within ZScatterer. */ //###################################################################### class ZMoveMinimizer:public RefinableObj { public: ZMoveMinimizer(ZScatterer &scatt); ~ZMoveMinimizer(); virtual REAL GetLogLikelihood()const; void RecordConformation(); void SetZAtomWeight(const CrystVector_REAL weight); void MinimizeChange(long nbTrial=10000); private: ZScatterer *mpZScatt; MonteCarloObj mOptimObj; CrystVector_REAL mXCoord0,mYCoord0,mZCoord0; CrystVector_REAL mAtomWeight; }; //###################################################################### /// ZScatterer: the basic type of complex scatterers, where atom positions /// are defined using a standard "Z-Matrix" description. This is used /// to describe inorganic polyhedras, as well as molecules. //###################################################################### class ZScatterer: public Scatterer { public: /** \brief ZScatterer constructor * * \param name: the name of the scatterer * \param cryst: the crystal in which the scatterer is (needed to convert * from cartesian to fractionnal coordinates). * \param x,y,z: fractionnal coordinates of the scatterer * \param phi,chi: angles defining the orientation of the scatterer */ ZScatterer(const string &name,Crystal &cryst, const REAL x=0.,const REAL y=0.,const REAL z=0., const REAL phi=0.,const REAL chi=0., const REAL psi=0.); /** \brief Copy constructor * */ ZScatterer(const ZScatterer &old); ~ZScatterer(); /// \internal so-called Virtual copy constructor, needed to make copies /// of arrays of Scatterers virtual ZScatterer* CreateCopy() const; virtual const string& GetClassName() const; /// Add an atom to the Zscatterer. If &ScatteringPower=0, then it is a 'dummy' /// atom and will be ignored for any scattering analysis. The 'name' supplied may /// not be respected, and can be replaced by 'ZScatterer_name'+'AtomNum'+'ScattPowName' void AddAtom(const string &name,const ScatteringPower *pow, const long atomBond, const REAL bondLength, const long atomAngle, const REAL bondAngle, const long atomDihedral, const REAL dihedralAngle, const REAL popu=1.); virtual int GetNbComponent() const; virtual const ScatteringComponentList& GetScatteringComponentList() const; virtual string GetComponentName(const int i) const; ///Print a single line of information about this scatterer void Print() const; ///Access to phi parameter (overall orientation of the scatterer) REAL GetPhi()const; ///Access to chi parameter (overall orientation of the scatterer) REAL GetChi()const; ///Access to psi parameter (overall orientation of the scatterer) REAL GetPsi()const; ///Access to phi parameter (overall orientation of the scatterer) void SetPhi(const REAL); ///Access to chi parameter (overall orientation of the scatterer) void SetChi(const REAL); ///Access to psi parameter (overall orientation of the scatterer) void SetPsi(const REAL); /// Get the X fractionnal coordinate of atom i REAL GetZAtomX(const int i)const; /// Get the Y fractionnal coordinate of atom i REAL GetZAtomY(const int i)const; /// Get the Z fractionnal coordinate of atom i REAL GetZAtomZ(const int i)const; /// Index of the 1st atom used to define the i-th atom in the Z-Matrix (the one from /// which the bondlength is calculated) long GetZBondAtom(const int i)const; /// Index of the 2nd atom used to define the i-th atom in the Z-Matrix (the one from /// which the angle is calculated) long GetZAngleAtom(const int i)const; /// Index of the 3rd atom used to define the i-th atom in the Z-Matrix (the one from /// which the dihedral angle is calculated) long GetZDihedralAngleAtom(const int i)const; ///Const access to bondlength parameter, for the i-th row in the Z-Matrix. REAL GetZBondLength(const int i)const; ///Const access to the angle parameter, for the i-th row in the Z-Matrix. REAL GetZAngle(const int i)const; ///Const access to the dihedral angle parameter, for the i-th row in the Z-Matrix. REAL GetZDihedralAngle(const int i)const; ///Access to bondlength parameter, for the i-th row in the Z-Matrix. void SetZBondLength(const int i,const REAL); ///Access to the angle parameter, for the i-th row in the Z-Matrix. void SetZAngle(const int i,const REAL); ///Access to the dihedral angle parameter, for the i-th row in the Z-Matrix. void SetZDihedralAngle(const int i,const REAL); ///Access to the registry of ZAtoms const ObjRegistry& GetZAtomRegistry()const; /// \warning Not implemented for ZScatterer virtual ostream& POVRayDescription(ostream &os, const CrystalPOVRayOptions &options)const; #ifdef OBJCRYST_GL virtual void GLInitDisplayList(const bool onlyIndependentAtoms=false, const REAL xMin=-.1,const REAL xMax=1.1, const REAL yMin=-.1,const REAL yMax=1.1, const REAL zMin=-.1,const REAL zMax=1.1, const bool displayEnantiomer=false, const bool displayNames=false, const bool hideHydrogens=false, const REAL fadeDistance=0, const bool fullMoleculeInLimits=false)const; #endif // OBJCRYST_GL /** \brief use a Global scattering power for this scatterer ? * * If true, then the overall scattering power of this ZScatterer will be * approximated to an isotropic scattering power computed for this scatterer. * Of course, only use this if the "isotropic" approximation is reasonable for * this scatterer (typically true for 'large' polyhedra). See GlobalScatteringPower. * * \warning EXPERIMENTAL */ virtual void SetUseGlobalScatteringPower(const bool useIt); virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); /// Get the list of all ZAtom cartesian x coordinates. const CrystVector_REAL& GetXCoord() const; /// Get the list of all ZAtom cartesian x coordinates. const CrystVector_REAL& GetYCoord() const; /// Get the list of all ZAtom cartesian x coordinates. const CrystVector_REAL& GetZCoord() const; virtual void EndOptimization(); /** Import "Fenske-Hall" ZMatrix file (fhz in the babel * program http://www.eyesopen.com/babel.html\ * example: use "./babel -ipdb foo.pdb -ofhz foo.fhz -d", * to convert a pdb file to a Z-Matrix file (the -d removes * hydrogen atoms) * * \param is: the input stream from which to read the z-matrix * \param names: if true, instead of reading a standard Fenske-Hall * z-matrix, the file will be read with names, i.e. with an added first * column with the names of the atoms, and the number used to reference * the bond, bond angle and dihedral angle atoms are replaced by the * names of the atoms. * * \warning: this should be called \e before any atom has been * added (if there are already atoms, they should be removed * but this has not been tested...) * * \note: this will search in the Crystal associated with this * ZScatterer the relevant ScatteringPowerAtom, which should have * the name of the corresponding symbol (eg 'H', 'C',...) * if these are not found then they will be added to the Crystal * with a default isotropic B-factor equal to 1. * \note: this also sets relative limits of +/-.03 Angstroems * for all bond distances, and +/-3.6 degress for bond and * dihedral angles. * \todo: identify which dihedral angles should \e not be limited, * by analysing a coordination table. */ void ImportFenskeHallZMatrix(istream &is,bool named=false); /** Export to Fenske-Hall ZMatrix file * * \todo USe more strict formatting than space-delimited. */ void ExportFenskeHallZMatrix(ostream &os); /// Set the index of the central atom (around which the rotation is made) void SetCenterAtomIndex(const unsigned int); /// Get the index of the central atom (around which the rotation is made) unsigned int GetCenterAtomIndex()const; /** STL access to registry of Zatom size */ std::size_t size() const; /** low-level access to the underlying vector of ZAtom begin(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. */ vector::const_iterator begin() const; /** low-level access to the underlying vector of ZAtom end(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. */ vector::const_iterator end() const; protected: /** Update the atom coordinates (in real units, in Angstroems). * * This takes into account the translation and global * rotation of the scatterer (ie this does not generate 'internal * coordinates). */ void UpdateCoordinates() const; /** Update the scattering component list, ie compute all atom * positions from the bonds/angles/dihedral angles, and convert * the coordinates to fractionnal coordinates of the Crystal. * * */ void UpdateScattCompList() const; /** For 3D display of the structure, bonds, triangular and quadric * faces can be displayed. This matrix determines what is drawn. * This is a 5-column matrix. The first column indicates the type of * drawing (0: : nothing, 1: display the atom (a sphere), 2: bond, * 3: triangular face, 4: quadric face) * the other columns indicate the index of the atoms involved in the * drawing (2 atoms for a bond, 3 for....) * * If the matrix is empty only the individual atoms are displayed. * * \todo This is still experimental. This is only used for the display * of ZPolyhedron, and should be more developped (and it should also * be saved in XML files !) */ CrystMatrix_long m3DDisplayIndex; /// The list of scattering components. mutable ScatteringComponentList mScattCompList; ///Total number of atoms in the structure long mNbAtom; private: ///Prepare refinable parameters for the scatterer object virtual void InitRefParList(); ///Number of "dummy" atoms in the structure long mNbDummyAtom; /// Index of atoms in the ScatteringComponentList. We need this list because /// Dummy atoms are not included in it. So this is an integer array with /// [ 0 1 2 4 5 6].. where the missing '3' marks a Dummy atom. Thus /// to get the name of component 'i' in the component list, you must /// take the mComponentIndex(i) atom in the ZAtom Registry. CrystVector_int mComponentIndex; /** \brief Angles giving the orientation of the ZScatterer (stored in radian) * * The position of any atom can be transformed from internal coordinates (orthonormal * coordinates derived from the ZMatrix, with first atom at (0,0,0), second * atom at (x,0,0), third atom at (x,y,0),...) to orthonormal coordinates in * the crystal reference frame (ie with orientation of the ZScatterer) using : * \f[ \left[ \begin{array}{c} x(i) \\ y(i) \\ z(i) \end{array} \right]_{orthonormal} = \left[ \begin{array}{ccc} \cos(\chi) & 0 & -\sin(\chi) \\ 0 & 1 & 0 \\ \sin(\chi) & 0 & \cos(\chi) \end{array} \right] \times \left[ \begin{array}{ccc} \cos(\phi) & -\sin(\phi) & 0 \\ \sin(\phi) & \cos(\phi) & 0 \\ 0 & 0 & 1 \end{array} \right] \times \left[ \begin{array}{ccc} 1 & 0 & 0 \\ 0 & \cos(\psi) & -\sin(\psi) \\ 0 & \sin(\psi) & \cos(\psi) \end{array} \right] \times \left[ \begin{array}{c} x_0(i) \\ y_0(i) \\ z_0(i) \end{array} \right] * \f] *, where x0(i), y0(i) and z0(i) describe the position for atom (i) in * internal coordinates, and x(i), y(i), z(i) are coordinates of the rotated ZScatterer. * * * The rotation is performed around a 'pivot' atom (see ZScatterer::mPivotAtom) */ REAL mPhi,mChi,mPsi; /// Registry for ZAtoms in this Scatterer. ObjRegistry mZAtomRegistry; /// Index of the atom used as a pivot (the scatterer is rotated around this atom). /// This should more or less be at the center of the Scatterer. long mCenterAtomIndex; /// Rotation matrix for the orientation of the scatterer mutable CrystMatrix_REAL mPhiChiPsiMatrix; /// Does the ZScatterer use a global scattering power ? /// \warning EXPERIMENTAL. bool mUseGlobalScattPow; /// the global scattering power used, if mUseGlobalScattPow=true /// \warning EXPERIMENTAL. GlobalScatteringPower* mpGlobalScattPow; /// Storage for Cartesian coordinates. The (0,0,0) is on the central atom. This /// includes Dummy atoms. mutable CrystVector_REAL mXCoord,mYCoord,mZCoord; /// Last time the cartesian coordinates were computed mutable RefinableObjClock mClockCoord; ZMoveMinimizer *mpZMoveMinimizer; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); friend class WXZScatterer; #endif }; //###################################################################### // // Different types of regular polyhedra // //###################################################################### enum RegularPolyhedraType { TETRAHEDRON, OCTAHEDRON, SQUARE_PLANE, CUBE, ANTIPRISM_TETRAGONAL, PRISM_TETRAGONAL_MONOCAP, PRISM_TETRAGONAL_DICAP, PRISM_TRIGONAL,PRISM_TRIGONAL_TRICAPPED, ICOSAHEDRON, TRIANGLE_PLANE}; //###################################################################### /// \class ZPolyhedron include.h ObjCryst/ZScatterer.h /// /// ZPolyhedron: a Scatterer to describe polyhedras such as octahedron, /// tetrahedron, square plane, etc... These are ZScatterer objects, so that /// even if they are initialized with constraints, these can be removed /// to make any configuration. //###################################################################### class ZPolyhedron: public ZScatterer { public: /** \brief ZPolyhedron constructor * \param type : OCTAHEDRON, TETRAHEDRON,... * \param cryst : a crystal is necessary to transform the orthornormal * coordinates (in which the relative atom positions are computed) to fractional ones. * \param x,y,z : \e fractional coordinates of the center of the polyhedra * \param name : name of the Polyhedra ('WO6','TaSe4_a', 'Tetra01'...). * The name can have \e any format but spaces should be avoided, since it * will generate problems when reading the names from a file. And there must \b not * be identical name for two scatterers in a given crystal object. * \param periphAtomPow,centralAtomPow: the ScatteringPower corresponding to the * central and peripheral atoms, respectively. * \param centralPeriphDist: the distance, in angstroems, from the central * to the peripheral atoms * \param ligandPopu : the relative population of ligand atoms, equal to 1/n if * ligand atoms are shared by n polyhedra. If you are using the 'Dynamical Polpulation * Correction', then keep this parameter to 1. * \param phi,chi,psi: initial angles for this polyhedron */ ZPolyhedron( const RegularPolyhedraType type, Crystal &cryst, const REAL x, const REAL y, const REAL z, const string &name, const ScatteringPower *centralAtomPow, const ScatteringPower *periphAtomPow,const REAL centralPeriphDist, const REAL ligandPopu=1, const REAL phi=0., const REAL chi=0., const REAL psi=0.); /// Copy Constructor ZPolyhedron(const ZPolyhedron&); /// \internal so-called Virtual copy constructor, needed to make copies ///of arrays of Scatterers virtual ZPolyhedron* CreateCopy() const; /* \brief Copy constructor * ZPolyhedron(const ZPolyhedron &old); */ protected: private: //Prepare refinable parameters for the scatterer object //virtual void InitRefParList(); /// RegularPolyhedraType mPolyhedraType; }; }//namespace #include "ObjCryst/ObjCryst/Crystal.h" #endif //_OBJCRYST_ZSCATTERER_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/geomStructFactor.cpp000066400000000000000000000043231417150057700250450ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ //:NOTE: It may be a good idea to use a static array to compute the structure //factor, so that less time be spent in the construction of the array. //For example by using mutable member (assuming h,k and l's are always CrystVector_REAL), //:NOTE: Or the result could be returned in an array given as a parameter //NOTA BENE : normally, the formatting of the equations is the same as in //the Int. Tables for X-Ray Crystallography (1969) : one line of equation //should correspond to one line in the table, for easier check. #include "ObjCryst/CrystVector/CrystVector.h" namespace ObjCryst { void RealGeomStructFactor (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& rsf) { }; void ImagGeomStructFactor (const REAL x, const REAL y, const REAL z, const CrystVector_REAL&h, const CrystVector_REAL&k, const CrystVector_REAL&l, CrystVector_REAL& isf) { }; }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/geomStructFactor_001.cpp000066400000000000000000000052251417150057700254270ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ObjCryst/CrystVector/CrystVector.h" #ifdef __VFN_GEOM_STRUCT_FACTOR_USE_POINTERS #define H (*h) #define K (*k) #define L (*l) #define SF (*sf) #define __VFN_GEOM_STRUCT_FACTOR_POINTERS_INIT const REAL *h,*k,*l; REAL*sf;\ h=hh.data();k=kk.data();l=ll.data();sf=sfsf.data(); for(long i=0;i #include #include "ObjCryst/ObjCryst/test.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Atom.h" #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" #include "ObjCryst/ObjCryst/PowderPattern.h" #include "ObjCryst/RefinableObj/GlobalOptimObj.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" namespace ObjCryst { SpeedTestReport SpeedTest(const unsigned int nbAtom, const int nbAtomType,const string spacegroup, const RadiationType radiation, const unsigned long nbReflections, const unsigned int dataType,const REAL time) { Crystal cryst(9,11,15,1.2,1.3,1.7,spacegroup); for(int i=0;iSetWavelength(0.25); pDataTmp->SetRadiationType(radiation); pDataTmp->SetMaxSinThetaOvLambda(100.); pDataTmp->SetCrystal(cryst); float maxtheta=0.1; for(;;) { pDataTmp->GenHKLFullSpace(maxtheta, true); if(pDataTmp->GetNbRefl()>(long)nbReflections) break; maxtheta*=1.5; if(maxtheta>=M_PI/2.) break; } CrystVector_REAL hh; hh=pDataTmp->GetH();hh.resizeAndPreserve(nbReflections);hh+=0.0001; CrystVector_REAL kk; kk=pDataTmp->GetK();kk.resizeAndPreserve(nbReflections);kk+=0.0001; CrystVector_REAL ll; ll=pDataTmp->GetL();ll.resizeAndPreserve(nbReflections);ll+=0.0001; CrystVector_long h(nbReflections); h=hh; CrystVector_long k(nbReflections); k=kk; CrystVector_long l(nbReflections); l=ll; CrystVector_REAL iobs(nbReflections); for(unsigned int i=0;iSetHklIobs (h, k, l, iobs, sigma); pDataTmp->SetWeightToInvSigma2(); pData=pDataTmp; break; } case 1: { PowderPattern *pDataTmp=new PowderPattern; pDataTmp->SetWavelength(0.25); pDataTmp->SetRadiationType(radiation); pDataTmp->SetPowderPatternPar(0.001,.001,3140); CrystVector_REAL iobs(3140); for(unsigned int i=0;i<3140;++i) iobs(i)=(REAL)rand()+1.; pDataTmp->SetPowderPatternObs(iobs); pDataTmp->SetMaxSinThetaOvLambda(100.); PowderPatternBackground *backgdData= new PowderPatternBackground; backgdData->SetName("PbSo4-background"); { CrystVector_REAL tth(2),backgd(2); tth(0)=0.;tth(1)=3.14; backgd(0)=1.;backgd(1)=9.; backgdData->SetInterpPoints(tth,backgd); } pDataTmp->AddPowderPatternComponent(*backgdData); PowderPatternDiffraction * diffData=new PowderPatternDiffraction; diffData->SetCrystal(cryst); pDataTmp->AddPowderPatternComponent(*diffData); diffData->SetName("Crystal phase"); diffData->SetReflectionProfilePar(PROFILE_PSEUDO_VOIGT, .03*DEG2RAD*DEG2RAD,0.,0.,0.3,0); { float maxtheta=0.1; for(;;) { diffData->ScatteringData::GenHKLFullSpace(maxtheta, true); if(diffData->GetNbRefl()>(long)nbReflections) break; maxtheta*=1.5; if(maxtheta>=M_PI/2.) break; } CrystVector_REAL hh; hh=diffData->GetH();hh.resizeAndPreserve(nbReflections); CrystVector_REAL kk; kk=diffData->GetK();kk.resizeAndPreserve(nbReflections); CrystVector_REAL ll; ll=diffData->GetL();ll.resizeAndPreserve(nbReflections); diffData->SetHKL (hh, kk, ll); } pData=pDataTmp; break; } } //Create the global optimization object MonteCarloObj *pGlobalOptObj=new MonteCarloObj; pGlobalOptObj->AddRefinableObj(*pData); pGlobalOptObj->AddRefinableObj(cryst); //Refine only positionnal parameters pGlobalOptObj->FixAllPar(); pGlobalOptObj->SetParIsFixed(gpRefParTypeScattTransl,false); pGlobalOptObj->SetParIsFixed(gpRefParTypeScattOrient,false); //Don't cheat ;-) pGlobalOptObj->RandomizeStartingConfig(); //Annealing parameters (schedule, Tmax, Tmin, displacement schedule, pGlobalOptObj->SetAlgorithmParallTempering(ANNEALING_SMART,1e8,1e-8, ANNEALING_EXPONENTIAL,8,.125); //Global Optimization //The real job-first test long nbTrial=50000000; pGlobalOptObj->Optimize(nbTrial,true,0,time); SpeedTestReport report; report.mNbAtom=nbAtom; report.mNbAtomType=nbAtomType; report.mSpacegroup=spacegroup; report.mRadiation=radiation; report.mNbReflections=nbReflections; report.mDataType=dataType; report.mBogoMRAPS=(REAL)nbAtom*cryst.GetSpaceGroup().GetNbSymmetrics()*(REAL)nbReflections *(50000000-nbTrial)/pGlobalOptObj->GetLastOptimElapsedTime()/1e6; report.mBogoMRAPS_reduced=(REAL)nbAtom*cryst.GetSpaceGroup().GetNbSymmetrics(true,true) *(REAL)nbReflections *(50000000-nbTrial)/pGlobalOptObj->GetLastOptimElapsedTime()/1e6; report.mBogoSPS=(50000000-nbTrial)/pGlobalOptObj->GetLastOptimElapsedTime(); delete pGlobalOptObj; delete pData; return report; } } libobjcryst-2021.1.2+ds1/src/ObjCryst/ObjCryst/test.h000066400000000000000000000053671417150057700222070ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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; version 2 of the License. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* test.h * header file for test functions (speed, etc...) * */ #ifndef _OBJCRYST_TEST_H_ #define _OBJCRYST_TEST_H_ #include "ObjCryst/ObjCryst/General.h" namespace ObjCryst { /** Structure to hold the results of a speedtest (see ObjCryst::SpeedTest()) * * */ struct SpeedTestReport { /// Total number of unique atoms in the test structure. unsigned int mNbAtom; /// Total number of atom types in the test structure. int mNbAtomType; /// The symbol for the spacegroup string mSpacegroup; /// The type of radiation used RadiationType mRadiation; /// The total number of reflections used for the tests unsigned long mNbReflections; /// dataType: 0= single crystal, 1= powder pattern (1 background + 1 crystal phase) unsigned int mDataType; /// Million of Reflections-Atoms computed Per Second (considering all atoms in the unit cell) REAL mBogoMRAPS; /// Million of Reflections-Atoms computed Per Second (considering all atoms in the unit cell, /// except those deduced by a center of symmetry or a lattice translation) REAL mBogoMRAPS_reduced; /// Number of Structures evaluated Per Second REAL mBogoSPS; }; /** * * \param nbAtom: total number of unique atoms. * \param nbAtomType: total number of atom types. Must be smaller than nbAtom. * \param spacegroup: the symbol or spacegroup number for the spacegroup to be tested. * \param radiation: the type of radiation to do the test with (neutron, x-ray). * \param nbReflections: total number of reflections to use. * \param time: duration of the test (10s is usually enough). * \param dataType: 0= single crystal, 1= powder pattern (1 background + 1 crystal phase) */ SpeedTestReport SpeedTest(const unsigned int nbAtom, const int nbAtomType,const string spacegroup, const RadiationType radiation, const unsigned long nbReflections, const unsigned int dataType,const REAL time); } #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/000077500000000000000000000000001417150057700205635ustar00rootroot00000000000000libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/Chronometer.h000066400000000000000000000044551417150057700232310ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2007 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __VFN_CHRONOMETER__ #define __VFN_CHRONOMETER__ #include #include #include using namespace std; /** Simple chronometer class, with microsecond precision * * Reported time correspond to \e real time, i.e. not the time the program * has been running independently from other programs. */ class Chronometer { public: Chronometer(){this->start();}; ~Chronometer(){}; void start() {mPaused=false;mTime0=boost::posix_time::microsec_clock::local_time();} void pause() {mTime1=boost::posix_time::microsec_clock::local_time();mPaused=true;} void resume() { mTime0=boost::posix_time::microsec_clock::local_time()-(mTime1-mTime0); mPaused=false; } void print() { if(mPaused == false) mTime1=boost::posix_time::microsec_clock::local_time(); cout.setf(ios::fixed); int tmp=cout.precision(2); cout << "Elapsed time : " << this->seconds() << " s."< #include using namespace std; int gDebugMessageGlobalLevel=10; int gDebugMessageLevel=gDebugMessageLevel; unsigned int gVFNDebugMessageIndent=0; /* void LibCrystDebugMessage(const string &message, const int level=0) { if(level >= sDebugMessageLevel) cout << "DEBUG MSG:" << message < #endif /// Set the Global debug level for messages void LibCrystDebugGlobalLevel(const int level); /// Use this for a local modification of debug level messages. Call this at the /// beginning of the function, and call it without argument at the end of the function /// to revert to the default global debug level. void LibCrystDebugLocalLevel(const int level); extern int gVFNDebugMessageGlobalLevel; extern int gVFNDebugMessageLevel; extern unsigned int gVFNDebugMessageIndent; //Debug messages are printed only if __DEBUG__ is on, and if their level //is greater or equal to debugMessageGlobalLevel // 0 : messages from low-level routines, // 5 // 10 : messages from top LibCryst++ routines #ifdef _MSC_VER #define VFN_DEBUG_MESSAGE(message,level) \ if(level >= gVFNDebugMessageLevel) \ {\ stringstream ss;\ for(unsigned int iii=0;iii= gVFNDebugMessageLevel)\ {\ stringstream ss;\ ss << message;\ OutputDebugStringA(ss.str().c_str());\ } #define VFN_DEBUG_ENTRY(message,level) \ if(level >= gVFNDebugMessageLevel) \ {\ stringstream ss;\ for(unsigned int iii=0;iii= gVFNDebugMessageLevel) \ {\ stringstream ss;\ if(gVFNDebugMessageIndent>0) gVFNDebugMessageIndent--;\ for(unsigned int iii=0;iii (at " << __FILE__ << "," << __LINE__ << ")" <= gVFNDebugMessageLevel) \ {\ for(unsigned int iii=0;iii= gVFNDebugMessageLevel) cout << message; #define VFN_DEBUG_ENTRY(message,level) \ if(level >= gVFNDebugMessageLevel) \ {\ for(unsigned int iii=0;iii= gVFNDebugMessageLevel) \ {\ if(gVFNDebugMessageIndent>0) gVFNDebugMessageIndent--;\ for(unsigned int iii=0;iii (at " << __FILE__ << "," << __LINE__ << ")" < #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/VFNDebug.h" using namespace std; //////////////////////////////////////////////////////////////////////// // // FormatInt // //////////////////////////////////////////////////////////////////////// FormatInt::FormatInt(const long num,const int width): mValue(num),mWidth(width) {} FormatInt::~FormatInt(){} ostream& operator<< (ostream& os, const FormatInt& fInt) { return os << setiosflags(ios::right) << setw(fInt.mWidth) << fInt.mValue << " "; } //////////////////////////////////////////////////////////////////////// // // FormatFloat // //////////////////////////////////////////////////////////////////////// FormatFloat::FormatFloat(const REAL num,const int width,const int precision) :mValue(num),mWidth(width),mPrecision(precision) { } FormatFloat::~FormatFloat(){} ostream& operator<< (ostream& os, const FormatFloat &fFloat) { std::istream::fmtflags old_flags=os.flags(); os.setf( std::istream::fixed | std::istream::right | std::istream::showpoint,std::istream::floatfield ); std::streamsize old_prec = os.precision(fFloat.mPrecision); std::streamsize old_width = os.width(fFloat.mWidth); os << fFloat.mValue; os.flags( old_flags ); os.precision( old_prec ); os.width(old_width); return os; } //////////////////////////////////////////////////////////////////////// // // FormatString // //////////////////////////////////////////////////////////////////////// FormatString::FormatString(const string &str,const unsigned int width): /*mString(str,1,width),*/mWidth(width) { mString=str; //:KLUDGE: if(mString.size() > mWidth) mString.resize(mWidth); else for(unsigned int i=mString.size();i FormatVertVector::FormatVertVector( const CrystVector &fVect, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect); } template FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); mvpVectors.push_back(&fVect2); } template FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); mvpVectors.push_back(&fVect2); mvpVectors.push_back(&fVect3); } template FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); mvpVectors.push_back(&fVect2); mvpVectors.push_back(&fVect3); mvpVectors.push_back(&fVect4); } template FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const CrystVector &fVect5, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); mvpVectors.push_back(&fVect2); mvpVectors.push_back(&fVect3); mvpVectors.push_back(&fVect4); mvpVectors.push_back(&fVect5); } template FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const CrystVector &fVect5, const CrystVector &fVect6, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); mvpVectors.push_back(&fVect2); mvpVectors.push_back(&fVect3); mvpVectors.push_back(&fVect4); mvpVectors.push_back(&fVect5); mvpVectors.push_back(&fVect6); } template FormatVertVector::FormatVertVector( const CrystVector *pVect, const int nbVect, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { for(int i=0;i FormatVertVector::FormatVertVector( const CrystVector &fVect1, const CrystVector *pVect, const int nbVect, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&fVect1); for(int i=1;i FormatVertVector::FormatVertVector( vector *>& v, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors=v; } template FormatVertVector::~FormatVertVector() { } template ostream& operator<< (ostream &os, const FormatVertVector &fVect) { VFN_DEBUG_MESSAGE("ostream& operator<<(os,FormatVertVector)",3) long i; size_t j; std::istream::fmtflags old_flags=os.flags(); os.setf( std::istream::fixed | std::istream::right | std::istream::showpoint); std::streamsize old_prec = os.precision(fVect.mPrecision); std::streamsize old_width = os.width(); long nb=fVect.mNb; if(nb==0)nb=(fVect.mvpVectors[0])->numElements(); for(i=0;i):End",2) return os; } //////////////////////////////////////////////////////////////////////// // // FormatHorizVector // //////////////////////////////////////////////////////////////////////// template FormatHorizVector::FormatHorizVector( const CrystVector &fVect, const int width, const int precision): mWidth(width),mPrecision(precision) { mpVectors=&fVect; } template FormatHorizVector::~FormatHorizVector() {} template ostream& operator<< (ostream &os, const FormatHorizVector &fVect) { long i; std::istream::fmtflags old_flags=os.flags(); os.setf( std::istream::fixed | std::istream::right | std::istream::showpoint); std::streamsize old_prec = os.precision(fVect.mPrecision); std::streamsize old_width = os.width(); for(i=0;i<(*(fVect.mpVectors)).numElements();i++) { os < FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); mvpVectors.push_back(&q); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); mvpVectors.push_back(&q); mvpVectors.push_back(&r); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); mvpVectors.push_back(&q); mvpVectors.push_back(&r); mvpVectors.push_back(&s); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const CrystVector &t, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); mvpVectors.push_back(&q); mvpVectors.push_back(&r); mvpVectors.push_back(&s); mvpVectors.push_back(&t); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const CrystVector &t, const CrystVector &u, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors.push_back(&h); mvpVectors.push_back(&k); mvpVectors.push_back(&l); mvpVectors.push_back(&m); mvpVectors.push_back(&n); mvpVectors.push_back(&o); mvpVectors.push_back(&p); mvpVectors.push_back(&q); mvpVectors.push_back(&r); mvpVectors.push_back(&s); mvpVectors.push_back(&t); mvpVectors.push_back(&u); } template FormatVertVectorHKLFloats::FormatVertVectorHKLFloats( vector *>& v, const int width, const int precision, const int nb): mWidth(width),mPrecision(precision),mNb(nb) { mvpVectors=v; } template FormatVertVectorHKLFloats::~FormatVertVectorHKLFloats() {} template ostream& operator<< (ostream& os, const FormatVertVectorHKLFloats &fVect) { long i; unsigned int j; std::istream::fmtflags old_flags=os.flags(); os.setf( std::istream::fixed | std::istream::right | std::istream::showpoint); std::streamsize old_prec = os.precision(fVect.mPrecision); std::streamsize old_width = os.width(); long nb=fVect.mNb; if(nb==0) nb=(fVect.mvpVectors[0])->numElements(); for(i=0;i; template ostream& operator<< (ostream&,const FormatVertVector&); template class FormatHorizVector; template ostream& operator<< (ostream&,const FormatHorizVector&); template class FormatVertVectorHKLFloats; template ostream& operator<< (ostream&,const FormatVertVectorHKLFloats&); template class FormatVertVector; template ostream& operator<< (ostream&,const FormatVertVector&); template class FormatHorizVector; template ostream& operator<< (ostream&,const FormatHorizVector&); template class FormatVertVectorHKLFloats; template ostream& operator<< (ostream&,const FormatVertVectorHKLFloats&); libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/VFNStreamFormat.h000066400000000000000000000312061417150057700237140ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2005 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // This file includes some "effectors" used to format //strings, numbers, some arrays... #ifndef _VFN_STREAM_FORMAT_H_ #define _VFN_STREAM_FORMAT_H_ #include #include #include #include "ObjCryst/CrystVector/CrystVector.h" /** output a number as a formatted integer: * * \code os << FormatInt(mynumber,5);\endcode * * */ class FormatInt { public: FormatInt(const long num,const int width=5); ~FormatInt(); //private: const long mValue; const int mWidth; }; std::ostream& operator<< (std::ostream& os, const FormatInt& fInt); /** output a number as a formatted float: * *\code os << FormatFloat(mynumber,10,4); \endcode * * */ class FormatFloat { public: FormatFloat(const REAL num,const int width=10,const int precision=4); ~FormatFloat(); //private: const REAL mValue; const int mWidth; const int mPrecision; }; std::ostream& operator<< (std::ostream& os, const FormatFloat &fFloat); /** output a string with a fixed length (adding necessary space or removing * excess characters) : * * \code os << FormatString(myString,15);\endcode */ class FormatString { public: FormatString(const string &str,const unsigned int width=5); ~FormatString(); int length() const; //private: string mString; const unsigned int mWidth; }; std::ostream& operator<< (std::ostream& os, const FormatString& fStr); /** output one or several vectors as (a) column(s): * * \code * os << FormatVertVector(vect,8,3); * os << FormatVertVector(vect1,vect2,vetc3,12,6); * // For 7 vectors with width 12 and precision 4, * // pVect being a pointer to an array of 7 vectors: * os << FormatVertVector(pVect,7,12,4); * \endcode */ template class FormatVertVector { public: FormatVertVector( const CrystVector &fVect, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const CrystVector &fVect5, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector &fVect2, const CrystVector &fVect3, const CrystVector &fVect4, const CrystVector &fVect5, const CrystVector &fVect6, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector *pVect, const int nbVect, const int width=10, const int precision=4, const int nb=0); FormatVertVector( const CrystVector &fVect1, const CrystVector *pVect, const int nbVect, const int width=10, const int precision=4, const int nb=0); FormatVertVector( std::vector *>& v, const int width=10, const int precision=4, const int nb=0); ~FormatVertVector(); //int length() const; //private: std::vector *>mvpVectors; const int mWidth; const int mPrecision; const int mNb; }; template std::ostream& operator<< (std::ostream &os, const FormatVertVector &fVect); /** Format vector as horiz array: * * \code os << FormatHorizVector(vect,8,3);\endcode */ template class FormatHorizVector { public: FormatHorizVector(const CrystVector &fVect, const int width=10, const int precision=4); ~FormatHorizVector(); //int length() const; //private: const CrystVector *mpVectors; const int mWidth; const int mPrecision; }; template ostream& operator<< (std::ostream &os, const FormatHorizVector &fVect); /** Output vectors as column arrays, with the first 3 columns printed as integers. * * \code cout << FormatVertVectorHKLFloats(vH,vK,vL,vIobs,vIcalc,vSigma,12,4);\endcode */ templateclass FormatVertVectorHKLFloats { public: FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const CrystVector &t, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( const CrystVector &h, const CrystVector &k, const CrystVector &l, const CrystVector &m, const CrystVector &n, const CrystVector &o, const CrystVector &p, const CrystVector &q, const CrystVector &r, const CrystVector &s, const CrystVector &t, const CrystVector &u, const int width=10, const int precision=4, const int nb=0); FormatVertVectorHKLFloats( std::vector *>& v, const int width=10, const int precision=4, const int nb=0); ~FormatVertVectorHKLFloats(); //int length() const; //private: std::vector *>mvpVectors; const int mWidth; const int mPrecision; const int mNb; }; template std::ostream& operator<< (std::ostream& os, const FormatVertVectorHKLFloats &fStr); #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/ci_string.cpp000066400000000000000000000021411417150057700232460ustar00rootroot00000000000000#include "ci_string.h" /// Case-insensitive string class /// From: Guru of the Week #29 /// e.g.: http://gcc.gnu.org/onlinedocs/libstdc++/21_strings/gotw29a.txt /// /// Public domain. int strnicmp(const char *s1, const char *s2, int len) { unsigned char c1, c2; while (len) { c1 = *s1; c2 = *s2; s1++; s2++; if (!c1) return c2 ? -1 : 0; if (!c2) return 1; if (c1 != c2) { c1 = tolower(c1); c2 = tolower(c2); if (c1 != c2) return c1 < c2 ? -1 : 1; } len--; } return 0; } bool ci_char_traits::eq( char c1, char c2 ) {return tolower(c1) == tolower(c2);} bool ci_char_traits::ne( char c1, char c2 ) {return tolower(c1) != tolower(c2);} bool ci_char_traits::lt( char c1, char c2 ) {return tolower(c1) < tolower(c2);} int ci_char_traits::compare(const char* s1,const char* s2,size_t n ) { #ifdef _MSC_VER return _strnicmp(s1, s2, n); #else return strnicmp(s1, s2, n); #endif } const char* ci_char_traits::find( const char* s, int n, char a ) { while( n-- > 0 && tolower(*s) != tolower(a) ) ++s; return s; } libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/ci_string.h000066400000000000000000000011221417150057700227110ustar00rootroot00000000000000#ifndef _CI_STRING_H #define _CI_STRING_H #include /// Case-insensitive string class /// From: Guru of the Week #29 /// e.g.: http://gcc.gnu.org/onlinedocs/libstdc++/21_strings/gotw29a.txt /// /// Public domain. struct ci_char_traits : public std::char_traits { static bool eq( char c1, char c2 ); static bool ne( char c1, char c2 ); static bool lt( char c1, char c2 ); static int compare(const char* s1,const char* s2,size_t n ); static const char* find( const char* s, int n, char a ); }; typedef std::basic_string ci_string; #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/Quirks/sse_mathfun.h000066400000000000000000000554631417150057700232650ustar00rootroot00000000000000/* SIMD (SSE1+MMX or SSE2) implementation of sin, cos, exp and log Inspired by Intel Approximate Math library, and based on the corresponding algorithms of the cephes math library The default is to use the SSE1 version. If you define USE_SSE2 the the SSE2 intrinsics will be used in place of the MMX intrinsics. Do not expect any significant performance improvement with SSE2. NOTE: - Original version available @: http://gruntthepeon.free.fr/ssemath/ - Modifications for inclusion in ObjCryst++ (http://objcryst.sf.net): - functions are now inline. */ /* Copyright (C) 2007 Julien Pommier This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. (this is the zlib license) */ #include /* yes I know, the top of this file is quite ugly */ #ifdef _MSC_VER /* visual c++ */ # define ALIGN16_BEG __declspec(align(16)) # define ALIGN16_END #else /* gcc or icc */ # define ALIGN16_BEG # define ALIGN16_END __attribute__((aligned(16))) #endif /* __m128 is ugly to write */ typedef __m128 v4sf; // vector of 4 float (sse1) #ifdef USE_SSE2 # include typedef __m128i v4si; // vector of 4 int (sse2) #else typedef __m64 v2si; // vector of 2 int (mmx) #endif /* declare some SSE constants -- why can't I figure a better way to do that? */ #define _PS_CONST(Name, Val) \ static const ALIGN16_BEG float _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } #define _PI32_CONST(Name, Val) \ static const ALIGN16_BEG int _pi32_##Name[4] ALIGN16_END = { Val, Val, Val, Val } #define _PS_CONST_TYPE(Name, Type, Val) \ static const ALIGN16_BEG Type _ps_##Name[4] ALIGN16_END = { Val, Val, Val, Val } _PS_CONST(1 , 1.0f); _PS_CONST(0p5, 0.5f); /* the smallest non denormalized float number */ _PS_CONST_TYPE(min_norm_pos, int, 0x00800000); _PS_CONST_TYPE(mant_mask, int, 0x7f800000); _PS_CONST_TYPE(inv_mant_mask, int, ~0x7f800000); _PS_CONST_TYPE(sign_mask, unsigned int, 0x80000000); _PS_CONST_TYPE(inv_sign_mask, unsigned int, ~0x80000000); _PI32_CONST(1, 1); _PI32_CONST(inv1, ~1); _PI32_CONST(2, 2); _PI32_CONST(4, 4); _PI32_CONST(0x7f, 0x7f); _PS_CONST(cephes_SQRTHF, 0.707106781186547524); _PS_CONST(cephes_log_p0, 7.0376836292E-2); _PS_CONST(cephes_log_p1, - 1.1514610310E-1); _PS_CONST(cephes_log_p2, 1.1676998740E-1); _PS_CONST(cephes_log_p3, - 1.2420140846E-1); _PS_CONST(cephes_log_p4, + 1.4249322787E-1); _PS_CONST(cephes_log_p5, - 1.6668057665E-1); _PS_CONST(cephes_log_p6, + 2.0000714765E-1); _PS_CONST(cephes_log_p7, - 2.4999993993E-1); _PS_CONST(cephes_log_p8, + 3.3333331174E-1); _PS_CONST(cephes_log_q1, -2.12194440e-4); _PS_CONST(cephes_log_q2, 0.693359375); #if defined (__MINGW32__) /* the ugly part below: many versions of gcc used to be completely buggy with respect to some intrinsics The movehl_ps is fixed in mingw 3.4.5, but I found out that all the _mm_cmp* intrinsics were completely broken on my mingw gcc 3.4.5 ... Note that the bug on _mm_cmp* does occur only at -O0 optimization level */ inline __m128 my_movehl_ps(__m128 a, const __m128 b) { asm ( "movhlps %2,%0\n\t" : "=x" (a) : "0" (a), "x"(b) ); return a; } #warning "redefined _mm_movehl_ps (see gcc bug 21179)" #define _mm_movehl_ps my_movehl_ps inline __m128 my_cmplt_ps(__m128 a, const __m128 b) { asm ( "cmpltps %2,%0\n\t" : "=x" (a) : "0" (a), "x"(b) ); return a; } inline __m128 my_cmpgt_ps(__m128 a, const __m128 b) { asm ( "cmpnleps %2,%0\n\t" : "=x" (a) : "0" (a), "x"(b) ); return a; } inline __m128 my_cmpeq_ps(__m128 a, const __m128 b) { asm ( "cmpeqps %2,%0\n\t" : "=x" (a) : "0" (a), "x"(b) ); return a; } #warning "redefined _mm_cmpxx_ps functions..." #define _mm_cmplt_ps my_cmplt_ps #define _mm_cmpgt_ps my_cmpgt_ps #define _mm_cmpeq_ps my_cmpeq_ps #endif #ifndef USE_SSE2 typedef union xmm_mm_union { __m128 xmm; __m64 mm[2]; } xmm_mm_union; #define COPY_XMM_TO_MM(xmm_, mm0_, mm1_) { \ xmm_mm_union u; u.xmm = xmm_; \ mm0_ = u.mm[0]; \ mm1_ = u.mm[1]; \ } #define COPY_MM_TO_XMM(mm0_, mm1_, xmm_) { \ xmm_mm_union u; u.mm[0]=mm0_; u.mm[1]=mm1_; xmm_ = u.xmm; \ } #endif // USE_SSE2 /* natural logarithm computed for 4 simultaneous float return NaN for x <= 0 */ inline v4sf log_ps(v4sf x) { #ifdef USE_SSE2 v4si emm0; #else v2si mm0, mm1; #endif v4sf one = *(v4sf*)_ps_1; v4sf invalid_mask = _mm_cmple_ps(x, _mm_setzero_ps()); x = _mm_max_ps(x, *(v4sf*)_ps_min_norm_pos); /* cut off denormalized stuff */ #ifndef USE_SSE2 /* part 1: x = frexpf(x, &e); */ COPY_XMM_TO_MM(x, mm0, mm1); mm0 = _mm_srli_pi32(mm0, 23); mm1 = _mm_srli_pi32(mm1, 23); #else emm0 = _mm_srli_epi32(_mm_castps_si128(x), 23); #endif /* keep only the fractional part */ x = _mm_and_ps(x, *(v4sf*)_ps_inv_mant_mask); x = _mm_or_ps(x, *(v4sf*)_ps_0p5); #ifndef USE_SSE2 /* now e=mm0:mm1 contain the really base-2 exponent */ mm0 = _mm_sub_pi32(mm0, *(v2si*)_pi32_0x7f); mm1 = _mm_sub_pi32(mm1, *(v2si*)_pi32_0x7f); v4sf e = _mm_cvtpi32x2_ps(mm0, mm1); _mm_empty(); /* bye bye mmx */ #else emm0 = _mm_sub_epi32(emm0, *(v4si*)_pi32_0x7f); v4sf e = _mm_cvtepi32_ps(emm0); #endif e = _mm_add_ps(e, one); /* part2: if( x < SQRTHF ) { e -= 1; x = x + x - 1.0; } else { x = x - 1.0; } */ v4sf mask = _mm_cmplt_ps(x, *(v4sf*)_ps_cephes_SQRTHF); v4sf tmp = _mm_and_ps(x, mask); x = _mm_sub_ps(x, one); e = _mm_sub_ps(e, _mm_and_ps(one, mask)); x = _mm_add_ps(x, tmp); v4sf z = _mm_mul_ps(x,x); v4sf y = *(v4sf*)_ps_cephes_log_p0; y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p1); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p2); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p3); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p4); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p5); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p6); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p7); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_log_p8); y = _mm_mul_ps(y, x); y = _mm_mul_ps(y, z); tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q1); y = _mm_add_ps(y, tmp); tmp = _mm_mul_ps(z, *(v4sf*)_ps_0p5); y = _mm_sub_ps(y, tmp); tmp = _mm_mul_ps(e, *(v4sf*)_ps_cephes_log_q2); x = _mm_add_ps(x, y); x = _mm_add_ps(x, tmp); x = _mm_or_ps(x, invalid_mask); // negative arg will be NAN return x; } _PS_CONST(exp_hi, 88.3762626647949f); _PS_CONST(exp_lo, -88.3762626647949f); _PS_CONST(cephes_LOG2EF, 1.44269504088896341); _PS_CONST(cephes_exp_C1, 0.693359375); _PS_CONST(cephes_exp_C2, -2.12194440e-4); _PS_CONST(cephes_exp_p0, 1.9875691500E-4); _PS_CONST(cephes_exp_p1, 1.3981999507E-3); _PS_CONST(cephes_exp_p2, 8.3334519073E-3); _PS_CONST(cephes_exp_p3, 4.1665795894E-2); _PS_CONST(cephes_exp_p4, 1.6666665459E-1); _PS_CONST(cephes_exp_p5, 5.0000001201E-1); inline v4sf exp_ps(v4sf x) { v4sf tmp = _mm_setzero_ps(), fx; #ifdef USE_SSE2 v4si emm0; #else v2si mm0, mm1; #endif v4sf one = *(v4sf*)_ps_1; x = _mm_min_ps(x, *(v4sf*)_ps_exp_hi); x = _mm_max_ps(x, *(v4sf*)_ps_exp_lo); /* express exp(x) as exp(g + n*log(2)) */ fx = _mm_mul_ps(x, *(v4sf*)_ps_cephes_LOG2EF); fx = _mm_add_ps(fx, *(v4sf*)_ps_0p5); /* how to perform a floorf with SSE: just below */ #ifndef USE_SSE2 /* step 1 : cast to int */ tmp = _mm_movehl_ps(tmp, fx); mm0 = _mm_cvttps_pi32(fx); mm1 = _mm_cvttps_pi32(tmp); /* step 2 : cast back to float */ tmp = _mm_cvtpi32x2_ps(mm0, mm1); #else emm0 = _mm_cvttps_epi32(fx); tmp = _mm_cvtepi32_ps(emm0); #endif /* if greater, substract 1 */ v4sf mask = _mm_cmpgt_ps(tmp, fx); mask = _mm_and_ps(mask, one); fx = _mm_sub_ps(tmp, mask); tmp = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C1); v4sf z = _mm_mul_ps(fx, *(v4sf*)_ps_cephes_exp_C2); x = _mm_sub_ps(x, tmp); x = _mm_sub_ps(x, z); z = _mm_mul_ps(x,x); v4sf y = *(v4sf*)_ps_cephes_exp_p0; y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p1); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p2); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p3); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p4); y = _mm_mul_ps(y, x); y = _mm_add_ps(y, *(v4sf*)_ps_cephes_exp_p5); y = _mm_mul_ps(y, z); y = _mm_add_ps(y, x); y = _mm_add_ps(y, one); /* build 2^n */ #ifndef USE_SSE2 z = _mm_movehl_ps(z, fx); mm0 = _mm_cvttps_pi32(fx); mm1 = _mm_cvttps_pi32(z); mm0 = _mm_add_pi32(mm0, *(v2si*)_pi32_0x7f); mm1 = _mm_add_pi32(mm1, *(v2si*)_pi32_0x7f); mm0 = _mm_slli_pi32(mm0, 23); mm1 = _mm_slli_pi32(mm1, 23); v4sf pow2n; COPY_MM_TO_XMM(mm0, mm1, pow2n); _mm_empty(); #else emm0 = _mm_cvttps_epi32(fx); emm0 = _mm_add_epi32(emm0, *(v4si*)_pi32_0x7f); emm0 = _mm_slli_epi32(emm0, 23); v4sf pow2n = _mm_castsi128_ps(emm0); #endif y = _mm_mul_ps(y, pow2n); return y; } _PS_CONST(minus_cephes_DP1, -0.78515625); _PS_CONST(minus_cephes_DP2, -2.4187564849853515625e-4); _PS_CONST(minus_cephes_DP3, -3.77489497744594108e-8); _PS_CONST(sincof_p0, -1.9515295891E-4); _PS_CONST(sincof_p1, 8.3321608736E-3); _PS_CONST(sincof_p2, -1.6666654611E-1); _PS_CONST(coscof_p0, 2.443315711809948E-005); _PS_CONST(coscof_p1, -1.388731625493765E-003); _PS_CONST(coscof_p2, 4.166664568298827E-002); _PS_CONST(cephes_FOPI, 1.27323954473516); // 4 / M_PI /* evaluation of 4 sines at onces, using only SSE1+MMX intrinsics so it runs also on old athlons XPs and the pentium III of your grand mother. The code is the exact rewriting of the cephes sinf function. Precision is excellent as long as x < 8192 (I did not bother to take into account the special handling they have for greater values -- it does not return garbage for arguments over 8192, though, but the extra precision is missing). Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the surprising but correct result. Performance is also surprisingly good, 1.33 times faster than the macos vsinf SSE2 function, and 1.5 times faster than the __vrs4_sinf of amd's ACML (which is only available in 64 bits). Not too bad for an SSE1 function (with no special tuning) ! However the latter libraries probably have a much better handling of NaN, Inf, denormalized and other special arguments.. On my core 1 duo, the execution of this function takes approximately 95 cycles. From what I have observed on the experiments with Intel AMath lib, switching to an SSE2 version would improve the perf by only 10%. Since it is based on SSE intrinsics, it has to be compiled at -O2 to deliver full speed. */ inline v4sf sin_ps(v4sf x) { // any x v4sf xmm1, xmm2 = _mm_setzero_ps(), xmm3, sign_bit, y; #ifdef USE_SSE2 v4si emm0, emm2; #else v2si mm0, mm1, mm2, mm3; #endif sign_bit = x; /* take the absolute value */ x = _mm_and_ps(x, *(v4sf*)_ps_inv_sign_mask); /* extract the sign bit (upper one) */ sign_bit = _mm_and_ps(sign_bit, *(v4sf*)_ps_sign_mask); /* scale by 4/Pi */ y = _mm_mul_ps(x, *(v4sf*)_ps_cephes_FOPI); //printf("plop:"); print4(y); #ifdef USE_SSE2 /* store the integer part of y in mm0 */ emm2 = _mm_cvttps_epi32(y); /* j=(j+1) & (~1) (see the cephes sources) */ emm2 = _mm_add_epi32(emm2, *(v4si*)_pi32_1); emm2 = _mm_and_si128(emm2, *(v4si*)_pi32_inv1); y = _mm_cvtepi32_ps(emm2); /* get the swap sign flag */ emm0 = _mm_and_si128(emm2, *(v4si*)_pi32_4); emm0 = _mm_slli_epi32(emm0, 29); /* get the polynom selection mask there is one polynom for 0 <= x <= Pi/4 and another one for Pi/4 #include "ObjCryst/RefinableObj/GlobalOptimObj.h" #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/VFNDebug.h" #include "ObjCryst/Quirks/Chronometer.h" #include "ObjCryst/ObjCryst/IO.h" #include "ObjCryst/RefinableObj/LSQNumObj.h" #include "ObjCryst/ObjCryst/Molecule.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxRefinableObj.h" #undef GetClassName // Conflict from wxMSW headers ? (cygwin) #endif //For some reason, with wxWindows this must be placed after wx headers (Borland c++) #include #include #include #include namespace ObjCryst { void CompareWorlds(const CrystVector_long &idx,const CrystVector_long &swap, const RefinableObj &obj) { const long nb=swap.numElements(); const CrystVector_REAL *pv0=&(obj.GetParamSet(idx(swap(nb-1)))); for(long i=0;inumElements();++j) d += ((*pv0)(j)-(*pv1)(j))*((*pv0)(j)-(*pv1)(j)); cout<<"d("< gOptimizationObjRegistry("List of all Optimization objects"); OptimizationObj::OptimizationObj(): mName(""),mSaveFileName("GlobalOptim.save"), mNbTrialPerRun(10000000),mNbTrial(0),mRun(0),mBestCost(-1), mBestParSavedSetIndex(-1), mContext(0), mIsOptimizing(false),mStopAfterCycle(false), mRefinedObjList("OptimizationObj: "+mName+" RefinableObj registry"), mRecursiveRefinedObjList("OptimizationObj: "+mName+" recursive RefinableObj registry"), mLastOptimTime(0) { VFN_DEBUG_ENTRY("OptimizationObj::OptimizationObj()",5) // This must be done in a real class to avoid calling a pure virtual method // if a graphical representation is automatically called upon registration. // gOptimizationObjRegistry.Register(*this); static bool need_initRandomSeed=true; if(need_initRandomSeed==true) { srand(time(NULL)); need_initRandomSeed=false; } // We only copy parameters, so do not delete them ! mRefParList.SetDeleteRefParInDestructor(false); VFN_DEBUG_EXIT("OptimizationObj::OptimizationObj()",5) } OptimizationObj::OptimizationObj(const string name): mName(name),mSaveFileName("GlobalOptim.save"), mNbTrialPerRun(10000000),mNbTrial(0),mRun(0),mBestCost(-1), mBestParSavedSetIndex(-1), mContext(0), mIsOptimizing(false),mStopAfterCycle(false), mRefinedObjList("OptimizationObj: "+mName+" RefinableObj registry"), mRecursiveRefinedObjList("OptimizationObj: "+mName+" recursive RefinableObj registry"), mLastOptimTime(0) { VFN_DEBUG_ENTRY("OptimizationObj::OptimizationObj()",5) // This must be done in a real class to avoid calling a pure virtual method // if a graphical representation is automatically called upon registration. // gOptimizationObjRegistry.Register(*this); static bool need_initRandomSeed=true; if(need_initRandomSeed==true) { srand(time(NULL)); need_initRandomSeed=false; } // We only copy parameters, so do not delete them ! mRefParList.SetDeleteRefParInDestructor(false); VFN_DEBUG_EXIT("OptimizationObj::OptimizationObj()",5) } OptimizationObj::OptimizationObj(const OptimizationObj &old): mName(old.mName),mSaveFileName(old.mSaveFileName), mNbTrialPerRun(old.mNbTrialPerRun),mNbTrial(old.mNbTrial),mRun(old.mRun),mBestCost(old.mBestCost), mBestParSavedSetIndex(-1), mContext(0), mIsOptimizing(false),mStopAfterCycle(false), mRefinedObjList("OptimizationObj: "+mName+" RefinableObj registry"), mRecursiveRefinedObjList("OptimizationObj: "+mName+" recursive RefinableObj registry"), mLastOptimTime(0) { VFN_DEBUG_ENTRY("OptimizationObj::OptimizationObj(&old)",5) // This must be done in a real class to avoid calling a pure virtual method // if a graphical representation is automatically called upon registration. // gOptimizationObjRegistry.Register(*this); static bool need_initRandomSeed=true; if(need_initRandomSeed==true) { srand(time(NULL)); need_initRandomSeed=false; } // We only copy parameters, so do not delete them ! mRefParList.SetDeleteRefParInDestructor(false); for(unsigned int i=0;iAddRefinableObj(old.mRefinedObjList.GetObj(i)); VFN_DEBUG_EXIT("OptimizationObj::OptimizationObj(&old)",5) } OptimizationObj::~OptimizationObj() { VFN_DEBUG_ENTRY("OptimizationObj::~OptimizationObj()",5) gOptimizationObjRegistry.DeRegister(*this); VFN_DEBUG_EXIT("OptimizationObj::~OptimizationObj()",5) } void OptimizationObj::RandomizeStartingConfig() { VFN_DEBUG_ENTRY("OptimizationObj::RandomizeStartingConfig()",5) this->PrepareRefParList(); for(int j=0;jBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;iBuildRecursiveRefObjList(); for(int i=0;imTotalLogLikelihood += tmp; st->mTotalLogLikelihoodDeltaSq += (tmp-st->mLastLogLikelihood)*(tmp-st->mLastLogLikelihood); st->mLastLogLikelihood=tmp; } cost += mvObjWeight[&(mRecursiveRefinedObjList.GetObj(i))].mWeight * tmp; } return cost; } void OptimizationObj::StopAfterCycle() { VFN_DEBUG_MESSAGE("OptimizationObj::StopAfterCycle()",5) if(mIsOptimizing) { #ifdef __WX__CRYST__ wxMutexLocker lock(mMutexStopAfterCycle); #endif mStopAfterCycle=true; } } void OptimizationObj::DisplayReport() { //:TODO: ask all objects to print their own report ? } void OptimizationObj::AddRefinableObj(RefinableObj &obj) { VFN_DEBUG_MESSAGE("OptimizationObj::AddRefinableObj():"<BuildRecursiveRefObjList(); mRefinedObjList.Register(obj); RefObjRegisterRecursive(obj,mRecursiveRefinedObjList); #ifdef __WX__CRYST__ if(0!=this->WXGet()) this->WXGet()->AddRefinedObject(obj); #endif } RefinableObj& OptimizationObj::GetFullRefinableObj(const bool rebuild) { if(rebuild) this->PrepareRefParList(); return mRefParList; } const string& OptimizationObj::GetName()const { return mName;} void OptimizationObj::SetName(const string& name) {mName=name;} const string OptimizationObj::GetClassName()const { return "OptimizationObj";} void OptimizationObj::Print()const {this->XMLOutput(cout);} void OptimizationObj::RestoreBestConfiguration() { //:TODO: check list of refinableObj has not changed, and the list of // RefPar has not changed in all sub-objects. if(mBestParSavedSetIndex>0) mRefParList.RestoreParamSet(mBestParSavedSetIndex); } bool OptimizationObj::IsOptimizing()const{return mIsOptimizing;} void OptimizationObj::TagNewBestConfig() { for(int i=0;i& OptimizationObj::GetOptionList() { return mOptionRegistry; } RefObjOpt& OptimizationObj::GetOption(const unsigned int i) { VFN_DEBUG_MESSAGE("RefinableObj::GetOption()"<Print(); throw ObjCrystException("OptimizationObj::GetOption(): cannot find option: "+name+" in object:"+this->GetName()); } return mOptionRegistry.GetObj(i); } const RefObjOpt& OptimizationObj::GetOption(const unsigned int i)const { VFN_DEBUG_MESSAGE("RefinableObj::GetOption()"<Print(); throw ObjCrystException("OptimizationObj::GetOption(): cannot find option: "+name+" in object:"+this->GetName()); } return mOptionRegistry.GetObj(i); } const ObjRegistry& OptimizationObj::GetRefinedObjList() const { return mRefinedObjList; } unsigned int OptimizationObj::GetNbParamSet() const { return mvSavedParamSet.size(); } long OptimizationObj::GetParamSetIndex(const unsigned int i) const { if(i>=mvSavedParamSet.size()) throw ObjCrystException("OptimizationObj::GetSavedParamSetIndex(i): i > nb saved param set"); return mvSavedParamSet[i].first; } long OptimizationObj::GetParamSetCost(const unsigned int i) const { if(i>=mvSavedParamSet.size()) throw ObjCrystException("OptimizationObj::GetSavedParamSetCost(i): i > nb saved param set"); return mvSavedParamSet[i].second; } void OptimizationObj::RestoreParamSet(const unsigned int i, const bool update_display) { mRefParList.RestoreParamSet(this->GetParamSetIndex(i)); if(update_display) this->UpdateDisplay(); } void OptimizationObj::PrepareRefParList() { VFN_DEBUG_ENTRY("OptimizationObj::PrepareRefParList()",6) this->BuildRecursiveRefObjList(); // As any parameter been added in the recursive list of objects ? // or has any object been added/removed ? RefinableObjClock clock; GetRefParListClockRecursive(mRecursiveRefinedObjList,clock); if( (clock>mRefParList.GetRefParListClock()) ||(mRecursiveRefinedObjList.GetRegistryClock()>mRefParList.GetRefParListClock()) ) { VFN_DEBUG_MESSAGE("OptimizationObj::PrepareRefParList():Rebuild list",6) mRefParList.ResetParList(); mRefParList.EraseAllParamSet(); for(int i=0;i (this->GetName()+"::Overall LogLikelihood",*this,fl)); for(long i=0;i (mRecursiveRefinedObjList.GetObj(i).GetName()+"::LogLikelihood",mRecursiveRefinedObjList.GetObj(i),fp)); if(mRecursiveRefinedObjList.GetObj(i).GetClassName()=="Crystal") { REAL (Crystal::*fc)() const; const Crystal *pCryst=dynamic_cast(&(mRecursiveRefinedObjList.GetObj(i))); fc=&Crystal::GetBumpMergeCost; mMainTracker.AddTracker(new TrackerObject (pCryst->GetName()+"::BumpMergeCost",*pCryst,fc)); fc=&Crystal::GetBondValenceCost; mMainTracker.AddTracker(new TrackerObject (pCryst->GetName()+"::BondValenceCost",*pCryst,fc)); } } } // Prepare for refinement, ie get the list of not fixed parameters, // and prepare the objects... mRefParList.PrepareForRefinement(); for(int i=0;iAddOption(&mXMLAutoSave); VFN_DEBUG_MESSAGE("OptimizationObj::InitOptions():End",5) } void OptimizationObj::UpdateDisplay() const { Chronometer chrono; for(int i=0;imRecursiveRefinedObjList.GetRegistryClock()) { VFN_DEBUG_ENTRY("OptimizationObj::BuildRecursiveRefObjList()",5) mRecursiveRefinedObjList.DeRegisterAll(); for(int i=0;iInitOptions(); mGlobalOptimType.SetChoice(GLOBAL_OPTIM_PARALLEL_TEMPERING); mAnnealingScheduleTemp.SetChoice(ANNEALING_SMART); mAnnealingScheduleMutation.SetChoice(ANNEALING_EXPONENTIAL); mXMLAutoSave.SetChoice(5);//Save after each Run mAutoLSQ.SetChoice(0); gOptimizationObjRegistry.Register(*this); VFN_DEBUG_EXIT("MonteCarloObj::MonteCarloObj()",5) } MonteCarloObj::MonteCarloObj(const string name): OptimizationObj(name), mCurrentCost(-1), mTemperatureMax(1e6),mTemperatureMin(.001),mTemperatureGamma(1.0), mMutationAmplitudeMax(8.),mMutationAmplitudeMin(.125),mMutationAmplitudeGamma(1.0), mNbTrialRetry(0),mMinCostRetry(0) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_ENTRY("MonteCarloObj::MonteCarloObj()",5) this->InitOptions(); mGlobalOptimType.SetChoice(GLOBAL_OPTIM_PARALLEL_TEMPERING); mAnnealingScheduleTemp.SetChoice(ANNEALING_SMART); mAnnealingScheduleMutation.SetChoice(ANNEALING_EXPONENTIAL); mXMLAutoSave.SetChoice(5);//Save after each Run mAutoLSQ.SetChoice(0); gOptimizationObjRegistry.Register(*this); VFN_DEBUG_EXIT("MonteCarloObj::MonteCarloObj()",5) } MonteCarloObj::MonteCarloObj(const MonteCarloObj &old): OptimizationObj(old), mCurrentCost(old.mCurrentCost), mTemperatureMax(old.mTemperatureMax),mTemperatureMin(old.mTemperatureMin), mTemperatureGamma(old.mTemperatureGamma), mMutationAmplitudeMax(old.mMutationAmplitudeMax),mMutationAmplitudeMin(old.mMutationAmplitudeMin), mMutationAmplitudeGamma(old.mMutationAmplitudeGamma), mNbTrialRetry(old.mNbTrialRetry),mMinCostRetry(old.mMinCostRetry) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_ENTRY("MonteCarloObj::MonteCarloObj(&old)",5) this->InitOptions(); for(unsigned int i=0;iGetNbOption();i++) this->GetOption(i).SetChoice(old.GetOption(i).GetChoice()); gOptimizationObjRegistry.Register(*this); VFN_DEBUG_EXIT("MonteCarloObj::MonteCarloObj(&old)",5) } MonteCarloObj::MonteCarloObj(const bool internalUseOnly): OptimizationObj(""), mCurrentCost(-1), mTemperatureMax(.03),mTemperatureMin(.003),mTemperatureGamma(1.0), mMutationAmplitudeMax(16.),mMutationAmplitudeMin(.125),mMutationAmplitudeGamma(1.0), mNbTrialRetry(0),mMinCostRetry(0) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_ENTRY("MonteCarloObj::MonteCarloObj(bool)",5) this->InitOptions(); mGlobalOptimType.SetChoice(GLOBAL_OPTIM_PARALLEL_TEMPERING); mAnnealingScheduleTemp.SetChoice(ANNEALING_SMART); mAnnealingScheduleMutation.SetChoice(ANNEALING_EXPONENTIAL); mXMLAutoSave.SetChoice(5);//Save after each Run mAutoLSQ.SetChoice(0); if(false==internalUseOnly) gOptimizationObjRegistry.Register(*this); VFN_DEBUG_EXIT("MonteCarloObj::MonteCarloObj(bool)",5) } MonteCarloObj::~MonteCarloObj() { VFN_DEBUG_ENTRY("MonteCarloObj::~MonteCarloObj()",5) gOptimizationObjRegistry.DeRegister(*this); VFN_DEBUG_EXIT ("MonteCarloObj::~MonteCarloObj()",5) } void MonteCarloObj::SetAlgorithmSimulAnnealing(const AnnealingSchedule scheduleTemp, const REAL tMax, const REAL tMin, const AnnealingSchedule scheduleMutation, const REAL mutMax, const REAL mutMin, const long nbTrialRetry,const REAL minCostRetry) { VFN_DEBUG_MESSAGE("MonteCarloObj::SetAlgorithmSimulAnnealing()",5) mGlobalOptimType.SetChoice(GLOBAL_OPTIM_SIMULATED_ANNEALING); mTemperatureMax=tMax; mTemperatureMin=tMin; mAnnealingScheduleTemp.SetChoice(scheduleTemp); mMutationAmplitudeMax=mutMax; mMutationAmplitudeMin=mutMin; mAnnealingScheduleMutation.SetChoice(scheduleMutation); mNbTrialRetry=nbTrialRetry; mMinCostRetry=minCostRetry; VFN_DEBUG_MESSAGE("MonteCarloObj::SetAlgorithmSimulAnnealing():End",3) } void MonteCarloObj::SetAlgorithmParallTempering(const AnnealingSchedule scheduleTemp, const REAL tMax, const REAL tMin, const AnnealingSchedule scheduleMutation, const REAL mutMax, const REAL mutMin) { VFN_DEBUG_MESSAGE("MonteCarloObj::SetAlgorithmParallTempering()",5) mGlobalOptimType.SetChoice(GLOBAL_OPTIM_PARALLEL_TEMPERING); mTemperatureMax=tMax; mTemperatureMin=tMin; mAnnealingScheduleTemp.SetChoice(scheduleTemp); mMutationAmplitudeMax=mutMax; mMutationAmplitudeMin=mutMin; mAnnealingScheduleMutation.SetChoice(scheduleMutation); //mNbTrialRetry=nbTrialRetry; //mMinCostRetry=minCostRetry; VFN_DEBUG_MESSAGE("MonteCarloObj::SetAlgorithmParallTempering():End",3) } void MonteCarloObj::Optimize(long &nbStep,const bool silent,const REAL finalcost, const REAL maxTime) { //:TODO: Other algorithms ! TAU_PROFILE("MonteCarloObj::Optimize()","void (long)",TAU_DEFAULT); VFN_DEBUG_ENTRY("MonteCarloObj::Optimize()",5) this->BeginOptimization(true); this->PrepareRefParList(); this->InitLSQ(false); mIsOptimizing=true; if(mTemperatureGamma<0.1) mTemperatureGamma= 0.1; if(mTemperatureGamma>10.0)mTemperatureGamma=10.0; if(mMutationAmplitudeGamma<0.1) mMutationAmplitudeGamma= 0.1; if(mMutationAmplitudeGamma>10.0)mMutationAmplitudeGamma=10.0; // prepare all objects this->TagNewBestConfig(); mCurrentCost=this->GetLogLikelihood(); mBestCost=mCurrentCost; mvObjWeight.clear(); mMainTracker.ClearValues(); Chronometer chrono; chrono.start(); switch(mGlobalOptimType.GetChoice()) { case GLOBAL_OPTIM_SIMULATED_ANNEALING: { this->RunSimulatedAnnealing(nbStep,silent,finalcost,maxTime); break; }//case GLOBAL_OPTIM_SIMULATED_ANNEALING case GLOBAL_OPTIM_PARALLEL_TEMPERING: { this->RunParallelTempering(nbStep,silent,finalcost,maxTime); break; }//case GLOBAL_OPTIM_PARALLEL_TEMPERING case GLOBAL_OPTIM_RANDOM_LSQ: //:TODO: { long cycles = 1; this->RunRandomLSQMethod(cycles); break; }//case GLOBAL_OPTIM_GENETIC } mIsOptimizing=false; #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif mStopAfterCycle=false; #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif mRefParList.RestoreParamSet(mBestParSavedSetIndex); this->EndOptimization(); (*fpObjCrystInformUser)((boost::format("Finished Optimization, final cost=%12.2f (dt=%.1fs)") % this->GetLogLikelihood() % chrono.seconds()).str()); if(mSaveTrackedData.GetChoice()==1) { ofstream outTracker; outTracker.imbue(std::locale::classic()); const string outTrackerName=this->GetName()+"-Tracker.dat"; outTracker.open(outTrackerName.c_str()); mMainTracker.SaveAll(outTracker); outTracker.close(); } for(vector >::iterator pos=mvSavedParamSet.begin();pos!=mvSavedParamSet.end();++pos) if(pos->first==mBestParSavedSetIndex) { if( (pos->second>mBestCost) ||(pos->second<0)) { pos->second=mBestCost; break; } } this->UpdateDisplay(); VFN_DEBUG_EXIT("MonteCarloObj::Optimize()",5) } void MonteCarloObj::MultiRunOptimize(long &nbCycle,long &nbStep,const bool silent, const REAL finalcost,const REAL maxTime) { //:TODO: Other algorithms ! TAU_PROFILE("MonteCarloObj::MultiRunOptimize()","void (long)",TAU_DEFAULT); VFN_DEBUG_ENTRY("MonteCarloObj::MultiRunOptimize()",5) //Keep a copy of the total number of steps, and decrement nbStep const long nbStep0=nbStep; this->BeginOptimization(true); this->PrepareRefParList(); this->InitLSQ(false); mIsOptimizing=true; if(mTemperatureGamma<0.1) mTemperatureGamma= 0.1; if(mTemperatureGamma>10.0)mTemperatureGamma=10.0; if(mMutationAmplitudeGamma<0.1) mMutationAmplitudeGamma= 0.1; if(mMutationAmplitudeGamma>10.0)mMutationAmplitudeGamma=10.0; // prepare all objects mCurrentCost=this->GetLogLikelihood(); mBestCost=mCurrentCost; this->TagNewBestConfig(); mvObjWeight.clear(); long nbTrialCumul=0; const long nbCycle0=nbCycle; Chronometer chrono; mRun = 0; while(nbCycle!=0) { if(!silent) cout <<"MonteCarloObj::MultiRunOptimize: Starting Run#"<RunSimulatedAnnealing(nbStep,silent,finalcost,maxTime);} catch(...){cout<<"Unhandled exception in MonteCarloObj::MultiRunOptimize() ?"<RunParallelTempering(nbStep,silent,finalcost,maxTime);} catch(...){cout<<"Unhandled exception in MonteCarloObj::MultiRunOptimize() ?"<RunRandomLSQMethod(nbCycle);} catch(...){cout<<"Unhandled exception in MonteCarloObj::RunRandomLSQMethod() ?"<1) (*fpObjCrystInformUser)((boost::format("Finished Run #%d, final cost=%12.2f, nbTrial=%d (dt=%.1fs), so far =%d") % (nbCycle0-nbCycle) % this->GetLogLikelihood() % (nbStep0-nbStep) % chrono.seconds() % (nbTrialCumul/(nbCycle0-nbCycle+1))).str()); else (*fpObjCrystInformUser)((boost::format("Finished Run #%d, final cost=%12.2f, nbTrial=%d (dt=%.1fs)") % (nbCycle0-nbCycle) % this->GetLogLikelihood() % (nbStep0-nbStep) % chrono.seconds()).str()); nbStep=nbStep0; if(false==mStopAfterCycle) this->UpdateDisplay(); stringstream s; s<<"Run #"<GetName(); time_t date=time(0); char strDate[40]; strftime(strDate,sizeof(strDate),"%Y-%m-%d_%H-%M-%S",localtime(&date));//%Y-%m-%dT%H:%M:%S%Z char costAsChar[30]; sprintf(costAsChar,"-Run#%ld-Cost-%f",abs(nbCycle),this->GetLogLikelihood()); saveFileName=saveFileName+(string)strDate+(string)costAsChar+(string)".xml"; XMLCrystFileSaveGlobal(saveFileName); } if(mSaveTrackedData.GetChoice()==1) { ofstream outTracker; outTracker.imbue(std::locale::classic()); char runNum[40]; sprintf(runNum,"-Tracker-Run#%ld.dat",abs(nbCycle)); const string outTrackerName=this->GetName()+runNum; outTracker.open(outTrackerName.c_str()); mMainTracker.SaveAll(outTracker); outTracker.close(); } nbCycle--; #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif if(mStopAfterCycle) { #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif break; } #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif mRun++; } mIsOptimizing=false; mRefParList.RestoreParamSet(mBestParSavedSetIndex); for(vector >::iterator pos=mvSavedParamSet.begin();pos!=mvSavedParamSet.end();++pos) if(pos->first==mBestParSavedSetIndex) { if( (pos->second>mBestCost) ||(pos->second<0)) { pos->second=mBestCost; break; } } this->EndOptimization(); if(false==mStopAfterCycle) this->UpdateDisplay(); #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif mStopAfterCycle=false; #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif if(finalcost>1) cout<="<DisplayReport(); REAL runBestCost; mCurrentCost=this->GetLogLikelihood(); runBestCost=mCurrentCost; const long lastParSavedSetIndex=mRefParList.CreateParamSet("MonteCarloObj:Last parameters (SA)"); const long runBestIndex=mRefParList.CreateParamSet("Best parameters for current run (SA)"); //Report each ... cycles const int nbTryReport=3000; // Keep record of the number of accepted moves long nbAcceptedMoves=0;//since last report long nbAcceptedMovesTemp=0;//since last temperature/mutation rate change // Number of tries since best configuration found long nbTriesSinceBest=0; // Change temperature (and mutation) every... const int nbTryPerTemp=300; mTemperature=sqrt(mTemperatureMin*mTemperatureMax); mMutationAmplitude=sqrt(mMutationAmplitudeMin*mMutationAmplitudeMax); // Do we need to update the display ? bool needUpdateDisplay=false; Chronometer chrono; chrono.start(); for(mNbTrial=1;mNbTrial<=nbSteps;) { if((mNbTrial % nbTryPerTemp) == 1) { VFN_DEBUG_MESSAGE("-> Updating temperature and mutation amplitude.",3) // Temperature & displacements amplitude switch(mAnnealingScheduleTemp.GetChoice()) { case ANNEALING_BOLTZMANN: mTemperature= mTemperatureMin*log((REAL)nbSteps)/log((REAL)(mNbTrial+1));break; case ANNEALING_CAUCHY: mTemperature=mTemperatureMin*nbSteps/mNbTrial;break; //case ANNEALING_QUENCHING: case ANNEALING_EXPONENTIAL: mTemperature=mTemperatureMax *pow(mTemperatureMin/mTemperatureMax, mNbTrial/(REAL)nbSteps);break; case ANNEALING_GAMMA: mTemperature=mTemperatureMax+(mTemperatureMin-mTemperatureMax) *pow(mNbTrial/(REAL)nbSteps,mTemperatureGamma);break; case ANNEALING_SMART: { if((nbAcceptedMovesTemp/(REAL)nbTryPerTemp)>0.30) mTemperature/=1.5; if((nbAcceptedMovesTemp/(REAL)nbTryPerTemp)<0.10) mTemperature*=1.5; if(mTemperature>mTemperatureMax) mTemperature=mTemperatureMax; if(mTemperature0.3) mMutationAmplitude*=2.; if((nbAcceptedMovesTemp/(REAL)nbTryPerTemp)<0.1) mMutationAmplitude/=2.; if(mMutationAmplitude>mMutationAmplitudeMax) mMutationAmplitude=mMutationAmplitudeMax; if(mMutationAmplitudeNewConfiguration(); accept=0; REAL cost=this->GetLogLikelihood(); if(costTagNewBestConfig(); needUpdateDisplay=true; mRefParList.SaveParamSet(runBestIndex); if(runBestCostUpdateDisplayNbTrial(); #endif } mNbTrial++;nbStep--; #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif if((runBestCost0)&&(chrono.seconds()>maxTime))) { #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif if(!silent) cout << endl <86400)) ||((mXMLAutoSave.GetChoice()==2)&&((chrono.seconds()-secondsWhenAutoSave)>3600)) ||((mXMLAutoSave.GetChoice()==3)&&((chrono.seconds()-secondsWhenAutoSave)> 600)) ||((mXMLAutoSave.GetChoice()==4)&&(accept==2)) ) { secondsWhenAutoSave=(unsigned long)chrono.seconds(); string saveFileName=this->GetName(); time_t date=time(0); char strDate[40]; strftime(strDate,sizeof(strDate),"%Y-%m-%d_%H-%M-%S",localtime(&date));//%Y-%m-%dT%H:%M:%S%Z char costAsChar[30]; if(accept!=2) mRefParList.RestoreParamSet(mBestParSavedSetIndex); sprintf(costAsChar,"-Cost-%f",this->GetLogLikelihood()); saveFileName=saveFileName+(string)strDate+(string)costAsChar+(string)".xml"; XMLCrystFileSaveGlobal(saveFileName); if(accept!=2) mRefParList.RestoreParamSet(lastParSavedSetIndex); } if((mNbTrial%300==0)&&needUpdateDisplay) { this->UpdateDisplay(); needUpdateDisplay=false; mRefParList.RestoreParamSet(lastParSavedSetIndex); } } //cout<<"Beginning final LSQ refinement? ... "; if(mAutoLSQ.GetChoice()>0) {// LSQ if(!silent) cout<<"Beginning final LSQ refinement"<GetLogLikelihood(); try {mLSQ.Refine(-50,true,true,false,0.001);} catch(const ObjCrystException &except){}; if(!silent) cout<<"LSQ cost: "< "<GetLogLikelihood()<GetLogLikelihood(); if(costGetLogLikelihood(); if(!silent) this->DisplayReport(); if(!silent) chrono.print(); } /* void MonteCarloObj::RunNondestructiveLSQRefinement( int nbCycle,bool useLevenbergMarquardt, const bool silent, const bool callBeginEndOptimization, const float minChi2var ) { float bsigma=-1, bdelta=-1; float asigma=-1, adelta=-1; //set the sigma values lower - it makes the molecular model more stable for LSQ for(int i=0;i(&(mRefinedObjList.GetObj(i))); for(int s=0;sGetScattererRegistry().GetNb();s++) { Molecule *pMol=dynamic_cast(&(pCryst->GetScatt(s))); if(pMol==NULL) continue; // not a Molecule for(vector::iterator pos = pMol->GetBondList().begin(); pos != pMol->GetBondList().end();++pos) { bsigma = (*pos)->GetLengthSigma(); bdelta = (*pos)->GetLengthDelta(); (*pos)->SetLengthDelta(0.02); (*pos)->SetLengthSigma(0.001); } for(vector::iterator pos=pMol->GetBondAngleList().begin();pos != pMol->GetBondAngleList().end();++pos) { asigma = (*pos)->GetAngleSigma(); adelta = (*pos)->GetAngleDelta(); (*pos)->SetAngleDelta(0.2*DEG2RAD); (*pos)->SetAngleSigma(0.01*DEG2RAD); } } } catch (const std::bad_cast& e) { } } } for(int i=0;i(&(mRefinedObjList.GetObj(i))); for(int s=0;sGetScattererRegistry().GetNb();s++) { Molecule *pMol=dynamic_cast(&(pCryst->GetScatt(s))); if(pMol==NULL) continue; // not a Molecule for(vector::iterator pos = pMol->GetBondList().begin(); pos != pMol->GetBondList().end();++pos) { (*pos)->SetLengthDelta(bdelta); (*pos)->SetLengthSigma(bsigma); } for(vector::iterator pos=pMol->GetBondAngleList().begin();pos != pMol->GetBondAngleList().end();++pos) { (*pos)->SetAngleDelta(adelta); (*pos)->SetAngleSigma(asigma); } } } catch (const std::bad_cast& e) { } } } } */ void MonteCarloObj::RunRandomLSQMethod(long &nbCycle) { //perform random move mMutationAmplitude=mMutationAmplitudeMax; float bsigma=-1, bdelta=-1; float asigma=-1, adelta=-1; //set the delta and sigma values - low values are good for LSQ! for(int i=0;i(&(mRefinedObjList.GetObj(i))); for(int s=0;sGetScattererRegistry().GetNb();s++) { Molecule *pMol=dynamic_cast(&(pCryst->GetScatt(s))); if(pMol==NULL) continue; // not a Molecule for(vector::iterator pos = pMol->GetBondList().begin(); pos != pMol->GetBondList().end();++pos) { bsigma = (*pos)->GetLengthSigma(); bdelta = (*pos)->GetLengthDelta(); (*pos)->SetLengthDelta(0.02); (*pos)->SetLengthSigma(0.001); } for(vector::iterator pos=pMol->GetBondAngleList().begin();pos != pMol->GetBondAngleList().end();++pos) { asigma = (*pos)->GetAngleSigma(); adelta = (*pos)->GetAngleDelta(); (*pos)->SetAngleDelta(0.2*DEG2RAD); (*pos)->SetAngleSigma(0.01*DEG2RAD); } } } catch (const std::bad_cast& e){ } } } const long starting_point=mRefParList.CreateParamSet("MonteCarloObj:Last parameters (RANDOM-LSQ)"); mRefParList.SaveParamSet(starting_point); mRun = 0; while(nbCycle!=0) { nbCycle--; mRefParList.RestoreParamSet(starting_point); //this->NewConfiguration(); for(int i=0;iUpdateDisplay(); //perform LSQ for(int i=0;iGetLogLikelihood(); try { mLSQ.Refine(20,true,true,false,0.001); } catch(const ObjCrystException &except) { //cout<<"Something wrong?"< "<GetLogLikelihood()<GetLogLikelihood(); mCurrentCost = lsq_cost; //mRefParList.SaveParamSet(lsqtParSavedSetIndex); if(mCurrentCostUpdateDisplay(); //save it to the file string saveFileName=this->GetName(); time_t date=time(0); char strDate[40]; strftime(strDate,sizeof(strDate),"%Y-%m-%d_%H-%M-%S",localtime(&date));//%Y-%m-%dT%H:%M:%S%Z char costAsChar[30]; sprintf(costAsChar,"#Run%ld-Cost-%f",nbCycle, mCurrentCost); saveFileName=saveFileName+(string)strDate+(string)costAsChar+(string)".xml"; XMLCrystFileSaveGlobal(saveFileName); #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif if(mStopAfterCycle) { #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif break; } #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif mRun++; } if(bsigma<0 || bdelta<0 || asigma<0 || adelta<0) return; //restore the delta and sigma values for(int i=0;i(&(mRefinedObjList.GetObj(i))); for(int s=0;sGetScattererRegistry().GetNb();s++) { Molecule *pMol=dynamic_cast(&(pCryst->GetScatt(s))); if(pMol==NULL) continue; // not a Molecule for(vector::iterator pos = pMol->GetBondList().begin(); pos != pMol->GetBondList().end();++pos) { (*pos)->SetLengthDelta(bdelta); (*pos)->SetLengthSigma(bsigma); } for(vector::iterator pos=pMol->GetBondAngleList().begin();pos != pMol->GetBondAngleList().end();++pos) { (*pos)->SetAngleDelta(adelta); (*pos)->SetAngleSigma(asigma); } } } catch (const std::bad_cast& e){ } } } } void MonteCarloObj::RunParallelTempering(long &nbStep,const bool silent, const REAL finalcost,const REAL maxTime) { TAU_PROFILE("MonteCarloObj::RunParallelTempering()","void ()",TAU_DEFAULT); TAU_PROFILE_TIMER(timer0a,"MonteCarloObj::RunParallelTempering() Begin 1","", TAU_FIELD); TAU_PROFILE_TIMER(timer0b,"MonteCarloObj::RunParallelTempering() Begin 2","", TAU_FIELD); TAU_PROFILE_TIMER(timer1,"MonteCarloObj::RunParallelTempering() New Config + LLK","", TAU_FIELD); TAU_PROFILE_TIMER(timerN,"MonteCarloObj::RunParallelTempering() Finish","", TAU_FIELD); TAU_PROFILE_START(timer0a); //Keep a copy of the total number of steps, and decrement nbStep const long nbSteps=nbStep; unsigned int accept;// 1 if last trial was accepted? 2 if new best config ? else 0 mNbTrial=0; // time (in seconds) when last autoSave was made (if enabled) unsigned long secondsWhenAutoSave=0; // Periodicity of the automatic LSQ refinements (if the option is set) const unsigned int autoLSQPeriod=150000; if(!silent) cout << "Starting Parallel Tempering Optimization"<GetLogLikelihood(); REAL runBestCost=mCurrentCost; CrystVector_REAL currentCost(nbWorld); currentCost=mCurrentCost; // Init the different temperatures CrystVector_REAL simAnnealTemp(nbWorld); for(int i=0;i=0;i--) { if((i!=(nbWorld-1))&&(i%2==0)) for(int j=0;jNewConfiguration(); accept=0; REAL cost=this->GetLogLikelihood(); TAU_PROFILE_STOP(timer1); //trialsDensity((long)(cost*100.),i+1)+=1; if(costTagNewBestConfig(); needUpdateDisplay=true; mRefParList.SaveParamSet(runBestIndex); if(runBestCostTrial :" << mNbTrial << " World="<< worldSwapIndex(i) << " Temp="<< mTemperature << " Mutation Ampl.: "<Trial :" << mNbTrial << " World="<< worldSwapIndex(i) << " Temp="<< mTemperature << " Mutation Ampl.: "<GetLogLikelihood()); saveFileName=saveFileName+(string)strDate+(string)costAsChar+(string)".xml"; XMLCrystFileSaveGlobal(saveFileName); //if(accept!=2) mRefParList.RestoreParamSet(lastParSavedSetIndex); } //if(accept==0) mRefParList.RestoreParamSet(lastParSavedSetIndex); mNbTrial++;nbStep--; if((mNbTrial%nbTrialsReport)==0) makeReport=true; }//nbTryPerWorld trials }//For each World if(mAutoLSQ.GetChoice()==2) if((mNbTrial%autoLSQPeriod)<(nbTryPerWorld*nbWorld)) {// Try a quick LSQ ? for(int i=0;i::iterator pos=mLSQ.GetRefinedObjMap().begin();pos!=mLSQ.GetRefinedObjMap().end();++pos) if(pos->first->GetNbLSQFunction()>0) { CrystVector_REAL tmp; tmp =pos->first->GetLSQCalc(pos->second); tmp-=pos->first->GetLSQObs (pos->second); tmp*=tmp; tmp*=pos->first->GetLSQWeight(pos->second); cout<first->GetClassName()<<":"<first->GetName()<<": GoF="<GetLogLikelihood();// cannot use currentCost(i), approximations changed... if(!silent) cout<<"LSQ: World="<first->GetName()<<": GoF="<GetLogLikelihood(); if(!silent) cout<<" -> "<GetLogLikelihood(); if(!silent) cout<<"LSQ2:"<"<TagNewBestConfig(); needUpdateDisplay=true; mRefParList.SaveParamSet(runBestIndex); if(runBestCostTrial :" << mNbTrial << " World="<< worldSwapIndex(i) << " LSQ2: NEW OVERALL Best Cost="<Trial :" << mNbTrial << " World="<< worldSwapIndex(i) << " LSQ2: NEW RUN Best Cost="<DisplayReport(); } // KLUDGE - after a successful LSQ, we will be close to a minimum, // which will make most successive global optimization trials to // be rejected, until the temperature is increased a lot - this // is a problem as the temperature increases so much that the // benefit of the LSQ is essentially negated. // So we need to use a higher recorded cost, so that successive trials // may be accepted #if 0 mMutationAmplitude=mutationAmplitude(i); for(unsigned int ii=0;ii<4;ii++) this->NewConfiguration(gpRefParTypeObjCryst,false); currentCost(i)=(this->GetLogLikelihood()+cost)/2; if(!silent) cout<<"LSQ3: #"<"<GetLogLikelihood()<GetLogLikelihood()-currentCost(i))/simAnnealTemp(i))) #endif { /* if(i>2) { cout <<"->Swapping Worlds :" << i <<"(cost="<GetLogLikelihood(); mRefParList.RestoreParamSet(worldCurrentSetIndex(i-1)); mMutationAmplitude=mutationAmplitude(i-1); currentCost(i-1)=this->GetLogLikelihood(); #endif } } #if 0 //Try mating worlds- NEW ! TAU_PROFILE_TIMER(timer1,\ "MonteCarloObj::Optimize (Try mating Worlds)"\ ,"", TAU_FIELD); TAU_PROFILE_START(timer1); if( (rand()/(REAL)RAND_MAX)<.1) for(int k=nbWorld-1;k>nbWorld/2;k--) for(int i=k-nbWorld/3;icrossoverPoint1)&&refParGeneGroupIndex(j)GetLogLikelihood(); //if(log((rand()+1)/(REAL)RAND_MAX) // < (-(cost-currentCost(k))/simAnnealTemp(k))) if(costTagNewBestConfig(); needUpdateDisplay=true; mRefParList.SaveParamSet(runBestIndex); if(costTrial :" << mNbTrial << " World="<< worldSwapIndex(k) << " Temp="<< simAnnealTemp(k) << " Mutation Ampl.: "<Trial :" << mNbTrial << " World="<< worldSwapIndex(k) << " Temp="<< simAnnealTemp(k) << " Mutation Ampl.: "<DisplayReport(); //for(int i=0;i ll,llvar; map::iterator pos; for(pos=mvContextObjStats[0].begin();pos!=mvContextObjStats[0].end();++pos) { ll [pos->first]=0.; llvar[pos->first]=0.; } for(int i=0;ifirst] += pos->second.mTotalLogLikelihood; llvar[pos->first] += pos->second.mTotalLogLikelihoodDeltaSq; } } for(pos=mvContextObjStats[0].begin();pos!=mvContextObjStats[0].end();++pos) { cout << pos->first->GetName() << " " << llvar[pos->first] << " " << mvObjWeight[pos->first].mWeight << " " << max<first] *= mvObjWeight[pos->first].mWeight; if(llvar[pos->first]>max) max=llvar[pos->first]; } map::iterator pos2; for(pos2=llvar.begin();pos2!=llvar.end();++pos2) { const REAL d=pos2->second; if(d<(max/mvObjWeight.size()/10.)) { if(d<1) continue; mvObjWeight[pos2->first].mWeight *=2; } } REAL ll1=0; REAL llt=0; for(pos2=ll.begin();pos2!=ll.end();++pos2) { llt += pos2->second; ll1 += pos2->second * mvObjWeight[pos2->first].mWeight; } map::iterator posw; for(posw=mvObjWeight.begin();posw!=mvObjWeight.end();++posw) { posw->second.mWeight *= llt/ll1; } } #endif //Experimental dynamical weighting #if 1 //def __DEBUG__ for(int i=0;i::iterator pos; for(pos=mvContextObjStats[i].begin();pos!=mvContextObjStats[i].end();++pos) { cout << pos->first->GetName() << "(LLK=" << pos->second.mLastLogLikelihood //<< "(=" //<< pos->second.mTotalLogLikelihood/nbTrialsReport //<< ", =" //<< pos->second.mTotalLogLikelihoodDeltaSq/nbTrialsReport << ", w="<first].mWeight <<") "; pos->second.mTotalLogLikelihood=0; pos->second.mTotalLogLikelihoodDeltaSq=0; } cout << endl; } #endif for(int i=0;i0.30) mutationAmplitude(i)*=2.; if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)<0.10) mutationAmplitude(i)/=2.; if(mutationAmplitude(i)>mMutationAmplitudeMax) mutationAmplitude(i)=mMutationAmplitudeMax; if(mutationAmplitude(i)0.30) simAnnealTemp(i)/=1.5; if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)>0.80) simAnnealTemp(i)/=1.5; if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)>0.95) simAnnealTemp(i)/=1.5; if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)<0.10) simAnnealTemp(i)*=1.5; if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)<0.04) simAnnealTemp(i)*=1.5; //if((worldNbAcceptedMoves(i)/(REAL)nbTrialsReport)<0.01) // simAnnealTemp(i)*=1.5; //cout<<"World#"<mTemperatureMax) simAnnealTemp(i)=mTemperatureMax; //if(simAnnealTemp(i)DisplayReport(); #ifdef __WX__CRYST__ if(0!=mpWXCrystObj) mpWXCrystObj->UpdateDisplayNbTrial(); #endif } if( (needUpdateDisplay&&(lastUpdateDisplayTime<(chrono.seconds()-1)))||(lastUpdateDisplayTime<(chrono.seconds()-10))) { mRefParList.RestoreParamSet(runBestIndex); this->UpdateDisplay(); needUpdateDisplay=false; lastUpdateDisplayTime=chrono.seconds(); } #ifdef __WX__CRYST__ mMutexStopAfterCycle.Lock(); #endif if((runBestCost0)&&(chrono.seconds()>maxTime))) { #ifdef __WX__CRYST__ mMutexStopAfterCycle.Unlock(); #endif if(!silent) cout << endl <0) {// LSQ if(!silent) cout<<"Beginning final LSQ refinement"<GetLogLikelihood(); try {mLSQ.Refine(-50,true,true,false,0.001);} catch(const ObjCrystException &except){}; if(!silent) cout<<"LSQ cost: "< "<GetLogLikelihood()<GetLogLikelihood(); if(costDisplayReport(); mRefParList.RestoreParamSet(runBestIndex); //for(int i=0;iGetLogLikelihood(); if(!silent) cout<<"Run Best Cost:"<GetName(),5) for(int i=0;iGetName()); tag.AddAttribute("NbTrialPerRun",(boost::format("%d")%(this->NbTrialPerRun())).str()); os <GetName(),5) } void MonteCarloObj::XMLInput(istream &is,const XMLCrystTag &tagg) { VFN_DEBUG_ENTRY("MonteCarloObj::XMLInput():"<GetName(),5) for(unsigned int i=0;iSetName(tagg.GetAttributeValue(i)); if("NbTrialPerRun"==tagg.GetAttributeName(i)) { stringstream ss(tagg.GetAttributeValue(i)); long v; ss>>v; this->NbTrialPerRun()=v; } } while(true) { XMLCrystTag tag(is); if(("GlobalOptimObj"==tag.GetName())&&tag.IsEndTag()) { VFN_DEBUG_EXIT("MonteCarloObj::Exit():"<GetName(),5) this->UpdateDisplay(); return; } if("Option"==tag.GetName()) { for(unsigned int i=0;i>mTemperatureMax>> mTemperatureMin; if(false==tag.IsEmptyTag()) XMLCrystTag junk(is);//:KLUDGE: for first release continue; } if("MutationMaxMin"==tag.GetName()) { is>>mMutationAmplitudeMax>>mMutationAmplitudeMin; if(false==tag.IsEmptyTag()) XMLCrystTag junk(is);//:KLUDGE: for first release continue; } if("RefinedObject"==tag.GetName()) { string name,type; for(unsigned int i=0;iAddRefinableObj(*obj); continue; } } } const string MonteCarloObj::GetClassName()const { return "MonteCarloObj";} LSQNumObj& MonteCarloObj::GetLSQObj() {return mLSQ;} const LSQNumObj& MonteCarloObj::GetLSQObj() const{return mLSQ;} void MonteCarloObj::NewConfiguration(const RefParType *type) { TAU_PROFILE("MonteCarloObj::NewConfiguration()","void ()",TAU_DEFAULT); VFN_DEBUG_ENTRY("MonteCarloObj::NewConfiguration()",4) for(int i=0;iOptimizationObj::InitOptions(); static string GlobalOptimTypeName; static string GlobalOptimTypeChoices[2];//:TODO: Add Genetic Algorithm static string AnnealingScheduleChoices[6]; static string AnnealingScheduleTempName; static string AnnealingScheduleMutationName; static string runAutoLSQName; static string runAutoLSQChoices[3]; static string saveTrackedDataName; static string saveTrackedDataChoices[2]; static bool needInitNames=true; if(true==needInitNames) { GlobalOptimTypeName="Algorithm"; GlobalOptimTypeChoices[0]="Simulated Annealing"; GlobalOptimTypeChoices[1]="Parallel Tempering"; //GlobalOptimTypeChoices[2]="Random-LSQ"; AnnealingScheduleTempName="Temperature Schedule"; AnnealingScheduleMutationName="Displacement Amplitude Schedule"; AnnealingScheduleChoices[0]="Constant"; AnnealingScheduleChoices[1]="Boltzmann"; AnnealingScheduleChoices[2]="Cauchy"; AnnealingScheduleChoices[3]="Exponential"; AnnealingScheduleChoices[4]="Smart"; AnnealingScheduleChoices[5]="Gamma"; runAutoLSQName="Automatic Least Squares Refinement"; runAutoLSQChoices[0]="Never"; runAutoLSQChoices[1]="At the end of each run"; runAutoLSQChoices[2]="Every 150000 trials, and at the end of each run"; saveTrackedDataName="Save Tracked Data"; saveTrackedDataChoices[0]="No (recommended!)"; saveTrackedDataChoices[1]="Yes (for tests ONLY)"; needInitNames=false;//Only once for the class } mGlobalOptimType.Init(2,&GlobalOptimTypeName,GlobalOptimTypeChoices); mAnnealingScheduleTemp.Init(6,&AnnealingScheduleTempName,AnnealingScheduleChoices); mAnnealingScheduleMutation.Init(6,&AnnealingScheduleMutationName,AnnealingScheduleChoices); mSaveTrackedData.Init(2,&saveTrackedDataName,saveTrackedDataChoices); mAutoLSQ.Init(3,&runAutoLSQName,runAutoLSQChoices); this->AddOption(&mGlobalOptimType); this->AddOption(&mAnnealingScheduleTemp); this->AddOption(&mAnnealingScheduleMutation); this->AddOption(&mSaveTrackedData); this->AddOption(&mAutoLSQ); VFN_DEBUG_MESSAGE("MonteCarloObj::InitOptions():End",5) } void MonteCarloObj::InitLSQ(const bool useFullPowderPatternProfile) { mLSQ.SetRefinedObj(mRecursiveRefinedObjList.GetObj(0),0,true,true); for(unsigned int i=1;i::iterator pos=mLSQ.GetRefinedObjMap().begin();pos!=mLSQ.GetRefinedObjMap().end();++pos) if(pos->first->GetClassName()=="PowderPattern") pos->second=1; } // Only refine structural parameters (excepting parameters already fixed) and scale factor mLSQ.PrepareRefParList(true); // Intensity corrections can be refined std::list vIntCorrPar; for(int i=0; iIsDescendantFromOrSameAs(gpRefParTypeScattDataCorrInt) && mLSQ.GetCompiledRefinedObj().GetPar(i).IsFixed()==false) vIntCorrPar.push_back(&mLSQ.GetCompiledRefinedObj().GetPar(i)); mLSQ.SetParIsFixed(gpRefParTypeScattData,true); mLSQ.SetParIsFixed(gpRefParTypeScattDataScale,false); for(std::list::iterator pos=vIntCorrPar.begin();pos!=vIntCorrPar.end();pos++) (*pos)->SetIsFixed(false); mLSQ.SetParIsFixed(gpRefParTypeUnitCell,true); mLSQ.SetParIsFixed(gpRefParTypeScattPow,true); mLSQ.SetParIsFixed(gpRefParTypeRadiation,true); } void MonteCarloObj::UpdateDisplay() const { Chronometer chrono; #ifdef __WX__CRYST__ if(0!=mpWXCrystObj) mpWXCrystObj->CrystUpdate(true,true); #endif this->OptimizationObj::UpdateDisplay(); } #ifdef __WX__CRYST__ WXCrystObjBasic* MonteCarloObj::WXCreate(wxWindow *parent) { mpWXCrystObj=new WXMonteCarloObj (parent,this); return mpWXCrystObj; } WXOptimizationObj* MonteCarloObj::WXGet() { return mpWXCrystObj; } void MonteCarloObj::WXDelete() { if(0!=mpWXCrystObj) delete mpWXCrystObj; mpWXCrystObj=0; } void MonteCarloObj::WXNotifyDelete() { mpWXCrystObj=0; } #endif }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/GlobalOptimObj.h000066400000000000000000000644051417150057700246550ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* OptimizationObj.h * header file for the Global Optimization object * */ #ifndef _GLOBALOPTIMOBJ_H #define _GLOBALOPTIMOBJ_H #include #include "ObjCryst/ObjCryst/General.h" namespace ObjCryst { class OptimizationObj; class MonteCarloObj; } #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/RefinableObj/LSQNumObj.h" #include "ObjCryst/RefinableObj/IO.h" #include "ObjCryst/RefinableObj/Tracker.h" #include #include #ifdef __WX__CRYST__ //#undef GetClassName // Conflict from wxMSW headers ? (cygwin) #include "ObjCryst/wxCryst/wxGlobalOptimObj.h" #endif namespace ObjCryst { /** Annealing schedule type. Used to determine the variation of the * temperature and the mutation amplitude * * With A=Temperature or A=MutationAMplitude, and the corresponding , min and max values supplied (the latter is ignored for constant, * Cauchy and Boltzmann), with 'step' being the current step, and * NbStep the total number of steps. (In the Parallel Tempering * algorithm, a 'step' denotes one of the parallel refinement). * \f[ A_{constant} = A_{min}\f] * \f[ A_{Boltzmann} = A_{min} \frac{\ln(NbStep)}{\ln(step)} \f] * \f[ A_{Cauchy} = A_{min} \frac{NbStep}{step} \f] * \f[ A_{exponential} = A_{max} (\frac{T_{min}}{T_{max}})^{\frac{step}{NbStep}} \f] * \f[ A_{\gamma} = A_{max} +(A_{min}-A_{max}*(\frac{step}{NbStep})^{\gamma} \f] * * For the 'smart' schedule, it is only supported so far for the mutation amplitude: * it is modulated so that for each temperature between 30 and 70% of trial * configurations are accepted, within the limits for the mutation. */ enum AnnealingSchedule { ANNEALING_CONSTANT, ANNEALING_BOLTZMANN, ANNEALING_CAUCHY, // ANNEALING_QUENCHING, ANNEALING_EXPONENTIAL, ANNEALING_SMART, ANNEALING_GAMMA }; /** Global optimization type. Eventually it would be better to build * a base Global Optimization (or even Optimization) object, and to derive * it in different classes for Simulated Annealing, Parallel Tempering, * Genetic Algorithm,... */ enum GlobalOptimType { GLOBAL_OPTIM_SIMULATED_ANNEALING, GLOBAL_OPTIM_PARALLEL_TEMPERING, GLOBAL_OPTIM_RANDOM_LSQ, GLOBAL_OPTIM_SIMULATED_ANNEALING_MULTI, GLOBAL_OPTIM_PARALLEL_TEMPERING_MULTI, }; /** \brief Base object for Optimization methods. * * This is an abstract base class, derived for Monte-Cralo type algorithms * (Simulated Annealing & Parallel Tempering), and hopefully soon * for Genetic Algorithms. * * \remarks Instead of keeping a copy of the list of parameters here, * maybe it would be better to delegate all parameter handling to the refined * objects (they would also have to keep in memory the saved parameter sets, so * that could be difficult to administrate...). */ class OptimizationObj { public: /// Default constructor OptimizationObj(); /// Constructor OptimizationObj(const string name); /// Copy constructor OptimizationObj(const OptimizationObj &old); /// Destructor virtual ~OptimizationObj(); /** \brief Randomize starting configuration. Only affects limited and periodic parameters. */ virtual void RandomizeStartingConfig(); /// Launch optimization (a single run) for N steps /// \param nbSteps: the number of steps to go. This number is modified (decreases!) /// as the refinement goes on. /// \param silent : if true, absolutely no message should be printed (except debugging) /// \param finalcost: the optimization will stop if overall cost fallse below this value /// \param maxTime: the optimization will stop after the given number of seconds has /// been spent optimizing (ignored if <0). virtual void Optimize(long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1)=0; /** Launch optimization for multiple runs of N steps * \param nbCycle: the number of runs (cycles) to perform. The structure is randomized * at the beginning of each cycle. If nbCycle==-1, this will run indefinitely. * The nbCycle parameter is decreased after each run. * \param nbSteps: the number of steps to go. This number is modified (decreases!) * as the refinement goes on. * \param silent : if true, absolutely no message should be printed (except debugging) * \param finalcost: the optimization will stop if overall cost fallse below this value * \param maxTime: the optimization will stop after the given number of seconds has * been spent optimizing (ignored if <0). */ virtual void MultiRunOptimize(long &nbCycle,long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1)=0; //Set Refinable parameters status /// Fix all parameters void FixAllPar(); /// Fix one parameter void SetParIsFixed(const string& parName,const bool fix); /// Fix one family of parameters void SetParIsFixed(const RefParType *type,const bool fix); /// UnFix All parameters void UnFixAllPar(); /// Set a parameter to be used void SetParIsUsed(const string& parName,const bool use); /// Set a family of parameters to be used void SetParIsUsed(const RefParType *type,const bool use); /// Change the relative limits for a parameter from its name void SetLimitsRelative(const string &parName, const REAL min, const REAL max); /// Change the relative limits for a family of parameter void SetLimitsRelative(const RefParType *type, const REAL min, const REAL max); /// Change the absolute limits for a parameter from its name void SetLimitsAbsolute(const string &parName, const REAL min, const REAL max); /// Change the absolute limits for a family of parameter void SetLimitsAbsolute(const RefParType *type, const REAL min, const REAL max); /** \brief The optimized (minimized, actually) function. * * This function is the weighted sum of the chosen Cost Functions for * the refined objects. */ virtual REAL GetLogLikelihood()const; /// Stop after the current cycle. USed for interactive refinement. void StopAfterCycle(); /// Show report to the user during refinement. Used for GUI update. virtual void DisplayReport(); /// Add a refined object. All sub-objects are also added void AddRefinableObj(RefinableObj &); /// Get the RefinableObj with all the parameters from all refined objects. /// If rebuild=true, prepare again the list of objects/parameters. RefinableObj& GetFullRefinableObj(const bool rebuild=true); /** \brief Output a description of the object in XML format to a stream. * * This saves the list of refined object and the cost functions, as well as options * for the refinement. The refined objects are \b not saved, so this must be done * somewhere else (they must be reloaded before this object). */ virtual void XMLOutput(ostream &os,int indent=0)const=0; /** \brief Input in XML format from a stream, restoring the set of refined * objects and the associated cost functions. Note that the corresponding objects * must have been loaded in memory before, else shit happens. * */ virtual void XMLInput(istream &is,const XMLCrystTag &tag)=0; //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); /// Get the name for this object const string& GetName()const; /// Set the name for this object void SetName(const string&); /// Get the name for this class type virtual const string GetClassName()const; /// Print some information about this object virtual void Print()const; /// Restore the Best configuration void RestoreBestConfiguration(); /// Are we busy optimizing ? bool IsOptimizing()const; /** During a global optimization, tell all objects that the current config is * the latest "best" config. */ void TagNewBestConfig(); /// Get the elapsed time (in seconds) during the last optimization REAL GetLastOptimElapsedTime()const; /// Get the MainTracker MainTracker& GetMainTracker(); /// Get the MainTracker const MainTracker& GetMainTracker()const; RefObjOpt& GetXMLAutoSaveOption(); const RefObjOpt& GetXMLAutoSaveOption()const; /// Access to current best cost const REAL& GetBestCost()const; /// Access to current best cost REAL& GetBestCost(); /// Begin optimization for all objects virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); /// End optimization for all objects virtual void EndOptimization(); /// Number of trial per run virtual long& NbTrialPerRun(); /// Number of trial per run virtual const long& NbTrialPerRun() const; /// Current trial number (updated during a run) long GetTrial() const; /// Current run number (updated during a run) long GetRun() const; //Options /// Access to the options registry ObjRegistry& GetOptionList(); /// Number of Options for this object unsigned int GetNbOption()const; /// Access to the options RefObjOpt& GetOption(const unsigned int i); /// Access to the options by name RefObjOpt& GetOption(const string & name); /// const access to the options const RefObjOpt& GetOption(const unsigned int i)const; /// const access to the options by name const RefObjOpt& GetOption(const string & name)const; /// Access the list of refined object const ObjRegistry& GetRefinedObjList() const; /// Update Display (if any display is available), when a new 'relevant' configuration /// is reached. This calls all RefinableObj::UpdateDisplay() virtual void UpdateDisplay() const; /// Get the number of saved parameters set unsigned int GetNbParamSet() const; /// Get the index of a saved parameters set in the compiled RefinableObj. /// The parameters can then be accessed using GetRefinedObjList().GetParamSet(idx) long GetParamSetIndex(const unsigned int i) const; /// Get the cost (log-likelihood) of a saved parameters set long GetParamSetCost(const unsigned int i) const; /// Restore a given saved parameter set. /// This is equivalent to GetRefinedObjList().RestoreParamSet(GetSavedParamSetIndex(i)) /// \param i: the order of the saved parameter set void RestoreParamSet(const unsigned int i, const bool update_display=true); protected: /// \internal Prepare mRefParList for the refinement void PrepareRefParList(); /// Initialization of options. virtual void InitOptions(); /// (Re)build OptimizationObj::mRecursiveRefinedObjList, if an /// object has been added or modified. If no object has been /// added and no sub-object has been added/removed, then nothing is done. void BuildRecursiveRefObjList(); /// \internal Add an option for this parameter void AddOption(RefObjOpt *opt); /// The refinable par list used during refinement. Only a condensed version /// of all objects. This is useful to keep an history of modifications, and to /// restore previous values. /// \remarks maybe this should be completely delegated to the refined objetcs. mutable RefinableObj mRefParList; /// Name of the GlobalOptimization object string mName; /// File name where refinement info is saved (NOT USED so far...) string mSaveFileName; //Status of optimization /// Number of trial per run, to be saved/restored in XML output long mNbTrialPerRun; /// Current trial number long mNbTrial; /// Current run number (during multiple runs) long mRun; /// Best value of the cost function so far REAL mBestCost; /// Index of the 'best' saved parameter set long mBestParSavedSetIndex; /// The current 'context', in the case the optimization is run in different /// parallel contexts unsigned long mContext; /// Statistics about each object contributing to the overall Log(likelihood) struct LogLikelihoodStats { /// Previous log(likelihood) REAL mLastLogLikelihood; /// Total Log(Likelihood), to compute the average REAL mTotalLogLikelihood; /// total of (Delta(Log(Likelihood)))^2 between successive trials REAL mTotalLogLikelihoodDeltaSq; }; /// Statistics for each context /// (mutable for dynamic update during optimization) mutable map > mvContextObjStats; // Dynamic weights (EXPERIMENTAL!) struct DynamicObjWeight { DynamicObjWeight():mWeight(1.){}; REAL mWeight; }; /// Weights for each objects in each context /// (mutable for dynamic update during optimization) mutable map mvObjWeight; /// List of saved parameter sets. This is used to save possible /// solutions during the optimization, so that the user can check them /// afterwards. /// /// The first member of each pair is the \e index of the parameter set, /// and the second is the overall cost for that set. std::vector > mvSavedParamSet; /// True if a refinement is being done. For multi-threaded environment bool mIsOptimizing; /// If true, then stop at the end of the cycle. Used in multi-threaded environment bool mStopAfterCycle; // Refined objects /// The refined objects. This is mutable to allow a copy constructor for /// the OptimizationObj, and because the objects are not owned /// but rather referenced here. mutable ObjRegistry mRefinedObjList; /// The refined objects, recursively including all sub-objects. /// This is mutable, since it is a function of mRefinedObjList only. mutable ObjRegistry mRecursiveRefinedObjList; /// Periodic save of complete environment as an xml file RefObjOpt mXMLAutoSave; /// The time elapsed after the last optimization, in seconds REAL mLastOptimTime; /// MainTracker object to track the evolution of cost functions, likelihood, /// and individual parameters. MainTracker mMainTracker; /// List of options for this object. Note that these are just references, /// to options allocated by the object, to have a simple global access to /// all options ObjRegistry mOptionRegistry; private: #ifdef __WX__CRYST__ public: /// Create a WXCrystObj for this object. virtual WXCrystObjBasic* WXCreate(wxWindow*)=0; virtual WXOptimizationObj* WXGet()=0; virtual void WXDelete()=0; virtual void WXNotifyDelete()=0; protected: //:TODO: remove this ! friend class ObjCryst::WXOptimizationObj; //friend class ObjCryst::WXMonteCarloObj; //friend class ObjCryst::WXGeneticAlgorithm; /// Mutex used to protect mStopAfterCycle wxMutex mMutexStopAfterCycle; #endif }; /** \brief Base object for Monte-Carlo Global Optimization methods. * * The algorithm is quite simple, whith two type of optimizations, either * simulated Annealing or Parallel Tempering, the latter being recommanded * for most real-world optimizations. * */ class MonteCarloObj:public OptimizationObj { public: /// Default Constructor MonteCarloObj(); /// Constructor MonteCarloObj(const string name); /// Copy constructor MonteCarloObj(const MonteCarloObj &old); /// Constructor. Using internalUseOnly=true will avoid registering the /// the object to any registry, and thus (for example) no display will be created, /// nor will this object be automatically be saved. MonteCarloObj(const bool internalUseOnly); /// Destructor virtual ~MonteCarloObj(); /** \brief Set the refinement method to simulated Annealing. Note that * Parellel Tempering is more efficient to get out of local minima, so you sould * rather use that method. * * The refinement begins at max and finishes at min temperature. * *\param scheduleTemp: temperature schedule. See AnnealingSchedule. *\param tMax,tMin: Max and Min temperatures. *\param scheduleMutation: the mutation schedule. For each new configuration, the * variation of each refinable parameter is less than its RefinablePar::GlobalOptimStep(), * multiplied by the current mutation amplitude. By default this mutation is equal to 1., * but making bigger steps is a good idea at the beginning of the refinement * (for higher temperatures). See AnnealingSchedule. See AnnealingSchedule. *\param mutMax,mutMin: Max and Min mutation amplitudes. *\param minCostRetry, nbTrialRetry: if after nbTrialRetry, the cost function is still * above minCostRetry, then start again from a random configuration. No randomization is * made if nbTrialRetry <= 0. *\param maxNbTrialSinceBest: if more than maxNbTrialSinceBest trials have been made * since the best configuration was recorded, then revert to that configuration. This * should be large enough to have an ergodic search (the default is never to revert..) * * \warning do not use the 'smart' option for the temperature schedule, it is not yet * implemented. Later it will be used to set the temperatures as a function of * the amplitude schedule, so that we accept between 30% and 70% moves. * \note this will be removed when we separate the different algorithms in different * classes. */ void SetAlgorithmSimulAnnealing(const AnnealingSchedule scheduleTemp, const REAL tMax, const REAL tMin, const AnnealingSchedule scheduleMutation=ANNEALING_CONSTANT, const REAL mutMax=16., const REAL mutMin=.125, const long nbTrialRetry=0,const REAL minCostRetry=0.); /** \brief Set the refinement method to Parallel Tempering. * * The refinement begins at max and finishes at min temperature. * *\param scheduleTemp: temperature schedule *\param tMax,tMin: Max and Min temperatures. See AnnealingSchedule. *\param scheduleMutation: the mutation schedule. For each new configuration, the * variation of each refinable parameter is less than its RefinablePar::GlobalOptimStep(), * multiplied by the current mutation amplitude. By default this mutation is equal to 1., * but making bigger steps can be a good idea at the beginning of the refinement. Thus * you can choose a schedule for the amplitude, exactly like for the temperature. *\param mutMax,mutMin: Max and Min mutation amplitudes. * \warning do not use the 'smart' option for the temperature schedule, it is not yet * implemented. Later it will be used to set the temperatures as a function of * the amplitude schedule, so that we keep accepted move between 30% and 70%. * \note this will be removed when we separate the different algorithms in different * classes. */ void SetAlgorithmParallTempering(const AnnealingSchedule scheduleTemp, const REAL tMax, const REAL tMin, const AnnealingSchedule scheduleMutation=ANNEALING_CONSTANT, const REAL mutMax=16., const REAL mutMin=.125); virtual void Optimize(long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1); virtual void MultiRunOptimize(long &nbCycle,long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1); /** \internal Do a single simulated annealing run. This is called by Optimize(...) and * MultiRunOptimize(), which must also prepare the optimization (PrepareRefParList(), etc..). */ void RunSimulatedAnnealing(long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1); /** \internal Do a single Parallel Tempering run. This is called by Optimize(...) and * MultiRunOptimize(), which must also prepare the optimization (PrepareRefParList(), etc..). */ void RunParallelTempering(long &nbSteps,const bool silent=false,const REAL finalcost=0, const REAL maxTime=-1); void RunRandomLSQMethod(long &nbCycle); //Parameter Access by name //RefinablePar& GetPar(const string& parName); // Print information about the current state of optimization (parameters value, // characteristic figures...) //virtual ostream& operator<<(ostream& os)const; virtual void XMLOutput(ostream &os,int indent=0)const; virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); virtual const string GetClassName()const; /// Access to the builtin LSQ optimization object LSQNumObj & GetLSQObj(); /// Access to the builtin LSQ optimization object const LSQNumObj & GetLSQObj() const; /** Prepare mLSQ for least-squares refinement during the global optimization * * \param useFullPowderPatternProfile: if true, the refinement will use the full * profile version of powder patterns, otherwise only the integrated powder pattern * will be used (faster). */ virtual void InitLSQ(const bool useFullPowderPatternProfile=true); /// Update Display (if any display is available), when a new 'relevant' configuration /// is reached. This calls all RefinableObj::UpdateDisplay() virtual void UpdateDisplay() const; protected: /** \brief Make a random change in the configuration. * * \internal * This just generates a new configuration with random changes (according * to current parameters). The new configuration is \e not tested \e in \e this \e function * vs temperature: this should be done in the OptimizationObj::Optimize() function, * which also chooses whether to revert to the previous configuration. * * Random moves are made by the objects and not by this function, * because the new configuration can be specific * (like, for example, permutations between some of the parameters (atoms)). * * \param type: can be used to restrict the move to a given category of parameters. */ virtual void NewConfiguration(const RefParType *type=gpRefParTypeObjCryst); virtual void InitOptions(); /// Method used for the global optimization. Should be removed when we switch /// to using several classes for different algorithms. RefObjOpt mGlobalOptimType; //Status of optimization /// Current value of the cost function REAL mCurrentCost; // History, for experimental purposes only ! /// Option to save the evolution of tracked data (cost functions, /// likelihhod, individual parameters,...) RefObjOpt mSaveTrackedData; // Annealing parameters /// Current temperature for annealing REAL mTemperature; /// Beginning temperature for annealing REAL mTemperatureMax; /// Lower temperature REAL mTemperatureMin; /// Schedule for the annealing RefObjOpt mAnnealingScheduleTemp; /// Gamma for the 'gamma' temperature schedule REAL mTemperatureGamma; //Parameters to create new configurations /// Mutation amplitude. From .25 to 64. Random moves will have a maximum amplitude /// equal to this amplitude multiplied by the Global optimization step defined /// for each RefinablePar. Large amplitude should be used at the beginning of the /// refinement (high temeratures). REAL mMutationAmplitude; /// Mutation amplitude at the beginning of the optimization. REAL mMutationAmplitudeMax; /// Mutation amplitude at the end of the optimization. REAL mMutationAmplitudeMin; /// Schedule for the annealing RefObjOpt mAnnealingScheduleMutation; /// Gamma for the 'gamma' Mutation amplitude schedule REAL mMutationAmplitudeGamma; //Automatic retry /// Number of trials before testing if we are below the given minimum cost. /// If <=0, this will be ignored. long mNbTrialRetry; /// Cost to reach unless an automatic randomization and retry is done REAL mMinCostRetry; /// Least squares object LSQNumObj mLSQ; /// Option to run automatic least-squares refinements RefObjOpt mAutoLSQ; private: #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow*); virtual WXOptimizationObj* WXGet(); virtual void WXDelete(); virtual void WXNotifyDelete(); protected: WXMonteCarloObj* mpWXCrystObj; friend class ObjCryst::WXMonteCarloObj; #endif }; /// Global Registry for all OptimizationObj extern ObjRegistry gOptimizationObjRegistry; }// namespace #endif //_GLOBALOPTIMOBJ_H libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/IO.cpp000066400000000000000000000335061417150057700226510ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for generic XMLInput/XMLOutput in * */ #include #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/RefinableObj/IO.h" namespace ObjCryst { //////////////////////////////////////////////////////////////////////// // // XMLCrystTag // //////////////////////////////////////////////////////////////////////// XMLCrystTag::XMLCrystTag(): mIsEndTag(false),mIsEmptyTag(false) {} XMLCrystTag::XMLCrystTag(istream &is) { is >> *this; } XMLCrystTag::XMLCrystTag(const string &tagName, const bool isEndTag, const bool isEmptyTag): mName(tagName),mIsEndTag(isEndTag),mIsEmptyTag(isEmptyTag) {} XMLCrystTag::~XMLCrystTag(){} const string& XMLCrystTag::GetName()const{return mName;} const string& XMLCrystTag::GetClassName()const{static string str="XMLCrystTag";return str;} unsigned int XMLCrystTag::GetNbAttribute()const{return mvAttribute.size();} void XMLCrystTag::AddAttribute(const string &attName,const string &attValue) { VFN_DEBUG_ENTRY("XMLCrystTag::AddAttribute():"<GetName(),4) mvAttribute.push_back(make_pair(attName,attValue)); VFN_DEBUG_EXIT("XMLCrystTag::AddAttribute():"<GetName(),4) } void XMLCrystTag::GetAttribute(const int attNum,string &attName,string &attValue) { attName=mvAttribute[attNum].first; attValue=mvAttribute[attNum].second; } const string& XMLCrystTag::GetAttributeName(const int attNum)const {return mvAttribute[attNum].first;} const string& XMLCrystTag::GetAttributeValue(const int attNum)const {return mvAttribute[attNum].second;} void XMLCrystTag::SetIsEndTag(const bool isEndTag){mIsEndTag=isEndTag;} bool XMLCrystTag::IsEndTag()const{return mIsEndTag;} void XMLCrystTag::SetIsEmptyTag(const bool isEmptyTag){mIsEmptyTag=isEmptyTag;} bool XMLCrystTag::IsEmptyTag()const{return mIsEmptyTag;} void XMLCrystTag::Print()const{cout<<*this;} #ifdef __WX__CRYST__ WXCrystObj* XMLCrystTag::WXCreate(wxWindow *parent) { //:TODO: //mpWXXMLCrystTag=new WXXMLCrystTag (parent,this); return mpWXXMLCrystTag; } WXCrystObj* XMLCrystTag::WXGet() { return mpWXXMLCrystTag; } void XMLCrystTag::WXDelete() { if(0!=mpWXXMLCrystTag) delete mpWXXMLCrystTag; mpWXXMLCrystTag=0; } void XMLCrystTag::WXNotifyDelete() { mpWXXMLCrystTag=0; } #endif ostream& operator<< (ostream& os, const XMLCrystTag&tag) { if(true==tag.mIsEndTag) { os <<""; return os; } os <<"<"<"; else os <<">"; return os; } istream& operator>> (istream& is, XMLCrystTag &tag) { ios::fmtflags f=is.flags(); is.unsetf(ios::skipws);//skip whitespaces tag.mIsEmptyTag=false; tag.mIsEndTag=false; char tmp; is>>tmp; while ((tmp!='<') && !(is.eof()) && !(is.fail()) )is>>tmp; if(is.eof()) return is; if(is.fail()) {cout<<"throw:"<<__FILE__<<":"<<__LINE__<<":"<> failed input");} while ((tmp==' ')||(tmp=='<'))is>>tmp; if('/'==tmp) { tag.mIsEndTag=true; while ((tmp==' ')||(tmp=='/'))is>>tmp; } string str=""; do { str+=tmp; is>>tmp; VFN_DEBUG_MESSAGE(str,1); if(is.fail()) {cout<<"throw:"<<__FILE__<<":"<<__LINE__<<":"<> failed input");} } while ((tmp!=' ')&&(tmp!='>')&&(tmp!='/')); tag.mName=str; string str2; while(true) { while(tmp==' ')is>>tmp; if(tmp=='>') { is.setf(f); return is; } if(tmp=='/') { is>>tmp; //if(tmp!='>') ; :TODO: tag.mIsEmptyTag=true; is.setf(f); return is; } str=""; do {str+=tmp;is>>tmp;VFN_DEBUG_MESSAGE(str,1)} while ((tmp!=' ')&&(tmp!='=')); while(tmp!='"')is>>tmp; str2=""; is>>tmp; if(tmp!='"') do {str2+=tmp;is>>tmp;VFN_DEBUG_MESSAGE(str2,1)} while (tmp!='"'); is>>tmp; tag.AddAttribute(str,str2); } is.setf(f); return is; } //////////////////////////////////////////////////////////////////////// // // I/O RefinablePar // //////////////////////////////////////////////////////////////////////// void RefinablePar::XMLOutput(ostream &os,const string &name,int indent)const { VFN_DEBUG_ENTRY("RefinablePar::XMLOutput():"<GetName(),5) XMLCrystTag tag("Par"); { stringstream ss; ss <IsFixed()); tag.AddAttribute("Refined",ss.str()); } { stringstream ss; ss <IsLimited(); tag.AddAttribute("Limited",ss.str()); } { stringstream ss; ss <GetHumanMin(); tag.AddAttribute("Min",ss.str()); } { stringstream ss; ss <GetHumanMax(); tag.AddAttribute("Max",ss.str()); } #if 0 {//Useless. Periodicity cannot be changed for a given parameter stringstream ss; ss <IsPeriodic(); tag.AddAttribute("Periodic",ss.str()); } #endif //the name of the parameter is saved last to enhance readability of saved files tag.AddAttribute("Name",name); for(int i=0;iGetHumanValue()<GetName(),5) } void RefinablePar::XMLOutput(ostream &os,int indent)const { this->XMLOutput(os,mName,indent); } void RefinablePar::XMLInput(istream &is,const XMLCrystTag &tag) { VFN_DEBUG_ENTRY("RefinablePar::XMLInput():"<GetName(),5) for(unsigned int i=0;i>b; this->SetIsFixed(!b); continue; } if("Limited"==tag.GetAttributeName(i)) { bool b; stringstream ss(tag.GetAttributeValue(i)); ss.imbue(std::locale::classic()); ss >>b; this->SetIsLimited(b); continue; } if("Min"==tag.GetAttributeName(i)) { REAL f; stringstream ss(tag.GetAttributeValue(i)); ss.imbue(std::locale::classic()); ss >>f; this->SetHumanMin(f); continue; } if("Max"==tag.GetAttributeName(i)) { REAL f; stringstream ss(tag.GetAttributeValue(i)); ss.imbue(std::locale::classic()); ss >>f; this->SetHumanMax(f); continue; } if("Periodic"==tag.GetAttributeName(i)) { bool b; stringstream ss(tag.GetAttributeValue(i)); ss.imbue(std::locale::classic()); ss >>b; this->SetIsPeriodic(b); continue; } } VFN_DEBUG_MESSAGE(tag, 10) REAL f=InputFloat(is,'<'); if(ISNAN_OR_INF(f)) f=1.0; this->SetHumanValue(f); XMLCrystTag junk(is);//read end tag VFN_DEBUG_MESSAGE(tag, 10) VFN_DEBUG_EXIT("RefinablePar::XMLInput():"<GetName(),5) } //////////////////////////////////////////////////////////////////////// // // I/O RefObjOpt // //////////////////////////////////////////////////////////////////////// void RefObjOpt::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_ENTRY("RefObjOpt::XMLOutput():"<GetName(),5) XMLCrystTag tag("Option",false,true); tag.AddAttribute("Name",this->GetName()); { stringstream ss; ss <GetChoice(); tag.AddAttribute("Choice",ss.str()); } tag.AddAttribute("ChoiceName",this->GetChoiceName(this->GetChoice())); for(int i=0;iGetName(),5) } void RefObjOpt::XMLInput(istream &is,const XMLCrystTag &tag) { VFN_DEBUG_ENTRY("RefObjOpt::XMLInput():"<GetName(),5) for(unsigned int i=0;i>b; this->SetChoice(b); continue; } } VFN_DEBUG_EXIT("RefObjOpt::XMLInput():"<GetName(),5) } //////////////////////////////////////////////////////////////////////// // // I/O RefinableObj // Does nothing ! Should be purely virtual... // //////////////////////////////////////////////////////////////////////// void RefinableObj::XMLOutput(ostream &os,int indent)const { VFN_DEBUG_MESSAGE("RefinableObj::XMLOutput():"<GetName(),5) } void RefinableObj::XMLInput(istream &is,const XMLCrystTag &tag) { VFN_DEBUG_MESSAGE("RefinableObj::XMLInput():"<GetName(),5) } #if 0 void RefinableObj::XMLInputOld(istream &is,const IOCrystTag &tag) { VFN_DEBUG_MESSAGE("RefinableObj::XMLInput():"<GetName(),5) } #endif //////////////////////////////////////////////////////////////////////// // // OLD Functions & objects // //////////////////////////////////////////////////////////////////////// #if 0 void IOCrystExtractNameSpace(istream &is,string &str) { ios::fmtflags f=is.flags(); is.unsetf(ios::skipws);//skip whitespaces char tmp; do {is>>tmp;} while (tmp==' '); str=""; do {str+=tmp;is>>tmp;VFN_DEBUG_MESSAGE(str,1)} while ((tmp!=' ')&&(tmp!='>')); if(tmp=='>') is.putback(tmp); is.setf(f); } void IOCrystExtractNameLine(istream &is,string &str) { ios::fmtflags f=is.flags(); is.setf(ios::skipws);//skip leading whitespaces getline(is,str); is.setf(f); } void IOCrystExtractNameQuoted(istream &is,string &str) { char tmp; do {is>>tmp;} while ((tmp!='\'')&&(tmp!='\"')); str=""; is>>tmp; if((tmp=='\'')||(tmp=='\"')) return; ios::fmtflags f=is.flags(); is.unsetf(ios::skipws);//do not skip whitespaces do {str+=tmp;is>>tmp;VFN_DEBUG_MESSAGE(str,1)} while ((tmp!='\'')&&(tmp!='\"')); is.setf(f); } void IOCrystXMLOutputNameQuoted(ostream &os,const string &str) { os << '\"' << str << '\"'; } //////////////////////////////////////////////////////////////////////// // // IOCrystTag // //////////////////////////////////////////////////////////////////////// IOCrystTag::IOCrystTag(const string& type,const string& name, const unsigned long version): mTagType(type),mTagName(name),mTagVersion(version),mIsClosingTag(false) {} IOCrystTag::IOCrystTag(istream &is) { VFN_DEBUG_MESSAGE("IOCrystTag::IOCrystTag(istream &is)",2) char tmp; do { is>>tmp; if(true==is.eof()) { mTagVersion=0;//closing tag mTagName=""; mTagType=""; mIsClosingTag=true; return; } } while (tmp!='<'); IOCrystExtractNameSpace(is,mTagType); VFN_DEBUG_MESSAGE("IOCrystTag::IOCrystTag(istream &is):TagType:"<> mTagVersion; mIsClosingTag=false; } do {is>>tmp;} while (tmp!='>'); VFN_DEBUG_MESSAGE("IOCrystTag::IOCrystTag(istream &is):End",2) } IOCrystTag::~IOCrystTag(){} bool IOCrystTag::operator==(const IOCrystTag& rhs)const { if( (rhs.GetType()==this->GetType()) && (rhs.GetName()==this->GetName())) return true; return false; } void IOCrystTag::XMLInput(istream &is) { VFN_DEBUG_MESSAGE("IOCrystTag::XMLInput(istream &is)",2) char tmp; do {is>>tmp;} while ((tmp!='<') && (!is.eof()) ); if(is.eof()) return; IOCrystExtractNameSpace(is,mTagType); VFN_DEBUG_MESSAGE("IOCrystTag::XMLInput(istream &is):TagType:"<> mTagVersion; mIsClosingTag=false; } do {is>>tmp;} while (tmp!='>'); VFN_DEBUG_MESSAGE("IOCrystTag::XMLInput(istream &is):End",2) } const string &IOCrystTag::GetType() const{return mTagType;} const string &IOCrystTag::GetName() const{return mTagName;} unsigned long IOCrystTag::GetVersion()const{return mTagVersion;} bool IOCrystTag::IsClosingTag()const{return mIsClosingTag;} void IOCrystTag::Print() const { if(mIsClosingTag==true) cout <<"<"<"<"< #include #include using namespace std; #include "ObjCryst/ObjCryst/General.h" namespace ObjCryst { class XMLCrystTag; } #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxCryst.h" #endif namespace ObjCryst { /** Safely read a floating-point value from a stream. * * \param endchar: the character ending the input. On return, the stream will be placed * at this character (i.e. it will be the next to be read). Note that the input will * stop when encoutering a space character, even if the endchar has not been found. * \return: the value - NaN will be returned as NaN, but probably only if the value * was written on the same platform */ float InputFloat(istream &is, const char endchar=' '); /// Test if the value is a NaN bool ISNAN_OR_INF(REAL r); #ifdef __WX__CRYST__ /** \brief wxWindows representation of a XMLCrystTag (not implemented yet !) * * This will be used to choose objects to import from a save file. */ class WXXMLCrystTag: public WXCrystObj { public: WXXMLCrystTag(wxWindow *parent, XMLCrystTag*); virtual void CrystUpdate(); virtual void SetObjName(const string&); virtual string GetObjName()const; virtual bool Show(const bool); private: XMLCrystTag* mpTag; }; #endif /** \brief class to input or output a well-formatted xml beginning or ending tag. * */ class XMLCrystTag { public: XMLCrystTag(); XMLCrystTag(istream &is); XMLCrystTag(const string &tagName,const bool isEndTag=false, const bool isEmptyTag=false); ~XMLCrystTag(); const string& GetName()const; const string& GetClassName()const; unsigned int GetNbAttribute()const; void AddAttribute(const string &attName,const string &attValue); void GetAttribute(const int attNum,string &attName,string &attValue); const string& GetAttributeName(const int attNum)const; const string& GetAttributeValue(const int attNum)const; void SetIsEndTag(const bool isEndTag); bool IsEndTag()const; void SetIsEmptyTag(const bool isEmptyTag); bool IsEmptyTag()const; void Print()const; private: string mName; bool mIsEndTag; bool mIsEmptyTag; vector > mvAttribute; friend ostream& operator<< (ostream&, const XMLCrystTag&); friend istream& operator>> (istream&, XMLCrystTag&); #ifdef __WX__CRYST__ public: /// Create a WXCrystObj for this object. (not implemented yet) WXCrystObj* WXCreate(wxWindow*); WXCrystObj* WXGet(); void WXDelete(); void WXNotifyDelete(); protected: WXXMLCrystTag *mpWXXMLCrystTag; #endif }; /// Output an XMLCrystTag to a stream ostream& operator<< (ostream&, const XMLCrystTag&); /// Input an XMLCrystTag from a stream istream& operator>> (istream&, XMLCrystTag&); #if 0 //OLD void IOCrystExtractNameSpace(istream &is,string &str); void IOCrystExtractNameLine(istream &is,string &str); void IOCrystExtractNameQuoted(istream &is,string &str); void IOCrystXMLOutputNameQuoted(ostream &os,const string &str); #ifdef __WX__CRYST__ class IOCrystTag; class WXIOCrystTag: public WXCrystObj { public: WXIOCrystTag(wxWindow *parent, IOCrystTag*); virtual void CrystUpdate(); virtual void SetObjName(const string&); virtual string GetObjName()const; virtual bool Show(const bool); private: IOCrystTag* mpTag; }; #endif /// OLD /// \internal Tag used to delimitate objects (example: "") /// This includes the name of the corresponding ObjCryst class, as well /// as a version number for the description. class IOCrystTag { public: IOCrystTag(const string& type,const string& name, const unsigned long version=0); IOCrystTag(istream &is); virtual ~IOCrystTag(); void XMLInput(istream &is); bool operator==(const IOCrystTag&)const; const string &GetType()const; const string &GetName()const; unsigned long GetVersion()const; bool IsClosingTag()const; void Print()const; /// This is the same as GetType(), but allows using a registry const string &GetClassName()const; private: string mTagType; string mTagName; unsigned long mTagVersion; bool mIsClosingTag; #ifdef __WX__CRYST__ public: /// Create a WXCrystObj for this object. virtual WXCrystObj* WXCreate(wxWindow*); WXCrystObj* WXGet(); void WXDelete(); void WXNotifyDelete(); protected: WXIOCrystTag *mpWXIOCrystTag; #endif }; #endif }//namespace ObjCryst #endif //_REFOBJ_IO_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/LSQNumObj.cpp000066400000000000000000001150411417150057700241070ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/RefinableObj/LSQNumObj.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxLSQ.h" #endif #include "newmat/newmatap.h" //for SVD decomposition #include "newmat/newmatio.h" #ifdef use_namespace using namespace NEWMAT; #endif using namespace std; #include #define POSSIBLY_UNUSED(expr) (void)(expr) namespace ObjCryst { LSQNumObj::LSQNumObj(string objName) #ifdef __WX__CRYST__ :mpWXCrystObj(0) #endif { mDampingFactor=1.; mSaveReportOnEachCycle=false; mName=objName; mSaveFileName="LSQrefinement.save"; mR=0; mRw=0; mChiSq=0; mStopAfterCycle=false; } LSQNumObj::~LSQNumObj() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } void LSQNumObj::SetParIsFixed(const string& parName,const bool fix) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.SetParIsFixed(parName,fix); } void LSQNumObj::SetParIsFixed(const RefParType *type,const bool fix) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.SetParIsFixed(type,fix); } void LSQNumObj::SetParIsFixed(RefinablePar &par,const bool fix) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.GetPar(par.GetPointer()).SetIsFixed(fix); } void LSQNumObj::SetParIsFixed(RefinableObj &obj,const bool fix) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); for(unsigned int i=0;iSetParIsFixed(obj.GetPar(i),fix); } void LSQNumObj::UnFixAllPar() { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.UnFixAllPar(); } void LSQNumObj::SetParIsUsed(const string& parName,const bool use) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.SetParIsUsed(parName,use); } void LSQNumObj::SetParIsUsed(const RefParType *type,const bool use) { if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.SetParIsUsed(type,use); } void LSQNumObj::Refine (int nbCycle,bool useLevenbergMarquardt, const bool silent, const bool callBeginEndOptimization, const float minChi2var) { TAU_PROFILE("LSQNumObj::Refine()","void ()",TAU_USER); TAU_PROFILE_TIMER(timer1,"LSQNumObj::Refine() 1 - Init","", TAU_FIELD); TAU_PROFILE_TIMER(timer2,"LSQNumObj::Refine() 2 - LSQ Deriv","", TAU_FIELD); TAU_PROFILE_TIMER(timer3,"LSQNumObj::Refine() 3 - LSQ MB","", TAU_FIELD); TAU_PROFILE_TIMER(timer4,"LSQNumObj::Refine() 4 - LSQ Singular Values","", TAU_FIELD); TAU_PROFILE_TIMER(timer5,"LSQNumObj::Refine() 5 - LSQ Newmat, eigenvalues...","", TAU_FIELD); TAU_PROFILE_TIMER(timer6,"LSQNumObj::Refine() 6 - LSQ Apply","", TAU_FIELD); TAU_PROFILE_TIMER(timer7,"LSQNumObj::Refine() 7 - LSQ Finish","", TAU_FIELD); TAU_PROFILE_START(timer1); if(callBeginEndOptimization) this->BeginOptimization(); mObs=this->GetLSQObs(); mWeight=this->GetLSQWeight(); bool terminateOnDeltaChi2=false; if(nbCycle<0) { nbCycle=-nbCycle; terminateOnDeltaChi2=true; } if(!silent) cout << "LSQNumObj::Refine():Beginning "<PrepareRefParList(); mRefParList.PrepareForRefinement(); //if(!silent) mRefParList.Print(); if(mRefParList.GetNbPar()==0) throw ObjCrystException("LSQNumObj::Refine():no parameter to refine !"); //variables long nbVar=mRefParList.GetNbParNotFixed(); const long nbObs=mObs.numElements(); CrystVector_REAL calc,calc0,calc1,tmpV1,tmpV2; CrystMatrix_REAL M(nbVar,nbVar); CrystMatrix_REAL N(nbVar,nbVar); CrystVector_REAL B(nbVar); CrystMatrix_REAL designMatrix(nbVar,nbObs); CrystVector_REAL deltaVar(nbVar); long i,j,k; REAL R_ini,Rw_ini; POSSIBLY_UNUSED(R_ini); REAL *pTmp1,*pTmp2; REAL marquardt=1e-2; const REAL marquardtMult=4.; //initial Chi^2, needed for Levenberg-Marquardt this->CalcChiSquare(); //store old values mIndexValuesSetInitial=mRefParList.CreateParamSet("LSQ Refinement-Initial Values"); mIndexValuesSetLast=mRefParList.CreateParamSet("LSQ Refinement-Last Cycle Values"); TAU_PROFILE_STOP(timer1); //refine for(int cycle=1 ; cycle <=nbCycle;cycle++) { TAU_PROFILE_START(timer2); const REAL ChisSqPreviousCycle=mChiSq; mRefParList.SaveParamSet(mIndexValuesSetLast);// end of last cycle if(!silent) cout << "LSQNumObj::Refine():Cycle#"<< cycle <GetLSQCalc(); //R tmpV1 = mObs; tmpV1 -= calc0; tmpV1 *= tmpV1; tmpV2 = mObs; tmpV2 *= mObs; R_ini=sqrt(tmpV1.sum()/tmpV2.sum()); //Rw tmpV1 *= mWeight; tmpV2 *= mWeight; Rw_ini=sqrt(tmpV1.sum()/tmpV2.sum()); //derivatives //designMatrix=0.; pTmp2=designMatrix.data(); //cout <<"obs:"<(calc0,10,8); //cout <<"calc:"<(mObs,10,8); //cout <<"weight:"<(mWeight,10,8); #if 1 for(i=0;iGetLSQDeriv(mRefParList.GetParNotFixed(i)); pTmp1=tmpV1.data(); //cout <<"deriv#"<(tmpV1,10,8); for(j=0;jGetLSQ_FullDeriv(); for(i=0;i=(nbVar-2)) cout<<__FILE__<<":"<<__LINE__<<":"<<(mRefParList.GetParNotFixed(i)).GetName()<<"size="<GetLSQDeriv(mRefParList.GetParNotFixed(i)); cout <<"deriv#"<(tmpV1,10,8); } } */ if(!silent) cout << "LSQNumObj::Refine(): Automatically fixing parameter"; if(!silent) cout << " and re-start cycle.."; if(!silent) cout << endl; mRefParList.GetParNotFixed(i).SetIsFixed(true); mRefParList.PrepareForRefinement(); nbVar=mRefParList.GetNbParNotFixed(); if(nbVar<=1) { mRefParList.RestoreParamSet(mIndexValuesSetInitial); if(callBeginEndOptimization) this->EndOptimization(); if(!silent) mRefParList.Print(); throw ObjCrystException("LSQNumObj::Refine(): not enough (1) parameters after fixing one..."); } N.resize(nbVar,nbVar); deltaVar.resize(nbVar); //Just remove the ith line in the design matrix REAL *p1=designMatrix.data(); const REAL *p2=designMatrix.data(); p1 += i*nbObs; p2 += i*nbObs+nbObs; for(long j=i*nbObs+nbObs;j=i) && (j minAllowedValue) newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1); else { cout << "LSQNumObj::Refine():SVD: fixing singular value "<< i < minAllowedValue) newmatInvW(i+1,i+1)= 1./newmatW(i+1,i+1); else { if(!silent) cout << "LSQNumObj::Refine():fixing ill-cond EigenValue "<< i < max ) { max = fabs(newmatW(j+1)*newmatV(j+1,i+1)*newmatV(j+1,i+1)); maxIndex=j; } cout << FormatFloat(newmatW(i+1,i+1),36,2) << " " ; cout << FormatFloat(max,36,2); cout << FormatFloat(newmatW(maxIndex+1,maxIndex+1),36,2) << " " ; cout << FormatFloat(newmatV(i+1,maxIndex+1)*100,8,2) ; //cout << endl; if(newmatW(i+1,i+1) > (max*minRatio)) { newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1); cout << endl; } else { cout << "LSQNumObj::Refine():fixing ill-cond EigenValue "<< i < minAllowedValue) newmatInvW(i+1,i+1) = 1./newmatW(i+1,i+1); else { cout << "LSQNumObj::Refine():SVD: fixing ill-cond value "<< i <GetLSQCalc(); //Chi^2 { REAL oldChiSq=mChiSq; tmpV1 = mObs; tmpV1 -= calc; tmpV1 *= tmpV1; tmpV1 *= mWeight; mChiSq=tmpV1.sum(); if(true==useLevenbergMarquardt) { if(mChiSq > (oldChiSq*1.0001)) { mRefParList.RestoreParamSet(mIndexValuesSetLast); increaseMarquardt=true; if(!silent) { cout << "LSQNumObj::Refine(Chi^2="<"<Increasing Levenberg-Marquardt factor :" << FormatFloat(marquardt*marquardtMult,18,14) <1e4) { // :TODO: Revert to previous parameters. Or initial ? mRefParList.RestoreParamSet(mIndexValuesSetLast); if(callBeginEndOptimization) this->EndOptimization(); //if(!silent) mRefParList.Print(); return; //throw ObjCrystException("LSQNumObj::Refine():Levenberg-Marquardt diverging !"); } TAU_PROFILE_STOP(timer6); goto LSQNumObj_Refine_RestartMarquardt; } else { if(!silent && (marquardt>1e-2)) { cout << "LSQNumObj::Refine(Chi^2="<"<Decreasing Levenberg-Marquardt factor :" << FormatFloat(marquardt/marquardtMult,18,14) <"<"<WriteReportToFile(); if(!silent) this->PrintRefResults(); TAU_PROFILE_STOP(timer7); if( terminateOnDeltaChi2 && (minChi2var>( (ChisSqPreviousCycle-mChiSq)/abs(ChisSqPreviousCycle+1e-6) ) ) ) break; } if(callBeginEndOptimization) this->EndOptimization(); } bool LSQNumObj::SafeRefine(std::list vnewpar, std::list vnewpartype, REAL maxChi2factor, int nbCycle, bool useLevenbergMarquardt, const bool silent, const bool callBeginEndOptimization, const float minChi2var) { if(callBeginEndOptimization) this->BeginOptimization(); // :TODO: update mObs and mWeight in a centralized way... Not in BeginOptimization() (not always called) mObs=this->GetLSQObs(); mWeight=this->GetLSQWeight(); //Prepare for refinement (get non-fixed parameters) if(mRefParList.GetNbPar()==0) this->PrepareRefParList(); mRefParList.PrepareForRefinement(); if(mRefParList.GetNbPar()==0) throw ObjCrystException("LSQNumObj::SafeRefine():no parameter to refine !"); this->CalcChiSquare(); const REAL chi2_0 = mChiSq; for(std::list::iterator pos=vnewpar.begin(); pos!=vnewpar.end(); pos++) { this->SetParIsFixed(**pos, false); } for(std::list::iterator pos=vnewpartype.begin(); pos!=vnewpartype.end(); pos++) { this->SetParIsFixed(*pos, false); } bool diverged = false; try { this->Refine(nbCycle, useLevenbergMarquardt, silent, false, minChi2var); } catch(const ObjCrystException &except) { diverged = true; if(!silent) cout << "Refinement did not converge !"; } const REAL deltachi2 = (mChiSq-chi2_0)/(chi2_0+1e-6); if(callBeginEndOptimization) this->EndOptimization(); if(deltachi2>maxChi2factor) { if(!silent) cout << "Refinement did not converge ! Chi2 increase("<"<::iterator pos=vnewpar.begin(); pos!=vnewpar.end(); pos++) { this->SetParIsFixed(**pos, true); } for(std::list::iterator pos=vnewpartype.begin(); pos!=vnewpartype.end(); pos++) { this->SetParIsFixed(*pos, true); } this->CalcRfactor(); this->CalcRwFactor(); this->CalcChiSquare(); if(!silent) cout <<"=> REVERTING to initial parameters values and fixing new parameters"<GetLSQCalc(); tmpV1 = this->GetLSQObs(); tmpV1 -= calc; tmpV1 *= tmpV1; tmpV2 = this->GetLSQObs(); tmpV2 *= tmpV2; mR=sqrt(tmpV1.sum()/tmpV2.sum()); } REAL LSQNumObj::Rfactor()const{return mR;}; void LSQNumObj::CalcRwFactor()const { CrystVector_REAL calc, tmpV1, tmpV2; calc=this->GetLSQCalc(); tmpV1 = this->GetLSQObs(); tmpV1 -= calc; tmpV1 *= tmpV1; tmpV2 = this->GetLSQObs(); tmpV2 *= tmpV2; tmpV1 *= mWeight; tmpV2 *= mWeight; mRw=sqrt(tmpV1.sum()/tmpV2.sum()); } REAL LSQNumObj::RwFactor()const{return mRw;}; void LSQNumObj::CalcChiSquare()const { CrystVector_REAL calc, tmpV1; calc=this->GetLSQCalc(); tmpV1 = mObs; tmpV1 -= calc; tmpV1 *= tmpV1; tmpV1 *= mWeight; mChiSq=tmpV1.sum(); } REAL LSQNumObj::ChiSquare()const{return mChiSq;}; void RecursiveMapFunc(RefinableObj &obj,map &themap, const unsigned int value) { themap[&obj]=value; ObjRegistry *pObjReg=&(obj.GetSubObjRegistry()); for(int i=0;iGetNb();i++) RecursiveMapFunc(pObjReg->GetObj(i),themap,value); return; } void LSQNumObj::SetRefinedObj(RefinableObj &obj, const unsigned int LSQFuncIndex, const bool init, const bool recursive) { if(init) { mvRefinedObjMap.clear(); } if(recursive) RecursiveMapFunc(obj,mvRefinedObjMap,LSQFuncIndex); else mvRefinedObjMap[&obj]=LSQFuncIndex; } //ObjRegistry &LSQNumObj::GetRefinedObjList(){return mRecursiveRefinedObjList;} const map& LSQNumObj::GetRefinedObjMap() const { return mvRefinedObjMap; } map& LSQNumObj::GetRefinedObjMap() { return mvRefinedObjMap; } RefinableObj& LSQNumObj::GetCompiledRefinedObj(){return mRefParList;} const RefinableObj& LSQNumObj::GetCompiledRefinedObj()const{return mRefParList;} void LSQNumObj::SetUseSaveFileOnEachCycle(bool yesOrNo) { mSaveReportOnEachCycle=yesOrNo; } void LSQNumObj::SetSaveFile(string fileName) { mSaveFileName=fileName; } void LSQNumObj::PrintRefResults() const { //:TODO: //this->PrepareRefParList(); activate this when PrepareRefParList() will be more savy cout << "Results after last refinement :(" ; cout << mRefParList.GetNbParNotFixed()<< " non-fixed parameters)"<GetLSQWeight().numElements()<,REAL > & LSQNumObj::GetVarianceCovarianceMap()const { return mvVarCovar;} void LSQNumObj::PrepareRefParList(const bool copy_param) { mRefParList.ResetParList(); for(map::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { VFN_DEBUG_MESSAGE("LSQNumObj::PrepareRefParList():"<first->GetName(),4); //mRecursiveRefinedObjList.GetObj(i).Print(); mRefParList.AddPar(*(pos->first),copy_param); } //mRefParList.Print(); if(copy_param) mRefParList.SetDeleteRefParInDestructor(true); else mRefParList.SetDeleteRefParInDestructor(false); } const CrystVector_REAL& LSQNumObj::GetLSQCalc() const { const CrystVector_REAL *pV; long nb=0; for(map::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { if(pos->first->GetNbLSQFunction()==0) continue; pV=&(pos->first->GetLSQCalc(pos->second)); const long n2 = pV->numElements(); if((nb+n2)>mLSQCalc.numElements()) mLSQCalc.resizeAndPreserve(nb+pV->numElements()); const REAL *p1=pV->data(); REAL *p2=mLSQCalc.data()+nb; for(long j = 0; j < n2; ++j) *p2++ = *p1++; nb+=n2; } if(mLSQCalc.numElements()>nb) mLSQCalc.resizeAndPreserve(nb); return mLSQCalc; } const CrystVector_REAL& LSQNumObj::GetLSQObs() const { const CrystVector_REAL *pV; long nb=0; for(map::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { if(pos->first->GetNbLSQFunction()==0) continue; pV=&(pos->first->GetLSQObs(pos->second)); const long n2 = pV->numElements(); mvRefinedObjLSQSize[pos->first]=n2; if((nb+n2)>mLSQObs.numElements()) mLSQObs.resizeAndPreserve(nb+pV->numElements()); const REAL *p1=pV->data(); REAL *p2=mLSQObs.data()+nb; for(long j = 0; j < n2; ++j) *p2++ = *p1++; nb+=n2; } if(mLSQObs.numElements()>nb) mLSQObs.resizeAndPreserve(nb); return mLSQObs; } const CrystVector_REAL& LSQNumObj::GetLSQWeight() const { const CrystVector_REAL *pV; long nb=0; for(map::const_iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { if(pos->first->GetNbLSQFunction()==0) continue; pV=&(pos->first->GetLSQWeight(pos->second)); const long n2 = pV->numElements(); if((nb+n2)>mLSQWeight.numElements()) mLSQWeight.resizeAndPreserve(nb+pV->numElements()); const REAL *p1=pV->data(); REAL *p2=mLSQWeight.data()+nb; for(long j = 0; j < n2; ++j) *p2++ = *p1++; nb+=n2; } if(mLSQWeight.numElements()>nb) mLSQWeight.resizeAndPreserve(nb); return mLSQWeight; } const CrystVector_REAL& LSQNumObj::GetLSQDeriv(RefinablePar&par) { const CrystVector_REAL *pV; long nb=0; for(map::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { if(pos->first->GetNbLSQFunction()==0) continue; pV=&(pos->first->GetLSQDeriv(pos->second,par)); const long n2 = pV->numElements(); if((nb+n2)>mLSQDeriv.numElements()) mLSQDeriv.resizeAndPreserve(nb+pV->numElements()); const REAL *p1=pV->data(); REAL *p2=mLSQDeriv.data()+nb; for(long j = 0; j < n2; ++j) *p2++ = *p1++; nb+=n2; } if(mLSQDeriv.numElements()>nb) mLSQDeriv.resizeAndPreserve(nb); return mLSQDeriv; } const std::map& LSQNumObj::GetLSQ_FullDeriv() { long nbVar=mRefParList.GetNbParNotFixed(); std::set vPar; for(unsigned int i=0;i::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) { if(pos->first->GetNbLSQFunction()==0) continue; const unsigned long n2=mvRefinedObjLSQSize[pos->first]; if(n2==0) continue;//this object does not have an LSQ function const std::map *pvV=&(pos->first->GetLSQ_FullDeriv(pos->second,vPar)); for(std::map::const_iterator d=pvV->begin();d!=pvV->end();d++) { if(mLSQ_FullDeriv[d->first].size()==0) mLSQ_FullDeriv[d->first].resize(mLSQObs.size()); REAL *p2=mLSQ_FullDeriv[d->first].data()+nb; if(d->second.size()==0) { //derivative can be null and then the vector missing // But we must still fill in zeros cout<<__FILE__<<":"<<__LINE__<<":"<first->GetClassName()<<":"<first->GetName()<<":"<first->GetName()<<" (all deriv=0)"<second.data(); for(unsigned long j=0;j::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) pos->first->BeginOptimization(allowApproximations, enableRestraints); } void LSQNumObj::EndOptimization() { for(map::iterator pos=mvRefinedObjMap.begin();pos!=mvRefinedObjMap.end();++pos) pos->first->EndOptimization(); } #ifdef __WX__CRYST__ WXCrystObjBasic* LSQNumObj::WXCreate(wxWindow* parent) { this->WXDelete(); mpWXCrystObj=new WXLSQ(parent,this); return mpWXCrystObj; } WXCrystObjBasic* LSQNumObj::WXGet() { return mpWXCrystObj; } void LSQNumObj::WXDelete() { if(0!=mpWXCrystObj) { VFN_DEBUG_MESSAGE("LSQNumObj::WXDelete()",5) delete mpWXCrystObj; } mpWXCrystObj=0; } void LSQNumObj::WXNotifyDelete() { VFN_DEBUG_MESSAGE("LSQNumObj::WXNotifyDelete():"< #include #include namespace ObjCryst { /** \brief (Quick & dirty) Least-Squares Refinement Object with Numerical derivatives * * This is still highly experimental ! */ class LSQNumObj { public: LSQNumObj(std::string objName="Unnamed LSQ object"); ~LSQNumObj(); /// Fix one parameter. /// /// LSQNumObj::PrepareRefParList() must be called first! void SetParIsFixed(const std::string& parName,const bool fix); /// Fix one family of parameters /// /// LSQNumObj::PrepareRefParList() must be called first! void SetParIsFixed(const RefParType *type,const bool fix); /** Fix one parameter * * Note that this will fix the copied parameter, not the one * in the original object. The supplied RefinablePar * may be either the copied one or the original. * * LSQNumObj::PrepareRefParList() must be called first! **/ void SetParIsFixed(RefinablePar &par,const bool fix); /** Fix all parameters within an object * * Note that this will fix the copied parameters, not the one * in the original objects. * * LSQNumObj::PrepareRefParList() must be called first! **/ void SetParIsFixed(RefinableObj &obj,const bool fix); /// UnFix All parameters /// /// LSQNumObj::PrepareRefParList() must be called first! void UnFixAllPar(); /// Set a parameter to be used /// /// LSQNumObj::PrepareRefParList() must be called first! void SetParIsUsed(const std::string& parName,const bool use); /// Set a family of parameters to be used /// /// LSQNumObj::PrepareRefParList() must be called first! void SetParIsUsed(const RefParType *type,const bool use); /** Do the refinement * * \param nbCycle: number of LSQ cycles - if negative, the algorithm will continue * until it reaches (-nbcycle) or until the relative variation in Chi2 is less * than minChi2var * \param useLevenbergMarquardt: enable Levenberg-Marquardt algorithm * to ensure that a decrease of Chi^2 will be obtained (actually a 1% * increase is allowed) * \param callBeginEndOptimization: if true, will call RefinableObj::BeginOptimization(true,...) * and RefinableObj::EndOptimization(). You may not want this if the LSQ is done during another * (e.g. monte-carlo) optimization - but then the calling function \b must ensure * that approximations are disabled (using RefinableObj::SetApproximationFlag) * for objects where that would render derivative calculations imprecise. * \param minChi2var: used for termination of the refinement if the relative variation * of Chi2 between two successive cyles is less than minChi2var */ void Refine (int nbCycle=1,bool useLevenbergMarquardt=false, const bool silent=false, const bool callBeginEndOptimization=true, const float minChi2var=0.01); /** Run a refinement in a 'safe' way: if the Chi2 value increases by more that a given factor * the parameters are reverted to their initial values. Moreover, the listed 'new' parameters * or parameter types are then fixed. * \param vnewpar: list of parameters added for this optimization, which will be unfixed at the * beginning, and will be fixed at the end if Chi2 increases. This can be empty. * \param vnewpartype: list of parameter types, which will be unfixed at the * beginning, and will be fixed at the end if Chi2 increases. This can be empty. * \param maxChi2factor: if Chi2_end> maxChi2factor * Chi2_begin, parameters are reverted to their * initial value, and new parameters are fixed. * All the other parameters are the same as in LSQNumObj::Refine. * \return: true if the minimization was succesful, false otherwise. */ bool SafeRefine(std::list vnewpar, std::list vnewpartype, REAL maxChi2factor=1.01, int nbCycle=1, bool useLevenbergMarquardt=false, const bool silent=false, const bool callBeginEndOptimization=true, const float minChi2var=0.01); CrystVector_REAL Sigma()const; CrystMatrix_REAL CorrelMatrix()const; void CalcRfactor()const; REAL Rfactor()const; void CalcRwFactor()const; REAL RwFactor()const; void CalcChiSquare() const; REAL ChiSquare()const; //uses the weight if specified /** Choose the object to refine. The minimization will be done * against its LSQ function and its parameters, as well as the LSQ functions * and parameters of its sub-objects (if recursive==true) * * \param LSQFuncIndex: one object can have a choice of several LSQ * functions to minimize- this allows to choose which one to minimize. * * \param init: if true, the list of refined objects is first cleared. otherwise * the new object (and its sub-objects) is just added to the list. * * \param recursive: if false, only the supplied object is added, and not its sub-objects */ void SetRefinedObj(RefinableObj &obj, const unsigned int LSQFuncIndex=0, const bool init=true, const bool recursive=false); // Access to the full list of refined objects. The list is initially built // recursively from one object. This function allows to modify the list // of sub-objects before refinement (such as for removing certain types // of objects). //ObjRegistry &GetRefinedObjList(); /** Get the map of refined objects - this is a recursive list of all the objects * that are taken into account for the refinement. The key is a pointer to the * object and the value is the LSQ function index for that object. */ const std::map& GetRefinedObjMap() const; /** Get the map of refined objects - this is a recursive list of all the objects * that are taken into account for the refinement. The key is a pointer to the * object and the value is the LSQ function index for that object. */ std::map& GetRefinedObjMap(); /** Access to the RefinableObj which is the compilation of all parameters * from the object supplied for optimization and its sub-objects. * * Since this compilation is only updated from the suplied refinableobj and * its sub-objects when SetRefinedObj() and PrepareRefParList() are called, * it is possible to alter the fixed/limited status of parameters * here without affecting the parameters in the refined objects. */ RefinableObj& GetCompiledRefinedObj(); /** Access to the RefinableObj which is the compilation of all parameters * from the object supplied for optimization and its sub-objects. * * Since this compilation is only updated from the suplied refinableobj and * its sub-objects when SetRefinedObj() and PrepareRefParList() are called, * it is possible to alter the fixed/limited status of parameters * here without affecting the parameters in the refined objects. */ const RefinableObj& GetCompiledRefinedObj()const; void SetUseSaveFileOnEachCycle(bool yesOrNo=true); void SetSaveFile(std::string fileName="refine.save"); void PrintRefResults()const; void SetDampingFactor(const REAL newDampFact); void PurgeSaveFile(); void WriteReportToFile()const; void OptimizeDerivativeSteps(); const std::map,REAL > &GetVarianceCovarianceMap()const; /** Prepare the full parameter list for the refinement * \param copy_param: if false (the default), then the lsq algorithm will work directly * on the parameters of the refined object and sub-object. So that any modification * to the fixed/used/limited status applies permanently to the parameters. * if true, then the parameters are copied and therefore only the value of the * parameter is changed (and the clocks are ticked). * * \note: if copy_param==true, then any modification to the parameters (fixed, limited, used * status) only affects the copy and not the original. Also, calling again PrepareRefParList * cancels any such modification. * * \note This will be called automatically before starting the refinement only if * the parameter list is empty. Otherwise it should be called before refinement. */ void PrepareRefParList(const bool copy_param=false); /// Get the LSQ calc vector (using either only the top or the hierarchy of object) const CrystVector_REAL& GetLSQCalc() const; /// Get the LSQ obs vector (using either only the top or the hierarchy of object) const CrystVector_REAL& GetLSQObs() const; /// Get the LSQ weight vector (using either only the top or the hierarchy of object) const CrystVector_REAL& GetLSQWeight() const; /// Get the LSQ deriv vector (using either only the top or the hierarchy of object) const CrystVector_REAL& GetLSQDeriv(RefinablePar&par); const std::map& GetLSQ_FullDeriv(); /** Tell all refined object that the refinement is beginning */ void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); /** Tell all refined object that the refinement is finished */ void EndOptimization(); protected: private: // Refined object /// The recursive list of all refined sub-objects ObjRegistry mRecursiveRefinedObjList; /** The refinable par list used during refinement. It is only a compilation * of the parameters in RefinableObj and its sub-objects * * This list is only updated from the suplied refinableobj and * its sub-objects when SetRefinedObj() and PrepareRefParList() are called, * so it is possible to alter the fixed/limited status of parameters * here without affecting the parameters in the refined objects. */ mutable RefinableObj mRefParList; /// Damping factor for the refinement (unused yet...) REAL mDampingFactor; ///Save result to file after each cycle ? bool mSaveReportOnEachCycle; /// Name of the refined object std::string mName; /// File name where refinement info is saved std::string mSaveFileName; mutable REAL mR,mRw,mChiSq; /// Correlation matrix between all refined parameters. CrystMatrix_REAL mCorrelMatrix; ///Variance-Covariance matrix, as a std::map std::map,REAL > mvVarCovar; /// Observed values. CrystVector_REAL mObs; /// Weight corresponding to all observed values. CrystVector_REAL mWeight; /// Index of the set of saved values for all refinable parameters, before refinement /// and before the last cycle. int mIndexValuesSetInitial, mIndexValuesSetLast; /// If true, then stop at the end of the cycle. Used in multi-threading environment bool mStopAfterCycle; // The optimized object //RefinableObj *mpRefinedObj; // The index of the LSQ function in the refined object (if there are several...) //unsigned int mLSQFuncIndex; /** Map of the recursive list of the objects to be refined. The key is the pointer * to the object and the value the LSQ function index * * Individual LSQ functions can be changed using GetRefinedObjMap(). */ std::map mvRefinedObjMap; /// Size of each object LSQ data. This is initialized in LSQNumObj::GetLSQObs() mutable std::map mvRefinedObjLSQSize; /// If true, then parameters to be refined will be copied instead of referenced. /// Therefore only their values and the parameter's clocks are affected when /// working on the copy. bool mCopyRefPar; /// Temporary arrays for LSQ functions evaluation - used when /// using recursive LSQ function mutable CrystVector_REAL mLSQObs,mLSQCalc,mLSQWeight,mLSQDeriv; mutable std::map mLSQ_FullDeriv; #ifdef __WX__CRYST__ public: virtual WXCrystObjBasic* WXCreate(wxWindow* parent); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); protected: WXCrystObjBasic *mpWXCrystObj; #endif }; }//namespace #endif //_LSQOBJNUM_H libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/RefinableObj.cpp000066400000000000000000002035741417150057700246700ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * source file for the RefinablePar and RefinableObj classes * */ #include #include #include "ObjCryst/RefinableObj/RefinableObj.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" #include "ObjCryst/Quirks/VFNDebug.h" #ifdef __WX__CRYST__ #include "ObjCryst/wxCryst/wxRefinableObj.h" #undef GetClassName // Conflict from wxMSW headers ? (cygwin) #endif #include #define POSSIBLY_UNUSED(expr) (void)(expr) namespace ObjCryst { //###################################################################### // // RefParType // //###################################################################### RefParType::RefParType(const string &name): mpParent(0),mName(name),mId(0) { this->InitId(); } RefParType::RefParType(const RefParType *parent,const string &name): mpParent(parent),mName(name),mId(0) { this->InitId(); } RefParType::~RefParType(){}; bool RefParType::IsDescendantFromOrSameAs(const RefParType *type) const { VFN_DEBUG_MESSAGE("RefParType::IsDescendantFromOrSameAs(RefParType*): "<mId==mId) return true; if(0==mpParent) return false; return mpParent->IsDescendantFromOrSameAs(type); } bool RefParType::operator==(const RefParType *type) const { if(this==type) return true; return false; } const string& RefParType::GetName() const{ return mName;} void RefParType::InitId() { static unsigned long nbRefParType=0; mId=nbRefParType++; } const RefParType *gpRefParTypeObjCryst=0; long NiftyStaticGlobalObjectsInitializer_RefinableObj::mCount=0; //###################################################################### // // // //###################################################################### unsigned long RefinableObjClock::msTick0=0; unsigned long RefinableObjClock::msTick1=0; RefinableObjClock::RefinableObjClock() { //this->Click(); mTick0=0; mTick1=0; } RefinableObjClock::~RefinableObjClock() { // first copy & clear sets to avoid possible loops in RemoveChild() set vChild=mvChild; set vParent=mvParent; mvChild.clear(); mvParent.clear(); for(std::set::iterator pos=vChild.begin(); pos!=vChild.end();++pos) (*pos)->RemoveParent(*this); for(std::set::iterator pos=vParent.begin(); pos!=vParent.end();++pos) (*pos)->RemoveChild(*this); } bool RefinableObjClock::operator< (const RefinableObjClock &rhs)const { if(mTick1 (const RefinableObjClock &rhs)const { if(mTick1>rhs.mTick1) return true; if(mTick1==rhs.mTick1) if(mTick0>rhs.mTick0) return true; return false; } bool RefinableObjClock::operator>=(const RefinableObjClock &rhs)const { if(mTick1>rhs.mTick1) return true; if(mTick1==rhs.mTick1) if(mTick0>=rhs.mTick0) return true; return false; } void RefinableObjClock::Click() { //return; if(++msTick0==0) ++msTick1;//Update ObjCryst++ static event counter mTick0=msTick0; mTick1=msTick1; for(std::set::iterator pos=mvParent.begin(); pos!=mvParent.end();++pos) (*pos)->Click(); VFN_DEBUG_MESSAGE("RefinableObjClock::Click():"<Print(); } void RefinableObjClock::Reset() { mTick0=0; mTick1=0; } void RefinableObjClock::Print()const { cout <<"Clock():"<Click();} void RefinableObjClock::RemoveChild(const RefinableObjClock &clock) { const unsigned int i = mvChild.erase(&clock); POSSIBLY_UNUSED(i); VFN_DEBUG_MESSAGE("RefinableObjClock::RemoveChild():"<Click(); } void RefinableObjClock::AddParent(RefinableObjClock &clock)const { // First check for loop if(&clock==this) throw ObjCrystException("RefinableObjClock::AddParent(..) child == Parent !!"); if(clock.HasParent(*this)==true) throw ObjCrystException("RefinableObjClock::AddParent(..) Loop in clock tree !!"); mvParent.insert(&clock); } void RefinableObjClock::RemoveParent(RefinableObjClock &clock)const { // avoid warnings about unused i when not debugging. const unsigned int i = mvParent.erase(&clock); POSSIBLY_UNUSED(i); VFN_DEBUG_MESSAGE("RefinableObjClock::RemoveParent():"<::iterator pos=mvParent.begin(); pos!=mvParent.end();++pos) if( (*this) > (**pos) ) **pos = *this; } bool RefinableObjClock::HasParent(const RefinableObjClock &clock) const { for(std::set::iterator pos=mvParent.begin(); pos!=mvParent.end();++pos) { if((*pos)==&clock) return true; if((*pos)->HasParent(clock)) return true; } return false; } //###################################################################### // Restraint //###################################################################### Restraint::Restraint(): mpRefParType(gpRefParTypeObjCryst) {} Restraint::Restraint(const RefParType *type): mpRefParType(type) {} Restraint::~Restraint() {} const RefParType* Restraint::GetType()const{return mpRefParType;} void Restraint::SetType(const RefParType *type){mpRefParType=type;} REAL Restraint::GetLogLikelihood()const{return 0.;} //###################################################################### // RefinablePar //###################################################################### RefinablePar::RefinablePar(): Restraint(), mName(""),mpValue(0),mMin(0),mMax(0), mHasLimits(false),mIsFixed(true),mIsUsed(true),mIsPeriodic(false), mPeriod(0.),mGlobalOptimStep(1.),mDerivStep(1e-5),mRefParDerivStepModel(REFPAR_DERIV_STEP_ABSOLUTE), mSigma(0.),mHumanScale(1.),mHasAssignedClock(false),mpClock(0) #ifdef __WX__CRYST__ ,mpWXFieldRefPar(0) #endif {} RefinablePar::RefinablePar( const string &name, REAL *refPar, const REAL min, const REAL max, const RefParType *type, RefParDerivStepModel derivMode, const bool hasLimits, const bool isFixed, const bool isUsed, const bool isPeriodic, const REAL humanScale, REAL period): Restraint(type), mName(name),mpValue(refPar),mMin(min),mMax(max), mHasLimits(hasLimits),mIsFixed(isFixed),mIsUsed(isUsed),mIsPeriodic(isPeriodic),mPeriod(period), mGlobalOptimStep((max-min)/100.),mDerivStep(1e-5),mRefParDerivStepModel(derivMode), mSigma(0.),mHumanScale(humanScale), #if 0 mUseEquation(false),mEquationNbRefPar(0),mEquationCoeff(0), #endif mHasAssignedClock(false),mpClock(0) #ifdef __WX__CRYST__ ,mpWXFieldRefPar(0) #endif {} RefinablePar::~RefinablePar() { #ifdef __WX__CRYST__ this->WXDelete(); #endif } void RefinablePar::Init(const string &name, REAL *refPar, const REAL min, const REAL max, const RefParType *type, RefParDerivStepModel derivMode, const bool hasLimits, const bool isFixed, const bool isUsed, const bool isPeriodic, const REAL humanScale, REAL period) { mName=name; mpValue=refPar; mMin=min; mMax=max; Restraint::SetType(type); mHasLimits=hasLimits; mIsFixed=isFixed; mIsUsed=isUsed; mIsPeriodic=isPeriodic; mPeriod=period; mGlobalOptimStep=(max-min)/100.; mDerivStep=1e-5; mRefParDerivStepModel=derivMode; mSigma=0.; mHumanScale=humanScale; #if 0 mUseEquation=false; mEquationNbRefPar=0; mEquationCoeff=0; #endif mHasAssignedClock=false; mpClock=0; } RefinablePar::RefinablePar(const RefinablePar &old): Restraint(old) { mpValue=old.mpValue; #ifdef __WX__CRYST__ mpWXFieldRefPar=0; #endif this->CopyAttributes(old); mHasAssignedClock=old.mHasAssignedClock; mpClock=old.mpClock; } void RefinablePar::CopyAttributes(const RefinablePar&old) { mName=old.mName; mMin=old.GetMin(); mMax=old.GetMax(); mHasLimits=old.mHasLimits; mIsFixed=old.mIsFixed; mIsUsed=old.mIsUsed; mIsPeriodic=old.mIsPeriodic; mPeriod=old.mPeriod; mGlobalOptimStep=old.mGlobalOptimStep; mDerivStep=old.mDerivStep; mRefParDerivStepModel=old.mRefParDerivStepModel; mSigma=old.mSigma; mHumanScale=old.mHumanScale; #if 0 mUseEquation=old.mUseEquation; mEquationNbRefPar=old.mEquationNbRefPar; mEquationCoeff=old.mEquationCoeff; #endif } REAL RefinablePar::GetValue()const { #if 0 if(true==mUseEquation) { VFN_DEBUG_MESSAGE("RefinablePar::Value():Evaluating Equation",0) REAL tmp=mEquationCoeff(0); for(int i=0;iGetValue(); *mpValue = tmp; } #endif return *mpValue; } const REAL* RefinablePar::GetPointer()const { return mpValue; } void RefinablePar::SetValue(const REAL value) { if(*mpValue == value) return; this->Click(); VFN_DEBUG_MESSAGE("RefinablePar::SetValue()",2) #if 0 if(true==mUseEquation) { cout << "RefinablePar::SetValue(): this parameter is defined by an equation !!" <IsLimited() ==true) { if(true==this->IsPeriodic()) { if(*mpValue > this->GetMax()) *mpValue -= this->GetMax()-this->GetMin(); if(*mpValue < this->GetMin()) *mpValue += this->GetMax()-this->GetMin(); } else { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } } */ if(this->IsLimited() ==true) { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } else if(true==this->IsPeriodic()) { if(*mpValue > mPeriod) *mpValue -= mPeriod; if(*mpValue < 0) *mpValue += mPeriod; } } const REAL& RefinablePar::GetHumanValue() const { static REAL val; val = *mpValue * mHumanScale; return val; } void RefinablePar::SetHumanValue(const REAL &value) { if(*mpValue == (value/mHumanScale)) return; this->Click(); VFN_DEBUG_MESSAGE("RefinablePar::SetHumanValue()",2) #if 0 if(true==mUseEquation) { cout << "RefinablePar::SetValue(): this parameter is defined by an equation !!" <IsLimited() ==true) { if(true==this->IsPeriodic()) { if(*mpValue > this->GetMax()) *mpValue -= this->GetMax()-this->GetMin(); if(*mpValue < this->GetMin()) *mpValue += this->GetMax()-this->GetMin(); } else { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } } */ if(this->IsLimited() ==true) { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } else if(true==this->IsPeriodic()) { if(*mpValue > mPeriod) *mpValue -= mPeriod; if(*mpValue < 0) *mpValue += mPeriod; } } void RefinablePar::Mutate(const REAL mutateValue) { if(0==mutateValue) return; VFN_DEBUG_MESSAGE("RefinablePar::Mutate():"<GetName(),1) if(true==mIsFixed) return; this->Click(); #if 0 if(true==mUseEquation) { cout << "RefinablePar::Mutate(): this parameter is defined by an equation !!" <IsLimited() ==true) { if(true==this->IsPeriodic()) { if(*mpValue > this->GetMax()) *mpValue -= this->GetMax()-this->GetMin(); if(*mpValue < this->GetMin()) *mpValue += this->GetMax()-this->GetMin(); } else { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } } */ if(this->IsLimited() ==true) { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } else if(true==this->IsPeriodic()) { //if(*mpValue > mPeriod) *mpValue -= mPeriod; *mpValue=fmod((REAL)*mpValue,(REAL)mPeriod); if(*mpValue < 0) *mpValue += mPeriod; } VFN_DEBUG_MESSAGE("RefinablePar::Mutate():End",0) } void RefinablePar::MutateTo(const REAL mutateValue) { VFN_DEBUG_MESSAGE("RefinablePar::MutateTo()",2) if(true==mIsFixed) return; if(*mpValue == mutateValue)return; this->Click(); #if 0 if(true==mUseEquation) { cout << "RefinablePar::Mutate(): this parameter is defined by an equation !!" <IsLimited() ==true) { if(true==this->IsPeriodic()) { if(*mpValue > this->GetMax()) *mpValue -= this->GetMax()-this->GetMin(); if(*mpValue < this->GetMin()) *mpValue += this->GetMax()-this->GetMin(); } else { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } } */ if(this->IsLimited() ==true) { if(*mpValue > this->GetMax()) *mpValue=this->GetMax(); if(*mpValue < this->GetMin()) *mpValue=this->GetMin(); } else if(true==this->IsPeriodic()) { if(*mpValue > mPeriod) *mpValue -= mPeriod; if(*mpValue < 0) *mpValue += mPeriod; } } REAL RefinablePar::GetSigma()const {return mSigma;} REAL RefinablePar::GetHumanSigma()const {return mSigma*mHumanScale;} void RefinablePar::SetSigma(const REAL sigma) {mSigma=sigma; this->Click();} void RefinablePar::Print() const { cout << this->GetName() << " : " << this->GetHumanValue() << " Fixed:"<< mIsFixed <<" Periodic:"<GetHumanMin() << " Max:" << this->GetHumanMax() << " Step:" <GetName(),1) mIsFixed=b; } bool RefinablePar::IsLimited()const {return mHasLimits;} void RefinablePar::SetIsLimited(const bool b) {mHasLimits=b;this->Click();} bool RefinablePar::IsUsed()const {return mIsUsed;} void RefinablePar::SetIsUsed(const bool b) {mIsUsed=b;this->Click();} bool RefinablePar::IsPeriodic()const {return mIsPeriodic;} void RefinablePar::SetIsPeriodic(const bool b,REAL period) {mIsPeriodic=b;mPeriod=period;this->Click();} REAL RefinablePar::GetMin()const {return mMin;} void RefinablePar::SetMin(const REAL min) { mMin=min;this->Click();} REAL RefinablePar::GetHumanMin()const {return mMin * mHumanScale;} void RefinablePar::SetHumanMin(const REAL min) { mMin=min/mHumanScale;this->Click();} REAL RefinablePar::GetMax()const {return mMax;} void RefinablePar::SetMax(const REAL max) { mMax=max;this->Click();} REAL RefinablePar::GetHumanMax()const {return mMax * mHumanScale;} void RefinablePar::SetHumanMax(const REAL max) { mMax=max/mHumanScale;this->Click();} REAL RefinablePar::GetPeriod()const {return mPeriod;} void RefinablePar::SetPeriod(const REAL period) { mPeriod=period;this->Click();} REAL RefinablePar::GetDerivStep()const { if(REFPAR_DERIV_STEP_ABSOLUTE==mRefParDerivStepModel) return mDerivStep; REAL d=mDerivStep* (*mpValue); //:KLUDGE: Parameter will probably has a singular value, so it should not matter.. if(d == 0.) return 1e-8; return d; } void RefinablePar::SetDerivStep(const REAL step) { this->Click(); mDerivStep = step; } REAL RefinablePar::GetGlobalOptimStep()const {return mGlobalOptimStep;} void RefinablePar::SetGlobalOptimStep(const REAL step) {mGlobalOptimStep=step;} REAL RefinablePar::GetHumanScale()const {return mHumanScale;} void RefinablePar::SetHumanScale(const REAL scale) {mHumanScale=scale;} #if 0 void RefinablePar::SetUseEquation(const bool useItOrNot,const REAL c0) { this->Click(); mUseEquation=useItOrNot; if(true==mUseEquation) { mEquationCoeff.resize(mEquationMaxRefPar); mEquationCoeff(0)=c0; } } void RefinablePar::SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1) { this->Click(); mUseEquation=useItOrNot; if(true==mUseEquation) { mEquationCoeff.resize(mEquationMaxRefPar); mEquationCoeff(0)=c0; mEquationCoeff(1)=c1; mEquationRefPar[0]=&refpar1; } } void RefinablePar::SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1, const REAL c2, const RefinablePar &refpar2) { this->Click(); mUseEquation=useItOrNot; if(true==mUseEquation) { mEquationCoeff.resize(mEquationMaxRefPar); mEquationCoeff(0)=c0; mEquationCoeff(1)=c1; mEquationCoeff(2)=c2; mEquationRefPar[0]=&refpar1; mEquationRefPar[1]=&refpar2; } } void RefinablePar::SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1, const REAL c2, const RefinablePar &refpar2, const REAL c3, const RefinablePar &refpar3) { this->Click(); mUseEquation=useItOrNot; if(true==mUseEquation) { mEquationCoeff.resize(mEquationMaxRefPar); mEquationCoeff(0)=c0; mEquationCoeff(1)=c1; mEquationCoeff(2)=c2; mEquationCoeff(3)=c2; mEquationRefPar[0]=&refpar1; mEquationRefPar[1]=&refpar2; mEquationRefPar[2]=&refpar2; } } #endif void RefinablePar::AssignClock(RefinableObjClock &clock) { VFN_DEBUG_MESSAGE("RefinablePar::AssignClock() for "<GetName()<< "at "<<&clock,4) mpClock=&clock; mHasAssignedClock=true; } void RefinablePar::Click() { if(false==mHasAssignedClock) return; VFN_DEBUG_MESSAGE("RefinablePar::Click():"<GetName(),1) mpClock->Click(); //mpClock->Print(); //VFN_DEBUG_MESSAGE("RefinablePar::Click():End",2) } void RefinablePar::SetLimitsAbsolute(const REAL min, const REAL max) { //:TODO: check limits mMin=min; mMax=max; mHasLimits=true; } void RefinablePar::SetLimitsRelative(const REAL min, const REAL max) { VFN_DEBUG_MESSAGE("RefinablePar::SetLimitsRelative():"<GetName(),1) //:TODO: check limits mMin=this->GetValue()+min; mMax=this->GetValue()+max; this->SetIsLimited(true); } void RefinablePar::SetLimitsProportional(const REAL min, const REAL max) { //:TODO: check limits mMin=this->GetValue()*min; mMax=this->GetValue()*max; this->SetIsLimited(true); } #ifdef __WX__CRYST__ WXCrystObjBasic* RefinablePar::WXCreate(wxWindow *parent) { VFN_DEBUG_MESSAGE("RefinablePar::WXCreate()",8) if(mpWXFieldRefPar!=0) { throw ObjCrystException((string)"RefinablePar::WXCreate():"+this->GetName()+(string)" WXFieldRefPar already exists !"); } mpWXFieldRefPar=new WXFieldRefPar (parent,this->GetName(),this); return (WXCrystObjBasic*) mpWXFieldRefPar; } WXCrystObjBasic* RefinablePar::WXGet() { return (WXCrystObjBasic*) mpWXFieldRefPar; } void RefinablePar::WXDelete() { if(0!=mpWXFieldRefPar) { VFN_DEBUG_MESSAGE("RefinablePar::WXDelete():"<GetName()<< \ " to "<GetChoiceName(choice),5) mChoice=choice; mClock.Click(); } void RefObjOpt::SetChoice(const string &choiceName) { int choice; for(choice=0;choiceSetChoice(choice); } const string& RefObjOpt::GetName()const { return *mpName; } const string& RefObjOpt::GetClassName()const { static string className="Option"; return className; } const string& RefObjOpt::GetChoiceName(const int i)const { return *(mpChoiceName+i); } const RefinableObjClock& RefObjOpt::GetClock()const{return mClock;} #ifdef __WX__CRYST__ WXCrystObjBasic* RefObjOpt::WXCreate(wxWindow *parent) { VFN_DEBUG_MESSAGE("RefObjOpt::WXCreate()",8) mpWXFieldOption=new WXFieldOption (parent,-1,this); return mpWXFieldOption; } WXCrystObjBasic* RefObjOpt::WXGet() { return mpWXFieldOption; } void RefObjOpt::WXDelete() { if(0!=mpWXFieldOption) { VFN_DEBUG_MESSAGE("RefObjOpt::WXDelete()",5) delete mpWXFieldOption; } mpWXFieldOption=0; } void RefObjOpt::WXNotifyDelete() { VFN_DEBUG_MESSAGE("RefObjOpt::WXNotifyDelete()",5) mpWXFieldOption=0; } #endif //###################################################################### // RefObjOption //###################################################################### template RefObjOption::RefObjOption(T* obj): mpObj(obj) {} template RefObjOption::~RefObjOption() {} template void RefObjOption::SetChoice(const int choice) { if(mChoice==choice)return; VFN_DEBUG_MESSAGE("RefObjOption::SetChoice()"<GetName()<< \ " to "<GetChoiceName(choice),5) mChoice=choice; mClock.Click(); if(mfpSetNewValue !=0) (mpObj->*mfpSetNewValue)(choice); } template void RefObjOption::Init(const int nbChoice, const string *name, const string *choiceNames, void (T::*fp)(const int)) { this->RefObjOpt::Init(nbChoice,name,choiceNames); mfpSetNewValue=fp; } //###################################################################### // ObjRegistry //###################################################################### #ifdef __WX__CRYST__ bool operator==(const wxString&wx,const string&str) { return wx==str.c_str(); } bool operator==(const string&str,const wxString&wx) { return wx==str.c_str(); } #endif template ObjRegistry::ObjRegistry(): mName(""),mAutoUpdateUI(true) #ifdef __WX__CRYST__ ,mpWXRegistry(0) #endif { VFN_DEBUG_MESSAGE("ObjRegistry::ObjRegistry()",5) } template ObjRegistry::ObjRegistry(const string &name): mName(name),mAutoUpdateUI(true) #ifdef __WX__CRYST__ ,mpWXRegistry(0) #endif { VFN_DEBUG_MESSAGE("ObjRegistry::ObjRegistry(name):"< ObjRegistry::~ObjRegistry() { VFN_DEBUG_MESSAGE("ObjRegistry::~ObjRegistry():"<WXDelete(); #endif } template void ObjRegistry::Register(T &obj) { VFN_DEBUG_ENTRY("ObjRegistry("<::iterator pos=find(mvpRegistry.begin(),mvpRegistry.end(),&obj); if(pos!=mvpRegistry.end()) { VFN_DEBUG_EXIT("ObjRegistry("<Add(obj.WXCreate(mpWXRegistry)); #endif //this->Print(); VFN_DEBUG_EXIT("ObjRegistry("< void ObjRegistry::DeRegister(T &obj) { VFN_DEBUG_ENTRY("ObjRegistry("<Print(); typename vector::iterator pos=find(mvpRegistry.begin(),mvpRegistry.end(),&obj); if(pos==mvpRegistry.end()) { VFN_DEBUG_EXIT("ObjRegistry("<Remove(obj.WXGet()); #endif mvpRegistry.erase(pos); typename list::iterator pos2=find(mvpRegistryList.begin(),mvpRegistryList.end(),&obj); mvpRegistryList.erase(pos2); mListClock.Click(); VFN_DEBUG_EXIT("ObjRegistry("< void ObjRegistry::DeRegister(const string &objName) { VFN_DEBUG_ENTRY("ObjRegistry("<Find(objName); if(-1==i) { VFN_DEBUG_EXIT("ObjRegistry("<::iterator pos=find(mvpRegistry.begin(),mvpRegistry.end(),mvpRegistry[i]); #ifdef __WX__CRYST__ if(0!=mpWXRegistry) mpWXRegistry->Remove((*pos)->WXGet()); #endif mvpRegistry.erase(pos); typename list::iterator pos2=find(mvpRegistryList.begin(),mvpRegistryList.end(),mvpRegistry[i]); mvpRegistryList.erase(pos2); mListClock.Click(); VFN_DEBUG_EXIT("ObjRegistry("< void ObjRegistry::DeRegisterAll() { VFN_DEBUG_ENTRY("ObjRegistry("<::iterator pos; for(pos=mvpRegistry.begin();pos!=mvpRegistry.end();++pos) mpWXRegistry->Remove((*pos)->WXGet()); } #endif mvpRegistry.clear(); mvpRegistryList.clear(); mListClock.Click(); VFN_DEBUG_EXIT("ObjRegistry("< void ObjRegistry::DeleteAll() { VFN_DEBUG_ENTRY("ObjRegistry("< reg=mvpRegistry;//mvpRegistry will be modified as objects are deleted, so use a copy typename vector::iterator pos; for(pos=reg.begin();pos!=reg.end();++pos) delete *pos; mvpRegistry.clear(); mvpRegistryList.clear(); mListClock.Click(); VFN_DEBUG_EXIT("ObjRegistry("< T& ObjRegistry::GetObj(const unsigned int i) { if(i>=this->GetNb()) throw ObjCrystException("ObjRegistry::GetObj(i): i >= nb!"); return *(mvpRegistry[i]); } template const T& ObjRegistry::GetObj(const unsigned int i) const { if(i>=this->GetNb()) throw ObjCrystException("ObjRegistry::GetObj(i): i >= nb!"); return *(mvpRegistry[i]); } template T& ObjRegistry::GetObj(const string &objName) { const long i=this->Find(objName); return *(mvpRegistry[i]); } template const T& ObjRegistry::GetObj(const string &objName) const { const long i=this->Find(objName); return *(mvpRegistry[i]); } template T& ObjRegistry::GetObj(const string &objName, const string& className) { const long i=this->Find(objName,className); return *(mvpRegistry[i]); } template const T& ObjRegistry::GetObj(const string &objName, const string& className) const { const long i=this->Find(objName,className); return *(mvpRegistry[i]); } template long ObjRegistry::GetNb()const{return (long)mvpRegistry.size();} template void ObjRegistry::Print()const { VFN_DEBUG_MESSAGE("ObjRegistry::Print():",2) cout <GetNb()<<" object registered:" <GetNb();++i) cout << boost::format("#%3d:%s(%s)") %i %this->GetObj(i).GetClassName() %this->GetObj(i).GetName()< void ObjRegistry::SetName(const string &name){ mName=name;} template const string& ObjRegistry::GetName()const { return mName;} template long ObjRegistry::Find(const string &objName) const { VFN_DEBUG_MESSAGE("ObjRegistry::Find(objName)",2) long index=-1; //bool error=false; for(long i=this->GetNb()-1;i>=0;i--) if( mvpRegistry[i]->GetName() == objName) return i; // if(-1 != index) error=true ;else index=i; //if(true == error) //{ // cout << "ObjRegistry::Find(name) : "; // cout << "found duplicate name ! This *cannot* be !!" ; // cout << objName <Print(); // throw 0; //} cout << "ObjRegistry::Find("<Print(); throw ObjCrystException("ObjRegistry::Find("+objName+"): Not found !!"); return index; } template long ObjRegistry::Find(const string &objName, const string &className, const bool nothrow) const { VFN_DEBUG_MESSAGE("ObjRegistry::Find(objName,className)",2) long index=-1; //bool error=false; for(long i=this->GetNb()-1;i>=0;i--) if( mvpRegistry[i]->GetName() == objName) if(className==mvpRegistry[i]->GetClassName()) return i; // if(-1 != index) error=true ;else index=i; //if(true == error) //{ // cout << "ObjRegistry::Find(name) : "; // cout << "found duplicate name ! This *cannot* be !!" ; // cout << objName <Print(); // throw 0; //} cout << "ObjRegistry::Find("<Print(); if(nothrow==false) throw ObjCrystException("ObjRegistry::Find("+objName+","+className+"): Not found !!"); return index; } template long ObjRegistry::Find(const T &obj) const { VFN_DEBUG_MESSAGE("ObjRegistry::Find(&obj)",2) for(long i=this->GetNb()-1;i>=0;i--) if( mvpRegistry[i]== &obj) return i; //:TODO: throw something return -1; } template long ObjRegistry::Find(const T *pobj) const { VFN_DEBUG_MESSAGE("ObjRegistry::Find(&obj)",2) for(long i=this->GetNb()-1;i>=0;i--) if( mvpRegistry[i]== pobj) return i; //:TODO: throw something return -1; } template const RefinableObjClock& ObjRegistry::GetRegistryClock()const{return mListClock;} template void ObjRegistry::AutoUpdateUI(const bool autoup) { mAutoUpdateUI=autoup; } template void ObjRegistry::UpdateUI() { #ifdef __WX__CRYST__ for(unsigned int i=0;iGetNb();i++) { if((this->GetObj(i).WXGet()==NULL) && (0!=mpWXRegistry)) mpWXRegistry->Add(this->GetObj(i).WXCreate(mpWXRegistry)); } #endif } template std::size_t ObjRegistry::size() const { return (std::size_t) mvpRegistry.size(); } template typename vector::const_iterator ObjRegistry::begin() const { return mvpRegistry.begin(); } template typename vector::const_iterator ObjRegistry::end() const { return mvpRegistry.end(); } template typename list::const_iterator ObjRegistry::list_begin() const { return mvpRegistryList.begin(); } template typename list::const_iterator ObjRegistry::list_end() const { return mvpRegistryList.end(); } #ifdef __WX__CRYST__ template WXRegistry* ObjRegistry::WXCreate(wxWindow *parent) { VFN_DEBUG_MESSAGE("ObjRegistry::WXCreate()",2) mpWXRegistry=new WXRegistry (parent,this); for(int i=0;iGetNb();i++) mpWXRegistry->Add(this->GetObj(i).WXCreate(mpWXRegistry)); return mpWXRegistry; } template void ObjRegistry::WXDelete() { if(0!=mpWXRegistry) { VFN_DEBUG_MESSAGE("ObjRegistry::WXDelete()",2) delete mpWXRegistry; } mpWXRegistry=0; } template void ObjRegistry::WXNotifyDelete() { VFN_DEBUG_MESSAGE("ObjRegistry::WXNotifyDelete()",2) mpWXRegistry=0; } #endif //###################################################################### // function RefObjRegisterRecursive //###################################################################### template void RefObjRegisterRecursive(T &obj,ObjRegistry ®) { VFN_DEBUG_MESSAGE("RefObjRegisterRecursive()",3) reg.Register(obj); ObjRegistry *pObjReg=&(obj.GetSubObjRegistry()); for(int i=0;iGetNb();i++) RefObjRegisterRecursive(pObjReg->GetObj(i),reg); return; } //###################################################################### // function RefObjRegisterRecursive //###################################################################### void GetSubRefObjListClockRecursive(ObjRegistry ®,RefinableObjClock &clock) { if(reg.GetRegistryClock()>clock) clock=reg.GetRegistryClock(); for(int i=0;i gRefinableObjRegistry("Global RefinableObj registry"); ObjRegistry gTopRefinableObjRegistry("Global Top RefinableObj registry"); RefinableObj::RefinableObj(): mName(""), mNbRefParNotFixed(-1),mOptimizationDepth(0),mDeleteRefParInDestructor(true) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_MESSAGE("RefinableObj::RefinableObj()",3) gRefinableObjRegistry.Register(*this); mSubObjRegistry.SetName("Registry for sub-objects"); mClientObjRegistry.SetName("Registry for Clients"); VFN_DEBUG_MESSAGE("RefinableObj::RefinableObj():End",2) } RefinableObj::RefinableObj(const bool internalUseOnly): mName(""), mNbRefParNotFixed(-1),mOptimizationDepth(0),mDeleteRefParInDestructor(true) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_MESSAGE("RefinableObj::RefinableObj(bool)",3) if(false==internalUseOnly) gRefinableObjRegistry.Register(*this); mSubObjRegistry.SetName("Registry for sub-objects"); mClientObjRegistry.SetName("Registry for Clients"); VFN_DEBUG_MESSAGE("RefinableObj::RefinableObj(bool):End",2) } RefinableObj::RefinableObj(const RefinableObj &old) {} /* RefinableObj::RefinableObj(const RefinableObj &old): mName(old.mName),mMaxNbRefPar(old.mMaxNbRefPar),mSavedValuesSetIsUsed(mMaxNbSavedSets), mOptimizationDepth(0),mDeleteRefParInDestructor(true) #ifdef __WX__CRYST__ ,mpWXCrystObj(0) #endif { VFN_DEBUG_MESSAGE("RefinableObj::RefinableObj(RefinableObj&)",3) mpRefPar = new RefinablePar*[mMaxNbRefPar]; mpSavedValuesSet = new CrystVector_REAL* [mMaxNbSavedSets]; mpSavedValuesSetName = new string* [mMaxNbSavedSets]; mSavedValuesSetIsUsed=false; *this=old; mSubObjRegistry.SetName("Registry for sub-objects of "+mName); mClientObjRegistry.SetName("Registry for Clients of "+mName); gRefinableObjRegistry.Register(*this); } */ RefinableObj::~RefinableObj() { VFN_DEBUG_MESSAGE("RefinableObj::~RefinableObj():"<GetName(),5) if(mvpRefPar.size()>0) { if(true==mDeleteRefParInDestructor) { vector::iterator pos; for(pos=mvpRefPar.begin();pos!=mvpRefPar.end();pos++) delete *pos; } } gRefinableObjRegistry.DeRegister(*this); for(int i=0;iWXDelete(); #endif } const string& RefinableObj::GetClassName() const { const static string className="RefinableObj"; return className; } const string& RefinableObj::GetName() const {return mName;} void RefinableObj::SetName(const string &name) { VFN_DEBUG_MESSAGE("RefinableObj::SetName()to :"<ResetParList(); //this->AddPar(old); // Do not copy old saved sets //... but erase any that may be stored for(long i=0;iGetNbPar()); for(long i=0;iGetNbPar();i++) if ( (this->GetPar(i).IsFixed() == false) && (this->GetPar(i).IsUsed() == true)) { mRefparNotFixedIndex(mNbRefParNotFixed) = i; mNbRefParNotFixed++; } //this->Print(); VFN_DEBUG_MESSAGE("RefinableObj::PrepareForRefinement():End",5) } void RefinableObj::FixAllPar() { VFN_DEBUG_ENTRY("RefinableObj("<GetClassName()<<":" <GetName()<<")::FixAllPar()",4) for(long i=0;iGetNbPar();i++) this->GetPar(i).SetIsFixed(true); for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).FixAllPar(); VFN_DEBUG_EXIT("RefinableObj("<GetName()<<")::FixAllPar()",4) } void RefinableObj::UnFixAllPar() { for(long i=0;iGetNbPar();i++) this->GetPar(i).SetIsFixed(false); for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).UnFixAllPar(); } void RefinableObj::SetParIsFixed(const long parIndex,const bool fix) { this->GetPar(parIndex).SetIsFixed(fix); } void RefinableObj::SetParIsFixed(const string& name,const bool fix) { for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) this->GetPar(i).SetIsFixed(fix); } void RefinableObj::SetParIsFixed(const RefParType *type,const bool fix) { for(long i=0;iGetNbPar();i++) if( this->GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) { //cout << " Fixing ..." << this->GetPar(i).Name()<GetPar(i).SetIsFixed(fix); } for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetParIsFixed(type,fix); } void RefinableObj::SetParIsUsed(const string& name,const bool use) { for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) this->GetPar(i).SetIsUsed(use); } void RefinableObj::SetParIsUsed(const RefParType *type,const bool use) { for(long i=0;iGetNbPar();i++) if( this->GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) { //cout << " Now used (Waow!) : ..." << this->GetPar(i).Name()<GetPar(i).SetIsUsed(use); } for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetParIsUsed(type,use); } long RefinableObj::GetNbPar()const { return mvpRefPar.size();} long RefinableObj::GetNbParNotFixed()const {return mNbRefParNotFixed;} RefinablePar& RefinableObj::GetPar(const long i) { return *(mvpRefPar[i]); } const RefinablePar& RefinableObj::GetPar(const long i) const { return *(mvpRefPar[i]); } RefinablePar& RefinableObj::GetPar(const string & name) { const long i=this->FindPar(name); if(-1==i) { this->Print(); throw ObjCrystException("RefinableObj::GetPar(): cannot find parameter: "+name+" in object:"+this->GetName()); } return *(mvpRefPar[i]); } const RefinablePar& RefinableObj::GetPar(const string & name) const { const long i=this->FindPar(name); if(-1==i) { this->Print(); throw ObjCrystException("RefinableObj::GetPar(): cannot find parameter: "+name+" in object:"+this->GetName()); } return *(mvpRefPar[i]); } RefinablePar& RefinableObj::GetPar(const REAL *p) { const long i=this->FindPar(p); if(-1==i) { this->Print(); throw ObjCrystException("RefinableObj::GetPar(*p): cannot find parameter in object:"+this->GetName()); } return *(mvpRefPar[i]); } const RefinablePar& RefinableObj::GetPar(const REAL *p) const { const long i=this->FindPar(p); if(-1==i) { this->Print(); throw ObjCrystException("RefinableObj::GetPar(*p): cannot find parameter in object:"+this->GetName()); } return *(mvpRefPar[i]); } RefinablePar& RefinableObj::GetParNotFixed(const long i) { return *(mvpRefPar[mRefparNotFixedIndex(i)]); } const RefinablePar& RefinableObj::GetParNotFixed(const long i) const { return *(mvpRefPar[mRefparNotFixedIndex(i)]); } void RefinableObj::AddPar(const RefinablePar &newRefPar) { VFN_DEBUG_MESSAGE("RefinableObj::AddPar(RefPar&)",2) string name=newRefPar.GetName(); long ct=0; if(this->FindPar(name)>=0) while(this->FindPar(name)!=-1) {// KLUDGE ? Extend name if another parameter already exists with the same name VFN_DEBUG_MESSAGE("RefinableObj::AddPar(): need to change name ?! -> "<FindPar(name),10) name += "~"; if(++ct==100) break;// KLUDGE, let go and hope for the best... } mvpRefPar.push_back(new RefinablePar(newRefPar)); mvpRefPar.back()->SetName(name); mRefParListClock.Click(); } void RefinableObj::AddPar(RefinablePar *newRefPar) { VFN_DEBUG_MESSAGE("RefinableObj::AddPar(RefPar&)",2) string name=newRefPar->GetName(); long ct=0; if(this->FindPar(name)>=0) while(this->FindPar(name)!=-1) {// KLUDGE ? Extend name if another parameter already exists with the same name VFN_DEBUG_MESSAGE("RefinableObj::AddPar(): need to change name ?! -> "<FindPar(name),10) name += "~"; if(++ct==100) break;// KLUDGE, let go and hope for the best... } mvpRefPar.push_back(newRefPar); mvpRefPar.back()->SetName(name); mRefParListClock.Click(); } void RefinableObj::AddPar(RefinableObj &newRefParList,const bool copyParam) { VFN_DEBUG_MESSAGE("RefinableObj::AddPar(RefParList&)" <AddPar(p); } } vector::iterator RefinableObj::RemovePar(RefinablePar *refPar) { VFN_DEBUG_MESSAGE("RefinableObj::RemovePar(RefPar&)",2) vector::iterator pos=find(mvpRefPar.begin(),mvpRefPar.end(),refPar); if(pos==mvpRefPar.end()) { throw ObjCrystException("RefinableObj::RemovePar():"+refPar->GetName() +"is not in this object:"+this->GetName()); } return mvpRefPar.erase(pos); } void RefinableObj::Print() const { VFN_DEBUG_ENTRY("RefinableObj::Print()",2) cout << "Refinable Object:"<GetName() <<", with " << this->GetNbPar() << " parameters" <GetNbPar();i++) { if(this->GetPar(i).IsUsed() == false) continue; cout << "#"<GetPar(i).GetName() << ": " ; cout << FormatFloat(this->GetPar(i).GetHumanValue(),18,12) << " "; if(true == this->GetPar(i).IsFixed()) cout << "Fixed"; else if(true == this->GetPar(i).IsLimited()) { cout << "Limited (" << this->GetPar(i).GetHumanMin()<<"," <GetPar(i).GetHumanMax()<<")"; if(true == this->GetPar(i).IsPeriodic()) cout << ",Periodic" ; } VFN_DEBUG_MESSAGE_SHORT(" (at "<GetPar(i).mpValue<<")",5) if(true == this->GetPar(i).mHasAssignedClock) { VFN_DEBUG_MESSAGE_SHORT(" (Clock at "<GetPar(i).mpClock<<")",5) } cout << endl; } VFN_DEBUG_EXIT("RefinableObj::Print()",2) } unsigned long RefinableObj::CreateParamSet(const string name) const { VFN_DEBUG_ENTRY("RefinableObj::CreateParamSet()",3) unsigned long id; for(id=0;id<=mvpSavedValuesSet.size();id++) if(mvpSavedValuesSet.end()==mvpSavedValuesSet.find(id)) break; pair< CrystVector_REAL ,string> p; p.second=name; mvpSavedValuesSet.insert(make_pair(id,p)); this->SaveParamSet(id); VFN_DEBUG_MESSAGE("RefinableObj::CreateParamSet(): new parameter set with id="<FindParamSet(id)); VFN_DEBUG_EXIT("RefinableObj::ClearParamSet()",2) } void RefinableObj::SaveParamSet(const unsigned long id)const { VFN_DEBUG_MESSAGE("RefinableObj::SaveRefParSet()",2) map >::iterator pos=this->FindParamSet(id); pos->second.first.resize(mvpRefPar.size()); REAL *p=pos->second.first.data(); for(long i=0;iGetNbPar();i++) *p++ = this->GetPar(i).GetValue(); } void RefinableObj::RestoreParamSet(const unsigned long id) { VFN_DEBUG_MESSAGE("RefinableObj::RestoreRefParSet()",2) map >::iterator pos=this->FindParamSet(id); REAL *p=pos->second.first.data(); for(long i=0;iGetNbPar();i++) { //if( !this->GetPar(i).IsFixed() && this->GetPar(i).IsUsed()) if(this->GetPar(i).IsUsed()) this->GetPar(i).SetValue(*p); p++; } } const CrystVector_REAL & RefinableObj::GetParamSet(const unsigned long id)const { VFN_DEBUG_MESSAGE("RefinableObj::GetParamSet() const",2) map >::const_iterator pos=this->FindParamSet(id); return pos->second.first; } CrystVector_REAL & RefinableObj::GetParamSet(const unsigned long id) { VFN_DEBUG_MESSAGE("RefinableObj::GetParamSet()",2) map >::iterator pos=this->FindParamSet(id); return pos->second.first; } REAL RefinableObj::GetParamSet_ParNotFixedHumanValue(const unsigned long id, const long par)const { VFN_DEBUG_MESSAGE("RefinableObj::RefParSetNotFixedHumanValue()",0) map >::iterator pos=this->FindParamSet(id); return pos->second.first(mRefparNotFixedIndex(par)); } const void RefinableObj::EraseAllParamSet() { mvpSavedValuesSet.clear(); } const string& RefinableObj::GetParamSetName(const unsigned long id)const { VFN_DEBUG_MESSAGE("RefinableObj::GetParamSetName()",2) map >::const_iterator pos=this->FindParamSet(id); return pos->second.second; } void RefinableObj::SetLimitsAbsolute(const string &name,const REAL min,const REAL max) { for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) this->GetPar(i).SetLimitsAbsolute(min,max); } void RefinableObj::SetLimitsAbsolute(const RefParType *type, const REAL min,const REAL max) { for(long i=0;iGetNbPar();i++) if(this->GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) this->GetPar(i).SetLimitsAbsolute(min,max); for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetLimitsAbsolute(type,min,max); } void RefinableObj::SetLimitsRelative(const string &name, const REAL min, const REAL max) { for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) this->GetPar(i).SetLimitsRelative(min,max); } void RefinableObj::SetLimitsRelative(const RefParType *type, const REAL min, const REAL max) { VFN_DEBUG_MESSAGE("RefinableObj::SetLimitsRelative(RefParType*):"<GetName(),2) for(long i=0;iGetNbPar();i++) { VFN_DEBUG_MESSAGE("RefinableObj::SetLimitsRelative(RefParType*):par #"<GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) this->GetPar(i).SetLimitsRelative(min,max); } for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetLimitsRelative(type,min,max); } void RefinableObj::SetLimitsProportional(const string &name,const REAL min,const REAL max) { for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) this->GetPar(i).SetLimitsProportional(min,max); } void RefinableObj::SetLimitsProportional(const RefParType *type, const REAL min, const REAL max) { for(long i=0;iGetNbPar();i++) if(this->GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) this->GetPar(i).SetLimitsProportional(min,max); for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetLimitsProportional(type,min,max); } void RefinableObj::SetGlobalOptimStep(const RefParType *type, const REAL step) { for(long i=0;iGetNbPar();i++) if(this->GetPar(i).GetType()->IsDescendantFromOrSameAs(type)) this->GetPar(i).SetGlobalOptimStep(step); for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).SetGlobalOptimStep(type,step); } ObjRegistry& RefinableObj::GetSubObjRegistry() {return mSubObjRegistry;} const ObjRegistry& RefinableObj::GetSubObjRegistry()const {return mSubObjRegistry;} void RefinableObj::RegisterClient(RefinableObj &obj)const {mClientObjRegistry.Register(obj);} void RefinableObj::DeRegisterClient(RefinableObj &obj)const {mClientObjRegistry.DeRegister(obj);} const ObjRegistry& RefinableObj::GetClientRegistry()const{return mClientObjRegistry;} ObjRegistry& RefinableObj::GetClientRegistry() {return mClientObjRegistry;} bool RefinableObj::IsBeingRefined()const {return mOptimizationDepth>0;} extern const long ID_WXOBJ_ENABLE; //These are defined in wxCryst/wxCryst.cpp extern const long ID_WXOBJ_DISABLE; void RefinableObj::BeginOptimization(const bool allowApproximations, const bool enableRestraints) { mOptimizationDepth++; if(mOptimizationDepth>1) return; this->Prepare(); for(int i=0;iEnable(false); else { wxUpdateUIEvent event(ID_WXOBJ_DISABLE); wxPostEvent(mpWXCrystObj,event); } } #endif } void RefinableObj::EndOptimization() { mOptimizationDepth--; if(mOptimizationDepth<0) throw ObjCrystException("RefinableObj::EndOptimization(): mOptimizationDepth<0 !!"); if(mOptimizationDepth>0) return; for(int i=0;iEnable(true); else { wxUpdateUIEvent event(ID_WXOBJ_ENABLE); wxPostEvent(mpWXCrystObj,event); } } #endif } void RefinableObj::SetApproximationFlag(const bool allow) { for(int i=0;iPrepareForRefinement(); for(int j=0;jGetNbParNotFixed();j++) { if(true==this->GetParNotFixed(j).IsLimited()) { const REAL min=this->GetParNotFixed(j).GetMin(); const REAL max=this->GetParNotFixed(j).GetMax(); this->GetParNotFixed(j).MutateTo(min+(max-min)*(rand()/(REAL)RAND_MAX) ); } else if(true==this->GetParNotFixed(j).IsPeriodic()) { this->GetParNotFixed(j).MutateTo((rand()/(REAL)RAND_MAX) * this->GetParNotFixed(j).GetPeriod()); } } for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).RandomizeConfiguration(); VFN_DEBUG_EXIT("RefinableObj::RandomizeConfiguration():Finished",5) } void RefinableObj::GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type) { if(mRandomMoveIsDone) return; VFN_DEBUG_ENTRY("RefinableObj::GlobalOptRandomMove()",2) for(int j=0;jGetNbParNotFixed();j++) { if(this->GetParNotFixed(j).GetType()->IsDescendantFromOrSameAs(type)) this->GetParNotFixed(j).Mutate( this->GetParNotFixed(j).GetGlobalOptimStep() *2*(rand()/(REAL)RAND_MAX-0.5)*mutationAmplitude); } for(int i=0;i::const_iterator pos; for(pos=mvpRestraint.begin();pos!=mvpRestraint.end();pos++) { VFN_DEBUG_MESSAGE("RefinableObj::GetLogLikelihood()Restraint: "<<*pos,2) loglike+= (*pos)->GetLogLikelihood(); } VFN_DEBUG_EXIT("RefinableObj::GetLogLikelihood()="<& RefinableObj::GetLogLikelihood_FullDeriv(std::set &vPar) // { // //TODO // return mLogLikelihood_FullDeriv; // } const CrystVector_REAL& RefinableObj::GetLSQCalc(const unsigned int) const { throw ObjCrystException("Error: called RefinableObj::GetLSQCalc()"); CrystVector_REAL *noWarning=new CrystVector_REAL; return *noWarning; } const CrystVector_REAL& RefinableObj::GetLSQObs(const unsigned int) const { throw ObjCrystException("Error: called RefinableObj::GetLSQObs()"); CrystVector_REAL *noWarning=new CrystVector_REAL; return *noWarning; } const CrystVector_REAL& RefinableObj::GetLSQWeight(const unsigned int) const { throw ObjCrystException("Error: called RefinableObj::GetLSQWeight()"); CrystVector_REAL *noWarning=new CrystVector_REAL; return *noWarning; } const CrystVector_REAL& RefinableObj::GetLSQDeriv(const unsigned int n, RefinablePar&par) { // By default, use numerical derivatives const REAL step=par.GetDerivStep(); par.Mutate(step); mLSQDeriv =this->GetLSQCalc(n); par.Mutate(-2*step); mLSQDeriv -=this->GetLSQCalc(n); par.Mutate(step); mLSQDeriv /= step*2; return mLSQDeriv; } std::map & RefinableObj::GetLSQ_FullDeriv(const unsigned int n,std::set &vPar) { mLSQ_FullDeriv[n].clear(); mLSQ_FullDeriv[n][(RefinablePar*)0]=this->GetLSQCalc(n); for(std::set::const_iterator pos=vPar.begin();pos!=vPar.end();pos++) mLSQ_FullDeriv[n][*pos]=this->GetLSQDeriv(n,**pos); return mLSQ_FullDeriv[n]; } void RefinableObj::ResetParList() { VFN_DEBUG_MESSAGE("RefinableObj::ResetParList()",3) if(mvpRefPar.size()>0) { if(true==mDeleteRefParInDestructor) { vector::iterator pos; for(pos=mvpRefPar.begin();pos!=mvpRefPar.end();pos++) delete *pos; } mvpRefPar.clear(); } mNbRefParNotFixed=-1; VFN_DEBUG_MESSAGE("RefinableObj::ResetParList():Deleting Saved Sets....",2) this->EraseAllParamSet(); mRefParListClock.Click(); VFN_DEBUG_MESSAGE("RefinableObj::ResetParList():End.",3) } ObjRegistry& RefinableObj::GetOptionList() { return mOptionRegistry; } unsigned int RefinableObj::GetNbOption()const { return mOptionRegistry.GetNb(); } RefObjOpt& RefinableObj::GetOption(const unsigned int i) { VFN_DEBUG_MESSAGE("RefinableObj::GetOption()"<Print(); throw ObjCrystException("RefinableObj::GetOption(): cannot find option: "+name+" in object:"+this->GetName()); } return mOptionRegistry.GetObj(i); } const RefObjOpt& RefinableObj::GetOption(const unsigned int i)const { //:TODO: Check return mOptionRegistry.GetObj(i); } const RefObjOpt& RefinableObj::GetOption(const string & name)const { VFN_DEBUG_MESSAGE("RefinableObj::GetOption()"<Print(); throw ObjCrystException("RefinableObj::GetOption(): cannot find option: "+name+" in object:"+this->GetName()); } return mOptionRegistry.GetObj(i); } void RefinableObj::GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &first) const { VFN_DEBUG_MESSAGE("RefinableObj::GetGeneGroup()",4) for(long i=0;iGetNbPar();j++) if(&(obj.GetPar(i)) == &(this->GetPar(j))) groupIndex(i)= first++; } void RefinableObj::SetDeleteRefParInDestructor(const bool b) {mDeleteRefParInDestructor=b;} const RefinableObjClock& RefinableObj::GetRefParListClock()const{return mRefParListClock;} REAL RefinableObj::GetRestraintCost()const { vector::const_iterator pos; REAL cost(0); for(pos=mvpRestraint.begin();pos != mvpRestraint.end();++pos) cost += (*pos)->GetLogLikelihood(); return 0; } void RefinableObj::AddRestraint(Restraint *pNewRestraint) { VFN_DEBUG_MESSAGE("RefinableObj::AddRestraint(Restraint*)",2) mvpRestraint.push_back(pNewRestraint); } vector::iterator RefinableObj::RemoveRestraint(Restraint *pRestraint) { VFN_DEBUG_MESSAGE("RefinableObj::RemoveRestraint(Restraint*)",2) vector::iterator pos=find(mvpRestraint.begin(),mvpRestraint.end(),pRestraint); if(mvpRestraint.end() != pos) { return mvpRestraint.erase(pos); } else { cout <<"RefinableObj::RemoveRestraint(..)" <<" Whoops... tried to remove a Restraint which does not exist..."<CrystUpdate(true,true); VFN_DEBUG_EXIT("RefinableObj::UpdateDisplay()",3) #endif } long RefinableObj::FindPar(const string &name) const { long index=-1; bool warning=false; for(long i=this->GetNbPar()-1;i>=0;i--) if( this->GetPar(i).GetName() == name) { if(-1 != index) warning=true ;else index=i; } if(true == warning) { throw ObjCrystException("RefinableObj::FindPar("+name+"): found duplicate refinable variable name in object:"+this->GetName()); } return index; } long RefinableObj::FindPar(const REAL *p) const { long index=-1; bool warning=false; for(long i=this->GetNbPar()-1;i>=0;i--) if( p == mvpRefPar[i]->mpValue ) //&(this->GetPar(i).GetValue()) { if(-1 != index) warning=true ;else index=i; } if(true == warning) { throw ObjCrystException("RefinableObj::FindPar(*p): Found duplicate parameter in object:"+this->GetName()); } return index; } void RefinableObj::AddSubRefObj(RefinableObj &obj) { VFN_DEBUG_MESSAGE("RefinableObj::AddSubRefObj()",3) mSubObjRegistry.Register(obj); mClockMaster.AddChild(obj.GetClockMaster()); } void RefinableObj::RemoveSubRefObj(RefinableObj &obj) { VFN_DEBUG_MESSAGE("RefinableObj::RemoveSubRefObj()",3) mSubObjRegistry.DeRegister(obj); mClockMaster.RemoveChild(obj.GetClockMaster()); } void RefinableObj::AddOption(RefObjOpt *opt) { VFN_DEBUG_MESSAGE("RefinableObj::AddOption()",5) //:TODO: automagically resize the option array if necessary mOptionRegistry.Register(*opt); mClockMaster.AddChild(opt->GetClock()); VFN_DEBUG_MESSAGE("RefinableObj::AddOption():End",5) } void RefinableObj::Prepare() { VFN_DEBUG_MESSAGE("RefinableObj::Prepare()",5) for(int i=0;iGetSubObjRegistry().GetNb();i++) this->GetSubObjRegistry().GetObj(i).Prepare(); } map >::iterator RefinableObj:: FindParamSet(const unsigned long id)const { VFN_DEBUG_ENTRY("RefinableObj::FindParamSet()",2) map >::iterator pos; pos=mvpSavedValuesSet.find(id); if(mvpSavedValuesSet.end() == pos) {//throw up throw ObjCrystException("RefinableObj::FindParamSet(long): Unknown saved set ! In object:"+this->GetName()); } VFN_DEBUG_EXIT("RefinableObj::FindParamSet()",2) return pos; } #ifdef __WX__CRYST__ WXCrystObjBasic* RefinableObj::WXCreate(wxWindow *parent) { VFN_DEBUG_MESSAGE("RefinableObj::WXCreate()",8) mpWXCrystObj=new WXRefinableObj (parent,this); return mpWXCrystObj; } WXCrystObjBasic* RefinableObj::WXGet() { return mpWXCrystObj; } void RefinableObj::WXDelete() { if(0!=mpWXCrystObj) { VFN_DEBUG_MESSAGE("RefinableObj::WXDelete()",5) delete mpWXCrystObj; } mpWXCrystObj=0; } void RefinableObj::WXNotifyDelete() { VFN_DEBUG_MESSAGE("RefinableObj::WXNotifyDelete():"< ®,RefinableObjClock &clock) { for(int i=0;iclock) clock=reg.GetObj(i).GetRefParListClock(); GetRefParListClockRecursive(reg.GetObj(i).GetSubObjRegistry(),clock); } } //***********EXPLICIT INSTANTIATION*******************// template void RefObjRegisterRecursive(RefinableObj &obj,ObjRegistry ®); }//namespace #include "ObjCryst/ObjCryst/Crystal.h" #include "ObjCryst/ObjCryst/Scatterer.h" #include "ObjCryst/ObjCryst/ScatteringPower.h" #include "ObjCryst/ObjCryst/ZScatterer.h" #include "ObjCryst/ObjCryst/PowderPattern.h" #include "ObjCryst/ObjCryst/DiffractionDataSingleCrystal.h" #include "ObjCryst/ObjCryst/ScatteringCorr.h" #include "ObjCryst/RefinableObj/GlobalOptimObj.h" #include "ObjCryst/RefinableObj/IO.h" #include "ObjCryst/ObjCryst/ReflectionProfile.h" namespace ObjCryst { template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; //template class ObjRegistry;//to be removed template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class ObjRegistry; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; template class RefObjOption; //template class RefObjOption; //template class RefObjOption; } // namespace ObjCryst libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/RefinableObj.h000066400000000000000000001702261417150057700243320ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * header file for the RefinablePar and RefinableObj classes * * */ #ifndef _VFN_REFINABLE_OBJ_H_ #define _VFN_REFINABLE_OBJ_H_ #include #include #include #include #include #include #include "ObjCryst/CrystVector/CrystVector.h" #include "ObjCryst/ObjCryst/General.h" #include "ObjCryst/RefinableObj/IO.h" #ifdef __WX__CRYST__ class wxWindow; namespace ObjCryst { template class ObjRegistry; class RefObjOpt; template class RefObjOption; class RefinableObj; } #include "ObjCryst/wxCryst/wxRefinableObj.h" #endif namespace ObjCryst { /// How do we compute steps h for numerical derivative calculation : d=f(x+h)-f(x-h)/h/2 /// either h is fixed (absolute), or relative h=x*derivFactor enum RefParDerivStepModel { REFPAR_DERIV_STEP_ABSOLUTE, REFPAR_DERIV_STEP_RELATIVE }; /** \brief class of refinable parameter types. * * This is used to categorize all parameters, to be able to modify * a complete category of parameters (fix/unfix, set limits,...). * The types are organized as a tree. * * Parameters should be allocated globally in the heap, so we only use * pointers in the interface. * * \note when modifying (fixing, changing limits) for a given RefParType (ie a 'family' * of parameters), it affects all RefinablePar of this type \e and the parameters * belonging to the children of this RefParType. eg fixing for the type "gpRefParTypeScatt" * will fix all the derived postionnal, orientationnal, and population parameters * for the scatterers. * * \remarks In the future, why not use a tree with multiple inheritance ?? It would * be easy to allow multiple parents... But beware of loops... */ class RefParType { public: /// Create a \e top parameter type. (in ObjCryst, there is /// only one, the "ObjCryst" category. RefParType(const string &name); /// create a children type. RefParType(const RefParType *parent,const string &name); ///Destructor ~RefParType(); /// Returns true if the parameter is a descendant of 'type' bool IsDescendantFromOrSameAs(const RefParType *type) const; /// returns true if the two types are the same. bool operator==(const RefParType *parent) const; /// Get the name for this parameter const string& GetName() const; private: /// Get a Unique id (RefParType::mId) void InitId(); /// the parent for this RefParType (we could easily allow several...) const RefParType* mpParent; /// The name/description for this parameter type const string mName; /// The unique number identifying this type unsigned long mId; }; /// Top RefParType for the ObjCryst++ library. extern const RefParType *gpRefParTypeObjCryst; class NiftyStaticGlobalObjectsInitializer_RefinableObj { public: NiftyStaticGlobalObjectsInitializer_RefinableObj() { if (mCount++ == 0) { gpRefParTypeObjCryst=new RefParType("ObjCryst++"); } } ~NiftyStaticGlobalObjectsInitializer_RefinableObj() { if (--mCount == 0) { delete gpRefParTypeObjCryst; gpRefParTypeObjCryst=0; } } private: static long mCount; }; static NiftyStaticGlobalObjectsInitializer_RefinableObj NiftyStaticGlobalObjectsInitializer_RefinableObj_counter; /// We need to record exactly when refinable objects /// have been modified for the last time (to avoid re-computation), /// and to do that we need a precise time. Since the clock() function is not /// precise enough (and is architecture-dependant), we use a custom time, /// which records the number of events in the program which uses the library. /// This is purely internal, so don't worry about it... /// /// The clock values have nothing to do with 'time' as any normal person undertands it. class RefinableObjClock { public: RefinableObjClock(); ~RefinableObjClock(); bool operator< (const RefinableObjClock &rhs)const; bool operator<=(const RefinableObjClock &rhs)const; bool operator> (const RefinableObjClock &rhs)const; bool operator>=(const RefinableObjClock &rhs)const; /// Record an event for this clock (generally, the 'time' /// an object has been modified, or some computation has been made) void Click(); /// Reset a Clock to 0, to force an update void Reset(); /// Print clock value. Only for debugging purposes. void Print()const; /// Print current general clock value. Only for debugging purposes. void PrintStatic()const; /// Add a 'child' clock. Whenever a child clock is clicked, it will also click its parent. /// This function takes care of adding itself to the list of parent in the children clock. void AddChild(const RefinableObjClock &); /// remove a child clock. This also tells the child clock to remove the parent. void RemoveChild(const RefinableObjClock &); /// Add a 'parent' clock. Whenever a clock is clicked, all parent clocks /// also are. void AddParent(RefinableObjClock &)const; /// remove a parent clock void RemoveParent(RefinableObjClock &)const; /// This will (i) set the clock to the same values as the rhs clock, but will not change /// the list of children and parent clocks. This will afterwards Click() the clock /// to notify parents. void operator=(const RefinableObjClock &rhs); private: bool HasParent(const RefinableObjClock &) const; unsigned long mTick0, mTick1; static unsigned long msTick0,msTick1; /// List of 'child' clocks, which will click this clock whenever they are clicked. std::set mvChild; /// List of parent clocks, which will be clicked whenever this one is. This /// is a mutable list since reporting to parent clocks does not change /// the vlaue of the clock. mutable std::set mvParent; }; /** Restraint: generic class for a restraint of a given model. This * defines only the category (RefParType) of restraint, and the function * to access the log(likelihood) associated to this restraint and the current model. * * By default: -log(likelihood)=0, and the function must be overloaded * for "real" restraints. * *\note the log(likelihood) \e must always include the normalization term, * so that variances can also optimized during the maximum likelihood * optimization. e.g.: * - \f$ P=\frac{1}{\sqrt{2\pi\sigma^2}}e^{\frac{-(calc-expected)^2}{\sigma^2}}\f$ * - \f$ -\log(P)= \log\left(\sqrt{2\pi\sigma^2}\right) * + \left(\frac{calc-expected}{\sigma} \right)^2\f$ * * forgetting the normalization term would result in making the optimization diverge towards * infinite variances. */ class Restraint { public: /// Default constructor, sets RefParType to gpRefParTypeObjCryst Restraint(); ///constructor specifying the type Restraint(const RefParType *type); virtual ~Restraint(); virtual const RefParType* GetType()const; virtual void SetType(const RefParType *type); /// Get -ln(likelihood) for this restraint virtual REAL GetLogLikelihood()const; private: const RefParType *mpRefParType; }; /** Generic class for parameters of refinable objects. * These must be continuous. * * \todo: define parameters using equations between parameters. * \todo: for complex objects with lots of parameters, give the * possibility to define vectors of parameters, all with the same * properties, to reduce memory usage. */ class RefinablePar:public Restraint { public: /// \name Destructor & Constructors //@{ /** Default Constructor */ RefinablePar(); /** \brief Constructor *\par name: the name of the parameter *\par refPar: the address of the refined parameter *\par min,max: the minimum & maximum value for this parameter. Only used * if the parameter is limited. *\par type: the type (category) of refinable parameter. This is used to (de)activate * groups of parameters. *\par derivMode: to compute numerical (partial) derivatives, the step used is either * an absolute (fixed) value, or it can be proportionnal to the current value of the * parameter. *\par hasLimits: if true, then the parameter cannot exceed its limits. *\par isFixed: if true, the parameter cannot be refined. *\par isUsed: if false, then the parameter does not affect in any way the refined object, * and thus is simply ignored and should never appear to the user. *\par isPeriodic: if true, then when the parameter exceeds one of its limits, it is * shifted by the period (=max-min), in order to be back to the allowed [min,max] range. *\par humanScale:this is the scale which should be used to display the value to the * end program user. This is mostly used for angles: the values are stored in radians, so * that a scale equal to 180/pi must be used for a 'human-understandable' value. Use * the RefinablePar::HumanValue() in order to get this value. By default it * is equal to 1.0 (no scaling required). */ RefinablePar( const string &name, REAL *refPar, const REAL min, const REAL max, const RefParType *type, RefParDerivStepModel derivMode=REFPAR_DERIV_STEP_RELATIVE, const bool hasLimits=true, const bool isFixed=false, const bool isUsed=true, const bool isPeriodic=false, const REAL humanScale=1., REAL period=1.); /** Copy Constructor */ RefinablePar(const RefinablePar &ref); ~RefinablePar(); /** \brief Constructor *\par name: the name of the parameter *\par refPar: the address of the refined parameter *\par min,max: the minimum & maximum value for this parameter. Only used * if the parameter is limited. *\par type: the type (category) of refinable parameter. This is used to (de)activate * groups of parameters. *\par derivMode: to compute numerical (partial) derivatives, the step used is either * an absolute (fixed) value, or it can be proportionnal to the current value of the * parameter. *\par hasLimits: if true, then the parameter cannot exceed its limits. *\par isFixed: if true, the parameter cannot be refined. *\par isUsed: if false, then the parameter does not affect in any way the refined object, * and thus is simply ignored and should never appear to the user. *\par isPeriodic: if true, then when the parameter exceeds one of its limits, it is * shifted by the period (=max-min), in order to be back to the allowed [min,max] range. *\par humanScale:this is the scale which should be used to display the value to the * end program user. This is mostly used for angles: the values are stored in radians, so * that a scale equal to 180/pi must be used for a 'human-understandable' value. Use * the RefinablePar::HumanValue() in order to get this value. By default it * is equal to 1.0 (no scaling required). */ void Init( const string &name, REAL *refPar, const REAL min, const REAL max, const RefParType *type, RefParDerivStepModel derivMode=REFPAR_DERIV_STEP_RELATIVE, const bool hasLimits=true, const bool isFixed=false, const bool isUsed=true, const bool isPeriodic=false, const REAL humanScale=1., REAL period=1.); /// Copy all attributes (limits, flags, etc...) from another RefinablePar object. /// This is useful in RefinableObj copy constructors. Everything is copied but the /// pointer to the value refined, and the pointer to the clock. void CopyAttributes(const RefinablePar&); //@} /// \name Access & change the current value of the parameter //@{ /** of the parameter. Use the The Mutate() and MutateTo() function * to change this value. */ REAL GetValue()const; /** Access to a const pointer to the refined value * * This can be used to identify the parameter */ const REAL* GetPointer()const; /** of the parameter. Use the The Mutate() and MutateTo() function * to change this value. */ void SetValue(const REAL value); /** \brief Current value of parameter, scaled if necessary (for angles) to a * human-understandable value. */ const REAL& GetHumanValue() const; /** \brief Current value of parameter, scaled if necessary (for angles) to a * human-understandable value. */ void SetHumanValue(const REAL&) ; /** \brief Add the given amount to the parameter current value. * * If limit is hit, set to limit. * If the limit is hit \e and the parameter is periodic, shift by period to bring * back to allowed values. *\warning Will throw an exception if the parameter is defined by an equation. */ void Mutate(const REAL mutateValue); /**Change the current value to the given one. * * If the limit is hit, then set to the limit (unless the pameter is periodic, * then shift by the period amount back to allowed values). *\warning Will throw an exception if the parameter is defined by an equation. */ void MutateTo(const REAL newValue); REAL GetSigma()const; REAL GetHumanSigma()const; void SetSigma(const REAL); //@} /// \name General info //@{ /// Get the parameter's name string GetName()const; /// Set the name of the parameter. It should be unique in the RefinableObj. void SetName(const string&); void Print() const; bool IsFixed()const; void SetIsFixed(const bool); bool IsLimited()const; void SetIsLimited(const bool); /// Is the parameter used (if not, it is simply irrelevant in the model) ? bool IsUsed()const; /// Is the parameter used (if not, it is simply irrelevant in the model) ? void SetIsUsed(const bool); bool IsPeriodic()const; void SetIsPeriodic(const bool,REAL period=1); /// Human scale for this parameter : for angles, this is equal to 180/pi. REAL GetHumanScale()const; /// Human scale for this parameter : for angles, this is equal to 180/pi. void SetHumanScale(const REAL); //@} /// \name Min, max values //@{ /// Minimum value allowed (if limited or periodic) REAL GetMin()const; /// Set the Minimum value allowed (if limited) void SetMin(const REAL); ///Get the minimum value allowed (if limited) REAL GetHumanMin()const; ///Set the minimum value allowed (if limited) void SetHumanMin(const REAL); ///Get the maximum value allowed (if limited) REAL GetMax()const; ///Get the maximum value allowed (if limited) void SetMax(const REAL); ///Get the maximum value allowed (if limited) REAL GetHumanMax()const; ///Get the maximum value allowed (if limited) void SetHumanMax(const REAL); ///Get the period (if periodic) REAL GetPeriod()const; ///Set the period value (if periodic) void SetPeriod(const REAL); //@} /// \name Steps during refinement //@{ ///Fixed step to use to compute numerical derivative REAL GetDerivStep()const; ///Fixed step to use to compute numerical derivative void SetDerivStep(const REAL); ///Maximum step to use during Global Optimization algorithms REAL GetGlobalOptimStep()const; ///Maximum step to use during Global Optimization algorithms void SetGlobalOptimStep(const REAL); //@} #if 0 /// \name Equations-In development ! ->do not use or even look. //@{ void SetUseEquation(const bool useItOrNot,const REAL c0=0.); void SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1); void SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1, const REAL c2, const RefinablePar &refpar2); void SetUseEquation(const bool useItOrNot,const REAL c0, const REAL c1, const RefinablePar &refpar1, const REAL c2, const RefinablePar &refpar2, const REAL c3, const RefinablePar &refpar3); //@} #endif /// \name Parameter's Clock //@{ /// \internal /// Assign a clock to this parameter. Any time this parameter is modified, /// the clock will be ticked ! void AssignClock(RefinableObjClock &clock); //@} /// \name Change Limits //@{ /// Change the limits for this object, giving absolute new limits void SetLimitsAbsolute(const REAL min, const REAL max); /// Change the limits for this object, giving relative new limits (eg giving -.1 /// and +.1 will set new limits at the current value + min and current value + max) /// Thus min should logically be <0 and max >0. void SetLimitsRelative(const REAL min, const REAL max); /// Change the limits for this object, proportionnaly to the current value. /// min should be < 1. and max > 1. void SetLimitsProportional(const REAL min, const REAL max); //@} /** \brief XMLOutput to stream in well-formed XML * * this will save the fixed & limited flags, as well as limits * \param name the name to use instead of the RefPar name. */ void XMLOutput(ostream &os,const string &name,int indent=0)const; /** \brief XMLOutput to stream in well-formed XML. * * this will save the fixed & limited flags, as well as limits. * In this function the name used is that of the RefPar. */ void XMLOutput(ostream &os,int indent=0)const; /** \brief XMLInput From stream * */ void XMLInput(istream &is,const XMLCrystTag &tag); private: /// Click the Clock ! to telle the RefinableObj it has been modified. void Click(); ///name of the refinable parameter string mName; /// Pointer to the refinable value REAL *mpValue; /// Hard lower and upper limits. REAL mMin,mMax; /// Does the refinable parameter need limits (min and max) ? bool mHasLimits; /// is the parameter currently fixed ? bool mIsFixed; /// Is the parameter currently used ? bool mIsUsed; /// Is the parameter periodic ? If this is the case, then when using the /// RefinablePar::Mutate() function, if the parameter goes beyond its limits, /// it will be shifted by the value of its period. bool mIsPeriodic; /// Period value (if relevant) REAL mPeriod; /// Step to use for global method search (simulated annealing,...) REAL mGlobalOptimStep; /// Step to use for numerical derivative calculation REAL mDerivStep; /// Model followed for derivation RefParDerivStepModel mRefParDerivStepModel; /// Calculated sigma on value REAL mSigma; /// Scale to be used to display 'human' value. This is for angular parameters: the computer /// stores values in radians, whil the user only understands degrees. So a scale /// factor of 180/pi is necessary. REAL mHumanScale; #if 0 // Parameter defined by equations ? :TODO: ///Is this parameter deined by an equation ? eg: mValue= c0 +c1*par1.Value+... bool mUseEquation; /// Max number of other ref. parameters involved in the equation evaluation static const int mEquationMaxRefPar=10; /// number of other ref. parameters involved in the equation evaluation int mEquationNbRefPar; /// Coefficient Ci used in equation: Value= C0 + C1 * RefPar1 + C2 * RefPar2 +... CrystVector_REAL mEquationCoeff; /// Array of pointers to the RefinablePar used in the equation const RefinablePar *mEquationRefPar[10]; #endif /// Is there a clock associated with this parameter ? If yes, then it must Click() it /// each time it is modified bool mHasAssignedClock; RefinableObjClock* mpClock; #ifdef __WX__CRYST__ public: /// Create a WXFieldRefPar representation of the parameter. WXCrystObjBasic* WXCreate(wxWindow *parent); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); private: WXFieldRefPar * mpWXFieldRefPar; #endif friend class RefinableObj; }; /** Base class for options * */ class RefObjOpt { public: /** Constructor for the option * \param obj: the */ RefObjOpt(); virtual ~RefObjOpt(); void Init(const int nbChoice,const string *name, const string *choiceNames); int GetNbChoice()const; int GetChoice()const; virtual void SetChoice(const int choice); void SetChoice(const string &choiceName); const string& GetName()const; const string& GetClassName()const; const string& GetChoiceName(const int i)const; const RefinableObjClock& GetClock()const; /** \brief XMLOutput to stream in well-formed XML. * * In this function the name used is that of the Option. */ void XMLOutput(ostream &os,int indent=0)const; /** \brief XMLInput From stream * */ void XMLInput(istream &is,const XMLCrystTag &tag); protected: /// Number of different choice possible for this option int mNbChoice; /// Current value int mChoice; /// (short) Name for this option. Should be statically stored in the class /// using the option const string* mpName; /// Names corresponding to each possible value of this option (Human-understandable). /// Should be statically stored in the class using the option. const string* mpChoiceName; /// The clock associated to this option RefinableObjClock mClock; #ifdef __WX__CRYST__ public: WXCrystObjBasic* WXCreate(wxWindow *parent); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); private: WXFieldOption * mpWXFieldOption; #endif }; /** * Class for options of RefinableObj, templated so that we can warn * the object that something has been changed. NOT USED SO FAR. */ template class RefObjOption:public RefObjOpt { public: /** Constructor for the option * \param obj: the */ RefObjOption(T* obj); ~RefObjOption(); void Init(const int nbChoice,const string *name, const string *choiceNames, void (T::*fp)(const int)); virtual void SetChoice(const int choice); protected: private: /// The object which uses this option T* mpObj; /// The pointer to the member function to be used when the choice is changed, to notify /// immediately the object. If null, the value is just recorded and no notification /// is done. void (T::*mfpSetNewValue)(const int); }; /** Object Registry * * This class is used to keep a list of all object of a given class at the global * level, or inside another object. This is primarily aimed for the derivative * of the RefinableObj class but it * can be used for \e any class that has GetName() and GetClassName() function. * This class now uses a vector<> approach from the STL. * * \warning the order of the objects in the registry can change (every time an object * is de-registered). * * \todo (?) create two derived classes with the same interface, one which is a const * registry (the 'client' registry for RefinableObj), and one which has a non-const * access to the registered objects (the 'sub-objects' in RefinableObj). */ template class ObjRegistry { public: ObjRegistry(); ObjRegistry(const string &name); ~ObjRegistry(); /// Register a new object. Already registered objects are skipped. void Register(T &obj); /// De-register an object. void DeRegister(T &obj); /// De-register an object from its name. void DeRegister(const string &objName); /// De-register \e all objects from the list. void DeRegisterAll(); /// Delete all objects in the registry.. Use with caution !! void DeleteAll(); /** Get object #i in the registry. * \internal * Use with caution. The order of the objects * changes as objects are added and removed. */ T& GetObj(const unsigned int i); /** Get object #i in the registry. * \internal * Use with caution. The order of the objects * changes as objects are added and removed. */ const T& GetObj(const unsigned int i)const; /// Get an object from its name in the registry. /// The search starts at the *end* of the registry. T& GetObj(const string &objName); /// Get an object from its name in the registry. /// The search starts at the *end* of the registry. const T& GetObj(const string &objName)const; /// Get an object from its name in the registry. /// The search starts at the *end* of the registry. /// Also check the class of the object. T& GetObj(const string &objName, const string& className); /// Get an object from its name in the registry. /// The search starts at the *end* of the registry. /// Also check the class of the object. const T& GetObj(const string &objName, const string& className)const; /// Get the index of an object in the registry, from its name /// Warning: it can change if an object is removed from the registry long GetNb()const; void Print()const; void SetName(const string &); const string& GetName()const; /// Find the number of an object in the registry from its name (slow !) /// The search starts at the *end* of the registry. long Find(const string &objName)const; /// Find the number of an object in the registry from its name (slow !) /// The search starts at the *end* of the registry. /// Also check the class of the object (inheritance...). /// use nothrow=true to avoid having an exception thrown if no object /// is found (instead the index returned will be -1) long Find(const string &objName, const string& className, const bool nothrow=false)const; /// Find the number of an object in the registry /// The search starts at the *end* of the registry. long Find(const T &obj)const; /// Find the number of an object in the registry /// The search starts at the *end* of the registry. long Find(const T *pobj)const; /// Last time an object was added or removed from the registry const RefinableObjClock& GetRegistryClock()const; /** Enable the UI automatic update, so that objects in the registry are * automatically added to the UI. */ void AutoUpdateUI(const bool autoup=true); /** Manually update the UI, making sure all objects in the registry are displayed * This is useful when the automatic adding of objects has been disabled. * */ void UpdateUI(); /** STL access to object size */ std::size_t size() const; /** low-level access to the underlying vector begin(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. * \warning: the iterator can be invalidated if the registry is modified */ typename vector::const_iterator begin() const; /** low-level access to the underlying vector end(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. * \warning: the iterator can be invalidated if the registry is modified */ typename vector::const_iterator end() const; /** low-level access to the underlying list begin(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. * This iterator should remain valid even if an object is removed. */ typename list::const_iterator list_begin() const; /** low-level access to the underlying list end(). * Const access as we do not want the number and order of objects to change, * but the objects themselves can be modified. * This iterator should remain valid even if an object is removed. */ typename list::const_iterator list_end() const; private: /// The registry of objects vector mvpRegistry; /// Another view of the registry of objects - this time as a std::list, which /// will not be invalidated if one object is deleted list mvpRegistryList; /// Name of this registry string mName; /// Last time an object was added or removed RefinableObjClock mListClock; /** Enable the user interface update. * If true, any time an object is added, it will be added to the user interface (wx...). * If objects have not been added to the user interface, this can be done asynchronously * using UpdateUI() which will go through the list of objects and add those not yet displayed. * * This does not affect the removal of objects. */ bool mAutoUpdateUI; #ifdef __WX__CRYST__ public: WXRegistry* WXCreate(wxWindow *parent); void WXDelete(); void WXNotifyDelete(); private: WXRegistry * mpWXRegistry; #endif }; /** \brief Generic Refinable Object * * This is basically a list of refinable parameters, with other basic common properties * such as a name,. etc... * This allows optimization/refinement algorithms to access the parameters without * knowing what the object really is. * * \todo Define more clearly which operations are recursive (ie also modify sub-objects). */ class RefinableObj { public: /// Constructor RefinableObj(); /// Constructor. Using internalUseOnly=true will avoid registering the /// the object to any registry, and thus (for example) no display will be created, /// nor will this object be automatically be saved. RefinableObj(const bool internalUseOnly); /// Defined not implemented... Should never be called /// (copying the refinable parameters would allow you to modify the /// input object). /// Use the default constructor and RefinableObj::AddPar(RefinableObj&) instead. RefinableObj(const RefinableObj &old); /// Destructor virtual ~RefinableObj(); /// Name for this class ("RefinableObj", "Crystal",...). This is only useful /// to distinguish different classes when picking up objects from the /// RefinableObj Global Registry virtual const string& GetClassName() const; /// Name of the object virtual const string& GetName() const; /// Name of the object virtual void SetName(const string &name); /** Defined not implemented... Should never be called */ void operator=(const RefinableObj &old); /// Find which parameters are used and \b not fixed, for a refinement /optimization. /// This \b must be called before any refinement... void PrepareForRefinement() const; /// Fix All parameters void FixAllPar(); /// UnFix All parameters void UnFixAllPar(); /// Fix/un-fix one parameter from its #. void SetParIsFixed(const long parIndex,const bool fix); /// Fix/un-fix one parameter from its name. void SetParIsFixed(const string& parName,const bool fix); /// Fix/un-fix one family of parameters void SetParIsFixed(const RefParType *type,const bool fix); /// Set whether a parameter is used void SetParIsUsed(const string& parName,const bool use); /// Set whether a family of parameters is used void SetParIsUsed(const RefParType *type,const bool use); /// Total number of refinable parameter in the object. Note that some /// may be actually fixed or even not used !! /// For refinement use PrepareForRefinement(), NbRefParNotFixed(), and /// ParNotFixed(i) long GetNbPar()const; /// Total number of non-fixed parameters. Is initialized by PrepareForRefinement() long GetNbParNotFixed()const; /// Access all parameters in the order they were inputted RefinablePar& GetPar(const long i); /// Access all parameters in the order they were inputted const RefinablePar& GetPar(const long i) const; /// Access all parameters from their name RefinablePar& GetPar(const string & name); ///Access all parameters from their name const RefinablePar& GetPar(const string & name) const; /// Access parameter from its adress RefinablePar& GetPar(const REAL*); /// Access parameter from its adress const RefinablePar& GetPar(const REAL*) const; /// Access all parameters in the order they were inputted, /// skipping fixed parameters. Must call PrepareForRefinement() before ! RefinablePar& GetParNotFixed(const long i); /// Access all parameters in the order they were inputed, /// skipping fixed parameters. Must call PrepareForRefinement() before ! const RefinablePar& GetParNotFixed(const long i)const; /** Add a refinable parameter. The parameter is copied, so * it need only be allocated temporarily. * * \deprecated Use the next function, which supplies the parameter as * a pointer, and avoids a useless copy. * \note: if a parameter is added and its name is already used by another, * its name will be automatically appended with an ~ */ void AddPar(const RefinablePar &newRefPar); /** Add a refinable parameter. The parameter is \e not copied, so * it should be allocated in the heap. * * \note: if a parameter is added and its name is already used by another, * its name will be automatically appended with an ~ */ void AddPar(RefinablePar *newRefPar); /** Add all the parameters in another RefinableObj. Parameters * are \not copied, so they should be allocated in the heap. * * \warning If a copy of another RefinableObj parameter list is made, * such as in the OptimizationObj class, make sure that upon deletion * of this object the parameters will not be destroyed. To do this * use RefinableObj::SetDeleteRefParInDestructor(false). * * \param copyParam: if false (default), then parameters are not copied * from the object but just referenced. Use RefinableObj::SetDeleteRefParInDestructor(false) * accordingly. If true, then the parameters are copied, so that any * modification to the fixed/limited/used attributes do not affect * the original parameter. Only the value and the parameter's clock * can then be modified by the copied parameter * * \note: if a parameter is added and its name is already used by another, * its name will be automatically appended with an ~ */ void AddPar(RefinableObj &newRefParList, const bool copyParam=false); /** Remove a refinable parameter. * * This returns an iterator to the next parameter in the vector. */ vector::iterator RemovePar(RefinablePar *refPar); virtual void Print() const; /** \brief Save the current set of refined values in a new set. * * \param name : the name associated to this set of values. Names should be unique. * \return an number identifying the set of saved values. * * \warning: there is no limit to the number of parameters sets, so try to * release them when you don't need them. */ unsigned long CreateParamSet(const string name="") const; /** \brief Erase the param set with the given id, releasing memory. */ void ClearParamSet(const unsigned long id)const; /** \brief Save the current set of refined values over a previously-created set *of saved values. * \param id the number identifying the set of saved values. */ void SaveParamSet(const unsigned long id)const; /** \brief Restore a saved set of values. * * \param id : the number identifying the set. * \warning this only affects parameters which are used. Others * remain unchanged. Parameters which are fixed are also restored, * although generally they will not be altered. */ void RestoreParamSet(const unsigned long id); /** \brief Access one save refpar set * * \param setId : the number identifying the set. */ const CrystVector_REAL& GetParamSet(const unsigned long setId)const; /** \brief Access one save refpar set * * \param setId : the number identifying the set. */ CrystVector_REAL& GetParamSet(const unsigned long setId); /** \brief Access the (human) value of one refined parameter in a saved set of parameters * * \internal * \param setId : the number identifying the set. * \param parNumber : the number identifying the parameter in the list of refined * parameters * \return if parNumber=5 and setId=37, then the returned value will be the value (scaled *if it is an angle) value of the 5th not-fixed parameter in the saved set #37. */ REAL GetParamSet_ParNotFixedHumanValue(const unsigned long setId,const long parNumber)const; /** \brief Erase all saved refpar sets * */ const void EraseAllParamSet(); /** \brief Get the name associated to a refpar set * * \param setId : the number identifying the set. */ const string& GetParamSetName(const unsigned long setId)const; /// Change the limits for a given parameter, giving absolute new limits void SetLimitsAbsolute(const string &parName, const REAL min, const REAL max); /// Change the limits for a category of parameters, giving absolute new limits void SetLimitsAbsolute(const RefParType *type, const REAL min, const REAL max); /// Change the limits for a given parameter, giving relative new limits (eg giving -.1 /// and +.1 will set new limits at the current value + min and current value + max) /// Thus min should logically be <0 and max >0. void SetLimitsRelative(const string &parName, const REAL min, const REAL max); /// Change the limits for a category of parameters, giving relative new limits /// (eg giving -.1 and +.1 will set new limits at the current value + min and /// current value + max). Thus min should logically be <0 and max >0. void SetLimitsRelative(const RefParType *type, const REAL min, const REAL max); /// Change the limits for a given parameter, proportionnaly to the current value. /// min should be < 1. and max > 1. void SetLimitsProportional(const string &parName, const REAL min, const REAL max); /// Change the limits for a category of parameters, proportionnaly to their current value. /// min should be < 1. and max > 1. void SetLimitsProportional(const RefParType *type, const REAL min, const REAL max); ///Change the maximum step to use during Global Optimization algorithms void SetGlobalOptimStep(const RefParType *type, const REAL step); /// Access to the registry of RefinableObj used by this object ObjRegistry& GetSubObjRegistry(); /// Access to the registry of RefinableObj used by this object const ObjRegistry& GetSubObjRegistry()const; /// Register a new object using this object /// \todo : the clients should be const, but are not... This need to be fixed... virtual void RegisterClient(RefinableObj &)const; /// Deregister an object (which not any more) using this object virtual void DeRegisterClient(RefinableObj &)const; /// Get the list of clients virtual const ObjRegistry& GetClientRegistry()const; /// Get the list of clients virtual ObjRegistry& GetClientRegistry(); /// Is the object being refined ? (Can be refined by one algorithm at a time only.) bool IsBeingRefined()const; /** This should be called by any optimization class at the begining of an optimization * * This will also check that everything is ready, eg call the RefinableObj::Prepare() * function. This also affects all sub-objects. * \note this may be called several time for some objects which are used by several * other objects, or for nested optimizations (e.g. least-squares optimizations * inside a global one). * * \note EndOptimization() must be called at the end of the optimization, the same * number of time BeginOptimization() was called ! * * \param allowApproximations: if true, then the object can use faster * but less precise functions during the optimization. This is useful for * global optimization not using derivatives. * \param enableRestraints: \deprecated if true, then restrained parameters will be allowed * to go beyond theur hard limits. This implies that the algorithm will take * into account the cost (penalty) related to the restraints. Objects which do not * use restraints will simply ignore this. WARNING: this parameter may be removed * with the new likelihood scheme. */ virtual void BeginOptimization(const bool allowApproximations=false, const bool enableRestraints=false); /** This should be called by any optimization class at the end of an optimization * * This also affects all sub-objects. * \note this may be called several time for some objects which are used by several * other objects. */ virtual void EndOptimization(); /** Enable or disable numerical approximations. This can be used for global optimization * to get faster calculations. Depending on the type of object, this may do something * or not (it does not do anything in a base RefinableObj, except calling this function * for all sub-objects). * * \note Currently there is no mApproximationFlag in the base class, but maybe there should... * * Also see: */ virtual void SetApproximationFlag(const bool allow); /// Randomize Configuration (before a global optimization). This /// Affects only parameters which are limited and not fixed. /// The randomization also affects all sub-objects (recursive). virtual void RandomizeConfiguration(); /** Make a random move of the current configuration. * * This is for global optimization algorithms. the moves for each * parameter are less than their global optimization step, multiplied * by the mutation amplitude. * * \warning: this makes a random move for the parameter declared * for this object, and it is the duty of the object to decide whether * the included objects should be moved and how. (eg an algorithm should * only call for a move with the top object, and this object decides how * he and his sub-objects moves). By default (RefinableObj implementation) * all included objects are moved recursively. * * RefinableObj:: * \param mutationAmplitude: multiplier for the maximum move amplitude, * for all parameters * \param type: restrain the change exclusively to parameters of a given * type (same type or descendant from this RefParType). */ virtual void GlobalOptRandomMove(const REAL mutationAmplitude, const RefParType *type=gpRefParTypeObjCryst); /** Raise a flag, to be sure not to make a random change more than once * in each RefinableObj. This calls recursively all sub-objects. * * This is necessary since one object may be included in several others. * This must be called before making a random configuration change on * a list of objects. */ void BeginGlobalOptRandomMove(); // Likelihood /** Get -log(likelihood) of the current configuration for the object. * * * By default (no likelihood evaluation available), this is equal to 0. * * This call should not be recursive, it is the task of the algorithm to * get the sum of likelihoods for all objects invlolved. * * \note contrary to the old "Cost Function" approach, with log(Likelihood) * there is no 'choice' of cost function, so that it is the task of the * object to give the optimized likelihood (possibly with user options). */ virtual REAL GetLogLikelihood()const; /* Get log(likelihood) and all its first derivative versus a list of parameters. * * \return: a map, with a RefinablePar pointer as key, and as value the corresponding * derivative. Note that the value of the map for the NULL key is the current value * for the log(likelihood), which is also returned. The map will include derivatives * only for parameters which have been supplied in vPar - but if a parameter * is listed in vPar and has a null derivative, it may be missing in the returned map. * * \warning: currently in development, to provide faster, analytic derivatives * * \note:ideally, this function should be const - but since numerical derivatives * may be used before all analytical formulas are entered, a non-const version is * required. * \todo */ //virtual std::map& GetLogLikelihood_FullDeriv(std::set &vPar); //LSQ functions /// Number of LSQ functions virtual unsigned int GetNbLSQFunction()const; // Get a Cost function name from its id#. //virtual const string& GetLSQFunctionName(const unsigned int)const; // Get the (short) description of a cost function //virtual const string& GetLSQFunctionDescription(const unsigned int)const; /// Get the current calculated value for the LSQ function virtual const CrystVector_REAL& GetLSQCalc(const unsigned int) const; /// Get the observed values for the LSQ function virtual const CrystVector_REAL& GetLSQObs(const unsigned int) const; /// Get the weight values for the LSQ function virtual const CrystVector_REAL& GetLSQWeight(const unsigned int) const; /** Get the first derivative values for the LSQ function, for a given * parameter. Note that the default method in the base RefinableObj * class is to use numerical derivatives, so it should be * overridden for better precision. * * \todo This should be a const method, and the given RefPar should be const too... */ virtual const CrystVector_REAL& GetLSQDeriv(const unsigned int, RefinablePar&); /** Get the first derivative for the LSQ function for each parameter supplied * in a list. * * \return: a map, with a RefinablePar pointer as key, and as value the corresponding * derivative vector. Note that the value of the map for the NULL key is the current value * for the LSQ function, which is also returned. The map will include derivatives * only for parameters which have been supplied in vPar - but if a parameter * is listed in vPar and has a null derivative, the returned vecor will be empty. * * \warning: currently in development, to provide faster, analytic derivatives * * \note:ideally, this function should be const - but since numerical derivatives * may be used before all analytical formulas are entered, a non-const version is * required. * \todo */ virtual std::map & GetLSQ_FullDeriv(const unsigned int,std::set &vPar); /// Re-init the list of refinable parameters, removing all parameters. /// This does \e not delete the RefinablePar if /// RefinableObj::mDeleteRefParInDestructor is false void ResetParList(); /** \brief Output to stream in well-formed XML * * \todo Use inheritance.. as for XMLInputTag()... */ virtual void XMLOutput(ostream &os,int indent=0)const; /** \brief Input From stream * * \todo Add an bool XMLInputTag(is,tag) function to recognize all the tags * from the stream. So that each inherited class can use the XMLInputTag function * from its parent (ie take advantage of inheritance). The children class * would first try to interpret the tag, then if unsuccessful would pass it to * its parent (thus allowing overloading), etc... */ virtual void XMLInput(istream &is,const XMLCrystTag &tag); //virtual void XMLInputOld(istream &is,const IOCrystTag &tag); /// If there is an interface, this should be automatically be called each /// time there is a 'new, significant' configuration to report. virtual void UpdateDisplay()const; //Options /// Access to the options list ObjRegistry& GetOptionList(); /// Number of Options for this object unsigned int GetNbOption()const; /// Access to the options RefObjOpt& GetOption(const unsigned int i); /// Access to the options by name RefObjOpt& GetOption(const string & name); /// const access to the options const RefObjOpt& GetOption(const unsigned int i)const; /// const access to the options by name const RefObjOpt& GetOption(const string & name)const; // Genetic /** \brief Get the gene group assigned to each parameter. * * Each parameter (a \e gene in terms of genetic algorithms) * can be assigned to a gene group. Thus when mating two configurations, * genes will be exchanged by groups. By default (in the base RefinabeObj class), * each parameter is alone in its group. Derived classes can group genes * for a better s** life. * * The number identifying a gene group only has a meaning in a given * object. It can also change on subsequent calls, and thus is not unique. * * \param obj the \RefinableObj, supplied by an algorithm class (OptimizationObj,..), * which contains a list of parameters, some of which (but possibly all or none) * are parameters belonging to this object. * \param groupIndex a vector of unsigned integers, one for each parameter in the * input object, giving an unsigned integer value as gene group index. * At the beginning this vector should contain only zeros (no group assigned). * \param firstGroup this is the number of groups which have already been assigned, * plus one. The gene groups returned by this object will start from this * value, and increment \b firstGroup for each gene group used, so that * different RefinableObj cannot share a gene group. * \note this function is not optimized, and should only be called at the beginning * of a refinement. */ virtual void GetGeneGroup(const RefinableObj &obj, CrystVector_uint & groupIndex, unsigned int &firstGroup) const; /** Set this object not to delete its list of parameters when destroyed. * * This is used for the RefinableObj in algorithms objects (OptimizationObj), * which only hold copies of parameters from the refined objects. */ void SetDeleteRefParInDestructor(const bool b); /** What was the last time a RefinablePar was added/removed ? * */ const RefinableObjClock& GetRefParListClock()const; // Restraints /** Get the restraint cost (overall penalty of all restraints) * * By default this returns 0, so this \e must be overloaded by any * object which actually uses restraint. * \note Instead, we could return by default the sum of the restraints, * but this is dangerous since we \e want to have derived objects fully * responsible for handling restraints. */ virtual REAL GetRestraintCost()const; /** Add a new restraint * * This returns an iterator pointing to the next Restraint in the vector. */ void AddRestraint(Restraint *pNewRestraint); /** Remove a restraint from the list of known restraints. This does not * delete the Restraint object. */ vector::iterator RemoveRestraint(Restraint *pRestraint); /** During a global optimization, tells the object that the current config is * the latest "best" config. * * This can be used by the object to make more intellingent random moves (use with * caution: highly experimental !). */ virtual void TagNewBestConfig()const; /// This clocks records _any_ change in the object. See refinableObj::mClockMaster const RefinableObjClock& GetClockMaster()const; /// Access to the integer address of this object, for unique identification from python size_t int_ptr() const; protected: /// Find a refinable parameter with a given name long FindPar(const string &name) const; /// Find a refinable parameter from the adress of its value long FindPar(const REAL*) const; /// \internal Add an object in the registry of used objects. void AddSubRefObj(RefinableObj &); /// \internal Remove an object in the registry of used objects. void RemoveSubRefObj(RefinableObj &); /// \internal Add an option for this parameter void AddOption(RefObjOpt *opt); /// \internal Prepare everything (if necessary) for an optimization/calculation. virtual void Prepare(); /// Find a parameter set with a given id (and check if it is there) map >::iterator FindParamSet(unsigned long id)const; ///Name for this RefinableObject. Should be unique, at least in the same scope.+ string mName; // Parameters /// Vector of pointers to the refinable parameters vector mvpRefPar; // Restraints /// Vector of pointers to the restraints for this object. This excludes /// all RefinablePar declared in RefinableObj::mpRefPar, which also /// are Restraint. vector mvpRestraint; //Saved sets of parameters /// Map of (index,pointers to arrays) used to save sets of values for all parameters. /// Currently there is no limit to the number of saved sets. /// /// This is mutable since creating/storing a param set does not affect the /// 'real' part of the object. mutable map > mvpSavedValuesSet; // Used during refinements, initialized by PrepareForRefinement() /// Total of not-fixed parameters mutable long mNbRefParNotFixed; /// Index of not-fixed parameters mutable CrystVector_long mRefparNotFixedIndex; /// Is the object being refined or optimized ? /// if mOptimizationDepth=0, no optimization is taking place. /// mOptimizationDepth>0 indicates the object is being optimized. Values /// larger than 1 indicate that several level of optimizations are taking place, /// e.g. one least-square optimization during a global optimization, etc... int mOptimizationDepth; /// Registry of RefinableObject needed for this object (owned by this object or not) ObjRegistry mSubObjRegistry; /// Registry of RefinableObject using this object. /// This is mutable so that client can modify it (kludge?) mutable ObjRegistry mClientObjRegistry; // Options for this object /// List of options for this object. Note that these are just references, /// to options allocated by the object, to have a simple global access to /// all options ObjRegistry mOptionRegistry; /// If true (the default), then all RefinablePar will be deleted when the /// the object is deleted. The opposite option (false) should only be used /// in RefinableObj holding 'copies' of other objects, such as in algorithms. bool mDeleteRefParInDestructor; /// Last time the RefinableParList was modified (a parameter added or removed). RefinableObjClock mRefParListClock; /// \internal This true is false if RefinableObj::GlobalOptRandomMove() has been called /// since RefinableObj::BeginGlobalOptRandomMove() was called. bool mRandomMoveIsDone; /// Temporary array used to return derivative values of the LSQ function for given /// parameters. mutable CrystVector_REAL mLSQDeriv; /// Temporary map to return the derivative of the LSQ function versus a list of parameters /// /// Several LSQ functions can be stored. /// /// \todo In development mutable std::map< unsigned int,std::map > mLSQ_FullDeriv; // Temporary map to return the derivative of log(likelihood) versus a list of parameters // // \todo In development //mutable std::map mLogLikelihood_FullDeriv; /// Master clock, which is changed whenever the object has been altered. /// It should be parent to all clocks recording changes in derived classes. RefinableObjClock mClockMaster; #ifdef __WX__CRYST__ public: /// Create a WXCrystObj for this object. Only a generic WXCrystObj pointer is kept. virtual WXCrystObjBasic* WXCreate(wxWindow*); WXCrystObjBasic* WXGet(); void WXDelete(); void WXNotifyDelete(); protected: WXCrystObjBasic *mpWXCrystObj; #endif }; /// Get the last time any RefinablePar was added in a recursive list of objects. void GetRefParListClockRecursive(ObjRegistry ®,RefinableObjClock &clock); /// Register a new object in a registry, and recursively /// include all included (sub)objects. template void RefObjRegisterRecursive(T &obj,ObjRegistry ®); /// Get the last time any object was added in the recursive list of objects. void GetSubRefObjListClockRecursive(ObjRegistry ®,RefinableObjClock &clock); /// Global Registry for all RefinableObj extern ObjRegistry gRefinableObjRegistry; /// This is a special registry for 'top' object for an optimization. In /// the ObjCryst++ class, this currently includes Crystal, PowderPattern and /// DiffractionDataSingleCrystal. extern ObjRegistry gTopRefinableObjRegistry; }//namespace #endif// _VFN_REFINABLE_OBJ_H_ libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/Simplex.cpp000066400000000000000000000157361417150057700237700ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2000-2002 Vincent Favre-Nicolin vincefn@users.sourceforge.net 2000-2001 University of Geneva (Switzerland) 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Simplex.cpp * source file for Conjugate Gradient Algorithm object * */ #include "ObjCryst/RefinableObj/Simplex.h" #include "ObjCryst/Quirks/VFNStreamFormat.h" namespace ObjCryst { SimplexObj::SimplexObj(const string name): OptimizationObj(name) { } void SimplexObj::Optimize(long &nbSteps,const bool silent,const REAL finalcost, const REAL maxTime) { VFN_DEBUG_ENTRY("SimplexObj::Optimize()",10) for(int i=0;iPrepareRefParList(); const unsigned long n=mRefParList.GetNbParNotFixed(); // Create the n+1 set of parameters (n+1 vertices for the initial simplex) // To obtain the n new vertices we just move from the starting point // by the amount of the declared global optimization step. CrystVector_long vIndex(n+1); vIndex(0)=mRefParList.CreateParamSet(); CrystVector_REAL vLLK(n+1); vLLK(0)=this->GetLogLikelihood(); for(unsigned long i=0;iGetLogLikelihood(); mRefParList.RestoreParamSet(vIndex(0)); } unsigned long best=0,worst=0,nextworst=0; for(;nbSteps>=0;--nbSteps) { // determine best, worst and next worst points if(vLLK(0)>vLLK(1)){worst=0;nextworst=1;} else{worst=1;nextworst=0;} for(unsigned long i=1;i<=n;i++) { if(vLLK(i)<=vLLK(best)) best =i; if(vLLK(i)>vLLK(worst)) { nextworst=worst; worst=i; } else if((vLLK(i)>vLLK(nextworst)) && (i!=worst)) nextworst=i; } { CrystVector_REAL center(n); center = 0.0; for(unsigned long i=0;i<=n;i++) { if(i==worst) continue; center += mRefParList.GetParamSet(vIndex(i)); } center /= (REAL)n; CrystVector_REAL worstdiff; worstdiff=mRefParList.GetParamSet(vIndex(worst)); worstdiff-=center; for(unsigned long i=0;iOptimize(nbSteps,silent,finalcost,maxTime); if(!silent) cout <<"SimplexObj::MultiRunOptimize: Finished Run#"<GetLogLikelihood(); //cout<<"New,f="<ReadValue();} void Tracker::Clear() { mvValues.clear(); } const std::map& Tracker::GetValues()const{return mvValues;} std::map& Tracker::GetValues(){return mvValues;} //////////////////////////////////////////////////////////////////////// // // MainTracker // //////////////////////////////////////////////////////////////////////// MainTracker::MainTracker() { #ifdef __WX__CRYST__ mpWXTrackerGraph=0; #endif } MainTracker::~MainTracker() { #ifdef __WX__CRYST__ this->WXDelete(); #endif this->ClearTrackers(); } void MainTracker::AddTracker(Tracker *t) { mvpTracker.insert(t); mClockTrackerList.Click(); this->UpdateDisplay(); } void MainTracker::AppendValues(const long nb) { for(std::set::iterator pos=mvpTracker.begin(); pos!=mvpTracker.end();++pos) (*pos)->AppendValue(nb); mClockValues.Click(); } void MainTracker::ClearTrackers() { std::set::iterator pos; for(pos=mvpTracker.begin();pos!=mvpTracker.end();++pos) delete *pos; mvpTracker.clear(); mClockTrackerList.Click(); this->UpdateDisplay(); } void MainTracker::ClearValues() { std::set::iterator pos; for(pos=mvpTracker.begin();pos!=mvpTracker.end();++pos) (*pos)->Clear(); mClockValues.Click(); this->UpdateDisplay(); } void MainTracker::SaveAll(std::ostream &os)const { std::set::const_iterator posT,posT0; os<<"#Trial "; for(posT=mvpTracker.begin();posT!=mvpTracker.end();++posT) os<<(*posT)->GetName()<<" "; os<::const_iterator pos0,pos; for(pos0=(*posT0)->GetValues().begin();pos0!=(*posT0)->GetValues().end();++pos0) { const long k=pos0->first; os<GetValues().find(k); if(pos==(*posT)->GetValues().end()) os << -1.0 <<" "; else os << pos->second <<" "; } os< &MainTracker::GetTrackerList()const { return mvpTracker; } void MainTracker::UpdateDisplay()const { #ifdef __WX__CRYST__ if(0!=mpWXTrackerGraph)mpWXTrackerGraph->UpdateDisplay(); #endif } const RefinableObjClock& MainTracker::GetClockTrackerList()const{return mClockTrackerList;} const RefinableObjClock& MainTracker::GetClockValues()const{ return mClockValues;} #ifdef __WX__CRYST__ WXTrackerGraph* MainTracker::WXCreate(wxFrame *frame) { if(0==mpWXTrackerGraph) mpWXTrackerGraph=new WXTrackerGraph(frame,this); return mpWXTrackerGraph; } WXTrackerGraph* MainTracker::WXGet(){return mpWXTrackerGraph;} void MainTracker::WXDelete() { if(0!=mpWXTrackerGraph) { delete mpWXTrackerGraph; mpWXTrackerGraph=0; } } void MainTracker::WXNotifyDelete() { mpWXTrackerGraph=0; } #endif }//namespace libobjcryst-2021.1.2+ds1/src/ObjCryst/RefinableObj/Tracker.h000066400000000000000000000066031417150057700234000ustar00rootroot00000000000000/* ObjCryst++ Object-Oriented Crystallographic Library (c) 2005- Vincent Favre-Nicolin vincefn@users.sourceforge.net 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * header file ObjCryst++ Tracker class * */ #ifndef _REFINABLEOBJ_TRACKER_H_ #define _REFINABLEOBJ_TRACKER_H_ #include #include #include #include "ObjCryst/RefinableObj/RefinableObj.h" #ifdef __WX__CRYST__ namespace ObjCryst { class MainTracker; class Tracker; } #include "ObjCryst/wxCryst/wxTrackerGraph.h" #endif namespace ObjCryst { /** A class to track the variation of parameters as a function * of a number of cycles/trials. * * This is an abstract base class. */ class Tracker { public: Tracker(const std::string &name); virtual ~Tracker(); const std::string& GetName()const; void AppendValue(const long trial); /// Removes all stored values void Clear(); const std::map& GetValues() const; std::map& GetValues(); protected: virtual REAL ReadValue()=0; std::map mvValues; std::string mName; }; /** A class to hold all trackers * * All trackers need not have the same */ class MainTracker { public: MainTracker(); ~MainTracker(); void AddTracker(Tracker *t); void AppendValues(const long trial); /// Removes all Trackers void ClearTrackers(); /// Removes all stored values void ClearValues(); /// Will save to a single file if all recorded trial numbers are the same /// Otherwise ? void SaveAll(std::ostream &out)const; const std::set &GetTrackerList()const; /// Update display, if any void UpdateDisplay()const; /// Get last time a tracker was added const RefinableObjClock& GetClockTrackerList()const; /// Get last time values were whanged const RefinableObjClock& GetClockValues()const; private: std::set mvpTracker; /// Last time a tracker was added RefinableObjClock mClockTrackerList; /// Last time values were whanged RefinableObjClock mClockValues; #ifdef __WX__CRYST__ public: WXTrackerGraph* WXCreate(wxFrame*); WXTrackerGraph* WXGet(); void WXDelete(); void WXNotifyDelete(); protected: WXTrackerGraph *mpWXTrackerGraph; #endif }; /** Tracker for objects (RefinableObj, Crystal, PowderPattern, RefPar,...) * */ template class TrackerObject:public Tracker { public: TrackerObject(const std::string &name, const T&obj, REAL (T::*f)() const): Tracker(name),mpObj(&obj),mfp(f) {} private: const T *mpObj; REAL (T::*mfp)() const; REAL ReadValue(){return (mpObj->*mfp)();} }; }//namespace #endif libobjcryst-2021.1.2+ds1/src/ObjCryst/license.txt000066400000000000000000000354511417150057700215000ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS libobjcryst-2021.1.2+ds1/src/ObjCryst/version.cpp000066400000000000000000000025001417150057700214730ustar00rootroot00000000000000/***************************************************************************** * * libobjcryst Complex Modeling Initiative * (c) 2015 Brookhaven Science Associates, * Brookhaven National Laboratory. * All rights reserved. * * File coded by: Pavol Juhas * * See AUTHORS.txt for a list of people who contributed. * See LICENSE.txt for license information. * ****************************************************************************** * * Definitions for the libobjcryst_version_info constants. * *****************************************************************************/ #include "version.h" const long long libobjcryst_version_info::version = LIBOBJCRYST_VERSION; const char* libobjcryst_version_info::version_str = LIBOBJCRYST_VERSION_STR; const int libobjcryst_version_info::major = LIBOBJCRYST_VERSION_MAJOR; const int libobjcryst_version_info::minor = LIBOBJCRYST_VERSION_MINOR; const int libobjcryst_version_info::micro = LIBOBJCRYST_VERSION_MICRO; const int libobjcryst_version_info::patch = LIBOBJCRYST_VERSION_PATCH; const char* libobjcryst_version_info::date = LIBOBJCRYST_VERSION_DATE; const char* libobjcryst_version_info::git_commit = LIBOBJCRYST_GIT_COMMIT; const char* libobjcryst_version_info::git_sha = libobjcryst_version_info::git_commit; // End of file libobjcryst-2021.1.2+ds1/src/ObjCryst/version.tpl000066400000000000000000000060011417150057700215100ustar00rootroot00000000000000/***************************************************************************** * * libobjcryst Complex Modeling Initiative * (c) 2015 Brookhaven Science Associates, * Brookhaven National Laboratory. * All rights reserved. * * File coded by: Pavol Juhas * * See AUTHORS.txt for a list of people who contributed. * See LICENSE.txt for license information. * ****************************************************************************** * * Macro definitions for * LIBOBJCRYST_VERSION, * LIBOBJCRYST_VERSION_MAJOR, * LIBOBJCRYST_VERSION_MINOR, * LIBOBJCRYST_VERSION_MICRO, * LIBOBJCRYST_VERSION_PATCH, * LIBOBJCRYST_VERSION_STR, * LIBOBJCRYST_VERSION_DATE * LIBOBJCRYST_GIT_COMMIT * * Declaration of libobjcryst_version_info struct for version data resolved * at runtime. * *****************************************************************************/ #ifndef LIBOBJCRYST_VERSION_HPP_INCLUDED #define LIBOBJCRYST_VERSION_HPP_INCLUDED #define LIBOBJCRYST_VERSION_MAJOR ${LIBOBJCRYST_VERSION_MAJOR} #define LIBOBJCRYST_VERSION_MINOR ${LIBOBJCRYST_VERSION_MINOR} #define LIBOBJCRYST_VERSION_MICRO ${LIBOBJCRYST_VERSION_MICRO} // number of git commits since the last release tag #define LIBOBJCRYST_VERSION_PATCH ${LIBOBJCRYST_VERSION_PATCH} // LIBOBJCRYST_VERSION is an integer representation of a full version: // // LIBOBJCRYST_VERSION / 1000000000 is the major version number // LIBOBJCRYST_VERSION / 1000000 % 1000 is the minor version number // LIBOBJCRYST_VERSION / 1000 % 1000 is the micro version number // LIBOBJCRYST_VERSION % 500 is the patch number // // alpha and beta releases have smaller LIBOBJCRYST_VERSION than // a finalized release. Numerical comparison of LIBOBJCRYST_VERSION // values from two pre-releases may be inaccurate. #define LIBOBJCRYST_VERSION ${LIBOBJCRYST_VERSION} // LIBOBJCRYST_VERSION_STR is a string form of LIBOBJCRYST_VERSION #define LIBOBJCRYST_VERSION_STR "${LIBOBJCRYST_VERSION_STR}" // LIBOBJCRYST_VERSION_DATE is the commit date of LIBOBJCRYST_VERSION #define LIBOBJCRYST_VERSION_DATE "${LIBOBJCRYST_VERSION_DATE}" // LIBOBJCRYST_GIT_COMMIT is a full git commit hash for the current version #define LIBOBJCRYST_GIT_COMMIT "${LIBOBJCRYST_GIT_COMMIT}" // LIBOBJCRYST_GIT_SHA is deprecated. Use LIBOBJCRYST_GIT_COMMIT instead. #define LIBOBJCRYST_GIT_SHA \ _Pragma ("GCC warning \"macro LIBOBJCRYST_GIT_SHA is deprecated\"") \ LIBOBJCRYST_GIT_COMMIT // libobjcryst_version_info will hold runtime version data, which may be // different from client compile-time values. struct libobjcryst_version_info { static const long long version; static const char* version_str; static const int major; static const int minor; static const int micro; static const int patch; static const char* date; static const char* git_commit; // git_sha is deprecated. Use git_commit instead. static const char* git_sha __attribute__ ((deprecated)); }; #endif // LIBOBJCRYST_VERSION_HPP_INCLUDED // vim:ft=cpp: libobjcryst-2021.1.2+ds1/src/SConscript000066400000000000000000000071241417150057700175640ustar00rootroot00000000000000import os Import('env') # Build environment configuration -------------------------------------------- # Insert LIBRARY_PATH explicitly because some compilers # ignore it in the system environment. env.PrependUnique(LIBPATH=env['ENV'].get('LIBRARY_PATH', '').split(':')) # Use Intel C++ compiler if requested by the user. icpc = None if env['tool'] == 'intelc': icpc = env.WhereIs('icpc') if not icpc: print("Cannot find the Intel C/C++ compiler 'icpc'.") Exit(1) env.Tool('intelc', topdir=icpc[:icpc.rfind('/bin')]) fast_linkflags = ['-s'] # Platform specific intricacies. if env['PLATFORM'] == 'darwin': env.Append(SHLINKFLAGS=['-install_name', '$TARGET.abspath']) env.AppendUnique(SHLINKFLAGS='-headerpad_max_install_names') fast_linkflags[:] = [] # Compiler specific options if icpc: # options for Intel C++ compiler on hpc dev-intel07 env.PrependUnique(CCFLAGS=['-w1', '-fp-model', 'precise']) env.PrependUnique(LIBS=['imf']) fast_optimflags = ['-fast', '-no-ipo'] else: # g++ options env.PrependUnique(CCFLAGS=['-Wall']) fast_optimflags = ['-ffast-math'] # Configure build variants if env['build'] == 'debug': env.Append(CCFLAGS='-g') elif env['build'] == 'fast': env.AppendUnique(CCFLAGS=['-O3'] + fast_optimflags) env.AppendUnique(CPPDEFINES={'NDEBUG' : None}) env.AppendUnique(LINKFLAGS=fast_linkflags) if env['profile']: env.AppendUnique(CCFLAGS='-pg') env.AppendUnique(LINKFLAGS='-pg') # Lists for storing built objects and header files env['newmatobjs'] = [] env['cctbxobjs'] = [] env['objcrystobjs'] = [] env['lib_includes'] = [] # Subsidiary SConscripts ----------------------------------------------------- # These will create the built objects and header file lists. SConscript(["SConscript.cctbx", "SConscript.newmat", "SConscript.objcryst"]) # Define sdist target for creating source distribution bundle # Do so only if required to avoid extra git executions. # Note: See .gitattributes for files excluded from sdist. if 'sdist' in COMMAND_LINE_TARGETS: SConscript('SConscript.sdist') # Top Level Targets ---------------------------------------------------------- # This retrieves the intermediate objects newmatobjs = env["newmatobjs"] cctbxobjs = env["cctbxobjs"] objcrystobjs = env["objcrystobjs"] # This builds the shared library libobjcryst = env.SharedLibrary("libObjCryst", objcrystobjs + cctbxobjs + newmatobjs) lib = Alias('lib', [libobjcryst, env['lib_includes']]) Default(lib) # Installation targets. prefix = env['prefix'] # install-lib install_lib = env.Install(env['libdir'], libobjcryst) if env['PLATFORM'] == 'darwin': # DARWIN_INSTALL_NAME can be pre-set in sconscript.local env.SetDefault(DARWIN_INSTALL_NAME='$TARGET.abspath') env.AddPostAction(install_lib, 'install_name_tool -id $DARWIN_INSTALL_NAME $TARGET') if env['PLATFORM'] == 'posix' and WhereIs('ldconfig'): opts = '' if os.getuid() == 0 else '-n' env.AddPostAction(install_lib, 'ldconfig %s $TARGET.dir' % opts) Alias('install-lib', install_lib) # install-include ninc = len(Dir('.').path) + 1 inc_target_path = lambda f: os.path.join(env['includedir'], f.path[ninc:]) include_targets = [inc_target_path(f) for f in env['lib_includes']] install_include = InstallAs(include_targets, env['lib_includes']) Alias('install-include', install_include) # install Alias('install', ['install-lib', 'install-include']) # do not install headers and data when shared library cannot be installed. if 'install' in COMMAND_LINE_TARGETS: Requires(install_include, install_lib) # vim: ft=python libobjcryst-2021.1.2+ds1/src/SConscript.cctbx000066400000000000000000000027741417150057700206740ustar00rootroot00000000000000Import('env') # Determine if we should use shared installation of cctbx if 'with_shared_cctbx' in env: has_shared_cctbx = env['with_shared_cctbx'] else: conf = Configure(env) has_shared_cctbx = conf.CheckLibWithHeader('cctbx', ''' cctbx/sgtbx/space_group.h cctbx/miller/sym_equiv.h cctbx/miller/index_generator.h cctbx/eltbx/wavelengths.h cctbx/eltbx/xray_scattering.h cctbx/eltbx/tiny_pse.h cctbx/eltbx/icsd_radii.h cctbx/eltbx/henke.h cctbx/eltbx/neutron.h cctbx/sgtbx/brick.h '''.split(), language='C++', autoadd=False) env = conf.Finish() # reuse the installed cctbx library if available if has_shared_cctbx: env.AppendUnique(LIBS='cctbx') # otherwise link in the included cctbx sources else: # Define the what we need for the cctbx cctbxenv = env.Clone() # Source path cctbxenv.PrependUnique(CPPPATH = ["./cctbx/include"]) # Idenfity the required source files srcfiles = Glob("./cctbx/cctbx/eltbx/*.cpp") srcfiles += Glob("./cctbx/cctbx/eltbx/xray_scattering/*.cpp") srcfiles += Glob("./cctbx/cctbx/sgtbx/*.cpp") srcfiles += Glob("./cctbx/cctbx/sgtbx/reference_settings/*.cpp") srcfiles += Glob("./cctbx/cctbx/miller/*.cpp") srcfiles += Glob("./cctbx/cctbx/uctbx/*.cpp") # Make the library object objects = cctbxenv.SharedObject(srcfiles) Clean(objects, "cctbx") # Put this back into the global environment env["cctbxobjs"] = objects # vim: ft=python libobjcryst-2021.1.2+ds1/src/SConscript.newmat000066400000000000000000000012351417150057700210530ustar00rootroot00000000000000Import('env') # Define the what we need to install cctbx newmatenv = env.Clone() # Add some flags newmatenv.PrependUnique(CPPPATH = ["."]) # Define the required source files srcfiles = ''' bandmat.cpp evalue.cpp myexcept.cpp newmat1.cpp newmat2.cpp newmat3.cpp newmat4.cpp newmat5.cpp newmat6.cpp newmat7.cpp newmat8.cpp newmat9.cpp newmatex.cpp sort.cpp submat.cpp '''.split() srcdir = "newmat" import os.path srcfiles = [os.path.join(srcdir, f) for f in srcfiles] # Make the library object objects = newmatenv.SharedObject(srcfiles) Clean(objects, "newmat") # Put this back into the global environment env["newmatobjs"] = objects # vim: ft=python libobjcryst-2021.1.2+ds1/src/SConscript.objcryst000066400000000000000000000024241417150057700214200ustar00rootroot00000000000000Import('env') # Define the what we need to install objcryst objcrystenv = env.Clone() # Source directories objcrystenv.PrependUnique(CPPPATH = ["."]) objcrystenv.PrependUnique(CPPPATH = ["./cctbx/include"]) # Idenfity the required source files srcfiles = Glob("./ObjCryst/ObjCryst/*.cpp") srcfiles += Glob("./ObjCryst/RefinableObj/*.cpp") srcfiles += Glob("./ObjCryst/CrystVector/*.cpp") srcfiles += Glob("./ObjCryst/Quirks/*.cpp") # Determine library version from the git data. SConscript("SConscript.version") srcfiles += [File("./ObjCryst/version.cpp")] # Make shared objects objects = objcrystenv.SharedObject(srcfiles) # Put VFNDebug.os first to define debug level constants objects.sort(key=lambda o: not o.name.startswith('VFNDebug')) Clean(objects, "ObjCryst") # Put this back into the global environment env["objcrystobjs"] = objects # Record headers env['lib_includes'] += Glob("./ObjCryst/ObjCryst/*.h") env['lib_includes'] += Glob("./ObjCryst/RefinableObj/*.h") env['lib_includes'] += Glob("./ObjCryst/CrystVector/*.h") # these headers are not included from any other headers excluded_quirks = set(['Chronometer.h', 'VFNStreamFormat.h', 'sse_mathfun.h']) env['lib_includes'] += [f for f in Glob("./ObjCryst/Quirks/*.h") if not f.name in excluded_quirks] # vim: ft=python libobjcryst-2021.1.2+ds1/src/SConscript.sdist000066400000000000000000000044201417150057700207050ustar00rootroot00000000000000import os from libobjcrystbuildutils import gitinfo Import('env') def add_version_and_compress(target, source, env): import tarfile import gzip tfin = tarfile.open(target[0].path) fpout = gzip.GzipFile(target[0].path + '.gz', 'w', mtime=0) tfout = tarfile.open(fileobj=fpout, mode='w') # copy archive members up to the ObjCryst/version.cpp member. tiiter = (t for t in tfin if not t.name.endswith('/version.tpl')) for ti in tiiter: tfout.addfile(ti, tfin.extractfile(ti)) if ti.name.endswith('src/ObjCryst/version.cpp'): break assert ti.name.endswith('version.cpp'), \ "src/ObjCryst/version.cpp not found in tar archive." # add the generated version.h file to the archive. vp = source[0].path ti.name = ti.name[:-4] + '.h' ti.size = os.path.getsize(vp) tfout.addfile(ti, open(vp, 'rb')) # finally copy the remaining members in the input tar file. for ti in tiiter: tfout.addfile(ti, tfin.extractfile(ti)) tfout.close() fpout.close() tfin.close() return def die_without_git(target, source, env): print('sdist must be built from a git repository.') Exit(1) return def generate_sdist_actions(target, source, env, for_signature): env.SetDefault(SDIST_ATTRIBUTES='site_scons/.gitattributes') ginfo = gitinfo() if not ginfo: return [die_without_git] actions = [] actions.append('echo "gitarchive.cfg -export-subst" > $SDIST_ATTRIBUTES') prefix = 'libobjcryst-%(version)s/' % ginfo gitcmd = ('git -c tar.umask=0022 archive ' '--worktree-attributes ' '--prefix=%s --output=$TARGET HEAD') % prefix actions.append(gitcmd) actions.append(Delete('$SDIST_ATTRIBUTES')) actions.append(add_version_and_compress) actions.append(Delete('$TARGET')) dst = '${TARGET.base}-%(version)s${TARGET.suffix}.gz' % ginfo actions.append(Move(dst, '${TARGET}.gz')) return actions env.Append(BUILDERS={'BuildSourceDistribution' : Builder(generator=generate_sdist_actions, suffix='.tar')}) # build node for version.hpp vh = [f for f in env['lib_includes'] if str(f).endswith('ObjCryst/version.h')] sdist = Alias('sdist', env.BuildSourceDistribution('#/libobjcryst', vh)) AlwaysBuild(sdist) # vim: ft=python libobjcryst-2021.1.2+ds1/src/SConscript.version000066400000000000000000000042441417150057700212500ustar00rootroot00000000000000import os import string Import('env') def get_version_or_die(): from libobjcrystbuildutils import getversion try: rv = getversion() except RuntimeError as e: print(e) Exit(1) return rv def build_VersionCode(target, source, env): tplcode = source[0].get_text_contents() numversion = gver['major'] numversion = 1000 * numversion + gver['minor'] numversion = 1000 * numversion + gver['micro'] numversion = 1000 * numversion + gver['patchnumber'] # verify that formulas in version.tpl work as advertised emsg = "Inconsistent value of LIBOBJCRYST_VERSION = %i" % numversion assert numversion // 1000000000 == gver['major'], emsg assert numversion // 1000000 % 1000 == gver['minor'], emsg assert numversion // 1000 % 1000 == gver['micro'], emsg assert numversion % 500 == gver['patchnumber'], emsg libversion = str(numversion) + "LL" if gver['prerelease']: libversion = "(-500 + %s)" % libversion flds = { 'LIBOBJCRYST_VERSION' : libversion, 'LIBOBJCRYST_VERSION_MAJOR' : gver['major'], 'LIBOBJCRYST_VERSION_MINOR' : gver['minor'], 'LIBOBJCRYST_VERSION_MICRO' : gver['micro'], 'LIBOBJCRYST_VERSION_PATCH' : gver['patchnumber'], 'LIBOBJCRYST_VERSION_STR' : gver['version'], 'LIBOBJCRYST_VERSION_DATE' : gver['date'], 'LIBOBJCRYST_GIT_COMMIT' : gver['commit'], } versiontemplate = string.Template(tplcode) versioncode = versiontemplate.safe_substitute(flds) with open(target[0].path, 'w') as fp: fp.write(versioncode) return None env.Append(BUILDERS={'BuildVersionCode' : Builder(action=build_VersionCode, suffix='.h', src_suffix='.tpl')}) # Targets -------------------------------------------------------------------- vhpp = File('ObjCryst/version.h') # If version.h does not exists, build it from git metadata if not os.path.isfile(str(vhpp.srcnode())): vtpl = File('ObjCryst/version.tpl') gver = get_version_or_die() vhpp, = env.BuildVersionCode(['ObjCryst/version.h'], vtpl) env.Depends(vhpp, env.Value(gver['version'] + gver['commit'])) env['lib_includes'] += [vhpp] # vim: ft=python