# ifndef CPPAD_TAPE_LINK_INCLUDED # define CPPAD_TAPE_LINK_INCLUDED /* -------------------------------------------------------------------------- CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-07 Bradley M. Bell CppAD is distributed under multiple licenses. This distribution is under the terms of the Common Public License Version 1.0. A copy of this license is included in the COPYING file of this distribution. Please visit http://www.coin-or.org/CppAD/ for information on other licenses. -------------------------------------------------------------------------- */ /* $begin tape_link$$ $comment CppAD Developer Documentation$$ $section Routines that Link AD and ADTape Objects$$ $spell omp bool ptr const tbl atexit $$ $head tape_this$$ $index tape_this$$ The syntax $syntax% %ptr% = %x%.tape_this() %$$ returns the tape corresponding to $italic x$$ where $italic x$$ and $italic ptr$$ have the prototypes $syntax% const AD<%Base%> &%x% ADTape<%Base%> *%ptr% %$$ The argument $italic x$$ must a variable. $head id_handle$$ $index id_handle$$ The syntax $syntax% %id% = AD<%Base%>::id_handle(%thread%) %$$ returns a pointer to the currently active tape identifier for the specified OpenMP thread. $subhead thread$$ The argument $italic thread$$ has prototype $syntax% size_t %thread% %$$ It must be less that $code CPPAD_MAX_NUM_THREADS$$ and specifies the OpenMP thread that the tape identifier is for. In the case where the preprocessor symbol $code _OPENMP$$ is not defined, $italic thread$$ must be zero. $subhead id$$ The return value $italic id$$ has prototype $syntax% size_t *%id% %$$ and is a pointer to the tape identifier for the specified thread. The initial value, for the tape identifier is zero. This way it is not equal to the default $code id_ = 1$$ value in each $syntax%AD<%Base%>%$$ object. Either $syntax%*id_handle(%thread%)%$$ is zero (its initial value) or the current thread number satisfies the equation $syntax/ /thread/ == *id_handle(/thread/) % CPPAD_MAX_NUM_THREADS /$$ (This is a restriction on how $syntax%*id_handle(%thread%)%$$ may be changed.) $head tape_handle$$ $index tape_handle$$ The syntax $syntax% %tape% = AD<%Base%>::tape_handle(%thread%) %$$ returns a pointer to a pointer to the current tape for the specified OpenMP thread. $subhead thread$$ The argument $italic thread$$ has prototype $syntax% size_t %thread% %$$ It must be less that $code CPPAD_MAX_NUM_THREADS$$ and specifies the OpenMP thread that the tape identifier is for. In the case where the preprocessor symbol $code _OPENMP$$ is not defined, $italic thread$$ must be zero. $subhead tape$$ The return value $italic tape$$ has prototype $syntax%% ADTape<%Base%> **tape %$$. If the tape is currently active, $syntax% *%tape% != CPPAD_NULL %$$ $head tape_new$$ $index tape_new$$ The syntax $syntax% %id% = AD<%Base%>::tape_new() %$$ creates a new tape and returns the corresponding tape identifier. The resulting tape identifier is not equal to zero, one, or to any of the previous values return by $code tape_new$$. In addition, the current thread number is given by $syntax/ /thread/ = /id/ % CPPAD_MAX_NUM_THREADS /$$ The return value $italic id$$ has prototype $syntax% size_t %id% %$$ This function is only called by the user $code Independent$$ routine and hence usage errors can be reported as coming from that routine. $head tape_delete$$ $index tape_delete$$ The syntax $syntax% AD<%Base%>::tape_delete(%id%) %$$ deletes the tape corresponding to the tape identifier $italic id$$. The value $syntax%*id_handle(%thread%)%$$ for this thread is set to a value larger than any previous value returned by $code tape_new()$$. $head tape_ptr$$ $index tape_ptr$$ The syntax $syntax% %ptr% = AD<%Base%>::tape_ptr() %$$ returns the a pointer to the tape corresponding to the current thread. The corresponding tape is active if and only if $syntax%%ptr% == CPPAD_NULL%$$. The syntax $syntax% %ptr% = AD<%Base%>::tape_ptr(%id%) %$$ does the same thing but if NDEBUG is not defined, it also check that the $italic id$$ is the corresponding tape identifier and that $italic ptr$$ is not equal to $code CPPAD_NULL$$. The argument $italic id$$ has prototype $syntax% size_t %id% %$$ $end ---------------------------------------------------------------------------- */ # ifdef _OPENMP # include # endif // BEGIN CppAD namespace namespace CppAD { // ---------------------------------------------------------------------- template inline ADTape *AD::tape_this(void) const { size_t thread = id_ % CPPAD_MAX_NUM_THREADS; CPPAD_ASSERT_UNKNOWN( id_ == *id_handle(thread) ); CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); return *tape_handle(thread); # if 0 // old code that did not use OpenMP CPPAD_ASSERT_UNKNOWN( id_ == *id_handle() ); CPPAD_ASSERT_UNKNOWN( *tape_handle() != CPPAD_NULL ); return *tape_handle(); # endif } // ---------------------------------------------------------------------- // Static functions // template inline size_t * AD::id_handle(size_t thread) { static size_t id_table[CPPAD_MAX_NUM_THREADS]; CPPAD_ASSERT_UNKNOWN( (id_table[thread] == 0) | (id_table[thread] % CPPAD_MAX_NUM_THREADS == thread) ); return id_table + thread; } template inline ADTape ** AD::tape_handle(size_t thread) { static ADTape *tape_table[CPPAD_MAX_NUM_THREADS]; return tape_table + thread; } template size_t AD::tape_new(void) { # ifdef _OPENMP size_t thread = static_cast ( omp_get_thread_num() ); # else size_t thread = 0; # endif size_t *id = id_handle(thread); ADTape **tape = tape_handle(thread); CPPAD_ASSERT_KNOWN( thread < omp_max_thread(0), "Independent: OpenMP thread number is >= omp_max_thread setting" ); // initialize so that id > 1 and thread == id % CPPAD_MAX_NUM_THREADS if( *id == 0 ) *id = thread + 2 * CPPAD_MAX_NUM_THREADS; // tape for this thread must be null at the start CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL ); *tape = new ADTape( *id ); return *id; } template void AD::tape_delete(size_t id_old) { size_t thread = id_old % CPPAD_MAX_NUM_THREADS; # ifdef _OPENMP CPPAD_ASSERT_KNOWN( thread == static_cast ( omp_get_thread_num() ), "AD tape recording must stop in same thread as it started in." ); # else CPPAD_ASSERT_UNKNOWN(thread == 0); # endif size_t *id = id_handle(thread); ADTape **tape = tape_handle(thread); CPPAD_ASSERT_UNKNOWN( *id == id_old ); CPPAD_ASSERT_UNKNOWN( *tape != CPPAD_NULL ); // increase the id for this thread in a way such that // thread = id % CPPAD_MAX_NUM_THREADS *id += CPPAD_MAX_NUM_THREADS; // delete the old tape for this thread delete ( *tape ); *tape = CPPAD_NULL; return; } template inline ADTape *AD::tape_ptr(void) { # ifdef _OPENMP size_t thread = static_cast ( omp_get_thread_num() ); # else size_t thread = 0; # endif return *tape_handle(thread); } template inline ADTape *AD::tape_ptr(size_t id) { size_t thread = id % CPPAD_MAX_NUM_THREADS; # ifdef _OPENMP CPPAD_ASSERT_KNOWN( thread == static_cast ( omp_get_thread_num() ), "Attempt to use an AD variable in two different OpenMP threads." ); # else CPPAD_ASSERT_UNKNOWN(thread == 0 ); # endif CPPAD_ASSERT_UNKNOWN( id == *id_handle(thread) ); CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); return *tape_handle(thread); } } // END CppAD namespace # endif