IMP
. Developers who wish to contribute code back to IMP
or distribute their code should also read the Contributing code to IMP page.
IMP
directory are structured as follows:tools
contains various command line utilities for use by developers. They are documented below.doc
contains inputs for general IMP
overview documentation (such as this page), as well as configuration scripts for doxygen
.applications
contains various applications implementing using a variety of IMP
modules.kernel
and the subdirectories of module/
each defines a module and have the same structure. The directory for module name
has the following structureinclude
contains the C++ header filessrc
contains the C++ source filesbin
contains C++ source files each of which is built into an executablepyext
contains files defining the python interface to the module as well as python source files (in pyext/src
)test
contains test files. When scons
test
or scons
name-test
is run each file in this directory named test_
is executed (after being built if it is a .cpp file)doc
contains the overview documentation for the file (in the SConscript
file) as well as any other documentation that is provided via
.dox filesexamples
contains examples, in python as well as any data needed for examplesdata
contains any data files needed by the module
When IMP
is built, the build
directory is created and filled with the results of the build. build
contains a number of subdirectories. They are
include
which includes all the headers. The headers for the kernel
are placed in include/IMP
and those for module name
are placed in include/IMP/name
lib
where the C++ and python libraries are placed. Module name
is built into a C++ library lib/libimp_name.so
(or
.dylib on a mac) and a python library with python files located in lib/IMP/name
and the binary part in lib/_IMP_name.so
.doc
where the html documentation is placed in doc/html
and the examples in doc/examples
with a subdirectory for each moduledata
where each module gets a subdirectory for its data.
Unfortunately, various intermediate files from the build are scattered throughout the module
and kernel
hierarchies. This messiness is part of the reason we strongly recommend doing an out of source build.
When IMP
is installed, the structure from the build
directory is moved over more or less intact except that the C++ and python libraries are put in the (different) appropriate locations.
modules
directory, complete with example code.We highly recommend using a revision control system such as Subversion or GIT to keep track of changes to your module.
If, instead, you choose to add code to an existing module you need to consult with the person who people who control that module. Their names can be found on the module main page.
When designing the interface for your new code, you should
IMP
for similar functionality and, if there is any, adapt the existing interface for your purposes. For example, the existing IMP::atom::read_pdb() and IMP::atom::write_pdb() functions provide templates that should be used for the design of any functions that create particles from a file or write particles to a file. Since IMP::atom::BondDecorator, IMP::algebra::Segment3D and IMP::display::Geometry all use methods like IMP::algebra::Segment3D::get_point() to access the endpoints of a segment, any new object which defines similar point-based geometry should do likewise.
You may want to read the design example for some suggestions on how to go about implementing your functionality in IMP
.
IMP
provides a number of tools to help you out.The first set are assert-style macros:
See Error reporting/checking page for more details. As a general guideline, any improper usage to produce at least a warning all return values should be checked by such code.
The second is logging macros such as:
Finally, each module has a set of unit tests. These are python scripts which test the behavior of a particular piece of the modules API. The scripts are located in the modules/modulename/test
directory. These tests should try, as much as possible to provide independent verification of the correctness of the C++ code. The command
scons test
scons modulename-test
modulename
, respectively. Any file in that directory or a subdirectory whose name matches test_*
.py is considered a test. The python files are scanned for classes which inherit from IMP.test.TestCase
. For each such class found, any method whose name starts with test_
is run.
Some tests will require input files or temporary files. Input files should be placed in a directory called input
in the test
directory. The test script should then call
self.get_input_file_name(file_name)
self.get_tmp_file_name(file_name)
build/tmp
. The test should remove temporary files after using them.
To ensure code consistency and readability, certain conventions must be adhered to when writing code for IMP
. Some of these conventions are automatically checked for by source control before allowing a new commit, and can also be checked yourself in new code by running
scons standards
astyle --convert-tabs --style=linux --indent=spaces=2 --unpad=paren --pad=oper
Rationale: Different users have different-sized windows or terminals, and different tab settings, but everybody can read 80 column output without tabs.
All Python code should conform to the Python style guide. In essence this translates to 4-space indents, no tabs, and similar class, method and variable naming to the C++ code. You can ensure that your Python code is correctly indented by using the
tools/reindent.py
IMP
distribution.IMP
and no IMP
code should depend on preprocessor symbols which do not start with IMP.SpecialVector.h
and SpecialVector.cpp
separated_by_underscores
, for example container_macros.h
Name
using a Names
. Declare functions that accept them to take a NamesTemp
(Names
is a NamesTemp
). Names
are reference counted (see IMP::RefCounted for details), NamesTemp
are not.show
method which takes an optional std::ostream
and prints information about the object (see IMP::Object::show() for an example). The helper macros, such as IMP_RESTRAINT() define such a method. In addition they must have operator<<
defined. This can be easily done using the IMP_OUTPUT_OPERATOR() macro once the show method is defined. Note that operator<<
writes human readable information. Add a write
method if you want to provide output that can be read back in.IMP
exceptions to report errors. See IMP::Exception for a list of existing exceptions. See assert for a list of functions to aid in error reporting and detection.IMPMODULE_BEGIN_NAMESPACE
, IMPMODULE_END_NAMESPACE
, IMPMODULE_BEGIN_INTERNAL_NAMESPACE
and IMPMODULE_END_INTERNAL_NAMESPACE
macros to put declarations in a namespace appropriate for module MODULE
.
Each module has an internal namespace, module_name::internal
and an internal include directory modulename/internal
. Any function which is
should be declared in an internal header and placed in the internal namespace.
The functionality in such internal headers is
As a result, such functions do not need to obey all the coding conventions (but we recommend that they do).
IMP
is documented using Doxygen. See documenting source code with doxygen to get started. We use //!
and /**
... * / blocks for documentation.Python code should provide Python doc strings.
All headers not in internal directories are parsed through Doxygen. Any function that you do not want documented (for example, because it is not well tested), hide by surrounding with
#ifndef IMP_DOXYGEN void messy_poorly_thought_out_function(); #endif
We provide a number of extra Doxygen commands to aid in producing nice IMP
documentation. The commands are used by writing \commandname{args}
or \commandname
if there are no arguments.
\command{the command text}
the command text
\salilab{imp, the IMP project}
\external{boost.org, Boost}
IMP
do \imp
IMP
as opposed to IMP).
IMP
code should be marked with \advanceddoc You can tweak this class in various ways in order to optimize its performance.
\advancedmethod
\warning Be afraid, be very afraid.
\unstable{Classname}
. The documentation will include a disclaimer and the class or function will be added to a list of unstable classes. It is better to simply hide such things from Doxygen.
\untested{Classname}
.
\untested{Classname}
.
\comparable
and then hide the comparison functions from Doxygen (there are a lot of them and they aren't very interesting).IMP
provides a variety of scripts to aid the lives of developers.SConscripts
in a number of the modules list all of the header and cpp
files which are part of the module (those of other modules automatically build this list at compile time). These lists can be generated using the make-sconscripts
script. To run it to rebuild the SConscripts for the module modulename do ./tools/make-sconscripts modulename
IMP
. First, choose a name for the module. The name should only contain letters, numbers and underscores as it needs to be a valid file name as well as an identifier in Python and C++.To create the module do
./tools/make-module my_module
scons
with localmodules=True
, your new module will be built. The new module includes a number of examples and comments to help you add code to the module.You can use your new module in a variety of ways:
.h
files in modules/my_module/include
and .cpp
files in modules/my_module/src
. In order to use use your new functions and classes in python, you must add a line include "IMP/my_module/myheader.h"
near the end of the file modules/my_module/pyext/my_module.i
.IMP
by creating .cpp
files in modules/my_module/bin
. Each .cpp
file placed there is built into a separate executable..py
file in modules/my_module/pyext/my_module/
pythoncode
blocks to modules/my_module/pyext/my_module.i
..py
files in modules/my_module/test
or a subdirectory.
If you feel your module is of interest to other IMP
users and developers, see the contributing code to IMP section.
If you document your code, running
scons doc
doc/html/index.html
.
In order to be shared with others as part of the IMP
distribution, code needs to be of higher quality and more thoroughly vetted than typical research code. As a result, it may make sense to keep the code as part of a private module until you better understand what capabilities can be cleanly offered to others.
The first set of questions to answer are
IMP
? If so, it might make more sense to modify the existing code in cooperation with its author. At the very least, the new code needs to respect the conventions established by the prior code in order to maintain consistency.
You are encouraged to post to the imp-dev to find help answering these questions as it can be hard to grasp all the various pieces of functionality already in the repository.
All code contributed to IMP
scons
doc
)The next suggestions provide more details about the above choices and how to implement them.
A list of all current modules in the IMP repository can be found in the modules list or from the modules tab at the top of this page.
As always, if in doubt, post to imp-dev.
Patches to modules for which you have write access can be submitted directly by doing:
svn commit -m "message describing the patch" files or directories to submit
The following sorts of changes must be announced on the imp-dev mailing list before being made
We recommend that changes be posted to the list a day or two before they are made so as to give everyone adequate time to comment.
In addition to monitoring the imp-dev list, developers who have a module or are committing patches to svn may want to subscribe to the imp-commits email list which receives notices of all changes made to the IMP
SVN repository.
IMP
endeavors to follow all the of the guidelines published in those books. The Sali lab owns copies of both of these books that you are free to borrow.
IMP
.
using
namespace'
outside of a function; instead explicitly provide the namespace. (This avoids namespace pollution, and removes any ambiguity.)
const
variables instead. Preprocessor symbols don't have scope or type and so can have unexpected effects.
const
& (if the object is large) and store copies of them.
const
value or const
ref if you are not providing write access. Returning a const
copy means the compiler will report an error if the caller tries to modify the return value without creating a copy of it.
IMP
modules and kernel and finally outside includes. This makes any dependencies in your code obvious, and by including standard headers after IMP
headers, any missing includes in the headers themselves show up early (rather than being masked by other headers you include).
#include <IMP/mymodule/mymodule_exports.h> #include <IMP/mymodlule/MyRestraint.h> #include <IMP/Restraint.h> #include <vector>
double
variables for all computational intermediates.
FloatKey get_my_float_key() { static FloatKey k("hello"); return k; }
double
parameters) it is easy for a user to mix up the order of arguments and the compiler will not complain. int
and double
count as equivalent types for this rule since the compiler will transparent convert an int
into a double
.